The previous blog posts explored subscribing to market data and how to get notified on Telegram when an interesting trading opportunity comes. The next step is to actually trade based on the signals we receive.
In this blog post, we will use a form of paper trading — Binance Testnet environment. The idea is simple. The Testnet gives you access to the Binance exchange but all order books, all trades, and your account balance sheet are simulated in this platform environment to mimic the real trading environment.
People use testnets to familiarize themselves with the platform before they feel confident risking their hard earned assets on a live exchange. By using the testnet, you will save some time as Binance does not need to verify your identity through their Know Your Customer process (KYC).
Introduction to Exchange Orders
Binance and other major exchanges allow you to create several different types of orders. The most commonly used order types are market orders and limit orders. A market order allows you to buy or sell a certain quantity of an asset at the best available price at that moment. In contrast, a limit order requires you to specify not only a quantity but also the price for which you are willing to buy (or sell) the asset.
It’s very important to realize why professional traders often prefer limit orders, and why using market orders can be dangerous. Consider the following scenario:
You intend to sell 1 BTC, and the order book indicates a favorable price of 75,000 EUR. However, upon selecting the “sell” button with the market order type, an unfortunate turn of events occurs — before your request is processed by the Binance platform, a significant investor decides to liquidate her holdings, causing the price to temporarily drop to 70,000 EUR. Consequently, your order is executed at this lower price, resulting in a loss of 5,000 EUR!
It’s very easy to lose hard-earned profit this way. That said, it’s also worth noting that the price could rise up just as easily. This is mentioned to emphasize the importance of understanding your risks when trading.
How to Place Orders in Whale’s Secret ScriptApiLib
Whale’s Secret ScriptApiLib offers API for creating and cancelling of orders. First, before an order can be placed, we need to establish an authenticated connection:
using WhalesSecret.ScriptApiLib;
using WhalesSecret.ScriptApiLib.Exchanges;
using WhalesSecret.TradeScriptLib.API.TradingV1;
using WhalesSecret.TradeScriptLib.Entities;
// Use the Binance Testnet.
CreateOptions createOptions = new(connectToBinanceSandbox: true);
await using ScriptApi scriptApi = await ScriptApi.CreateAsync(createOptions);
// Specify your Binance Testnet API credentials.
using IApiIdentity apiIdentity = BinanceApiIdentity.CreateHmac(name: "MyApiKey",
key: "<KEY>", secret: Convert.FromBase64String("<SECRET>"));
scriptApi.SetCredentials(apiIdentity);
// Connect.
ITradeApiClient client = await scriptApi.ConnectAsync(ExchangeMarket.BinanceSpot);
Console.WriteLine("Ready to trade!");
And then we might want to buy 0.00015 BTC using a market order:
// Ask Binance to place a market order to buy 0.00015 BTC.
ILiveMarketOrder order = await client.CreateMarketOrderAsync(SymbolPair.BTC_EUR,
OrderSide.Buy, size: 0.00015m);
Success! However, if you are not familiar with bitcoin exchange rates, you might be curious about the value of 0.00015 BTC (spoiler: it is approximately 11 EUR at the time of writing). In this case, we can specify the quantity directly in euros for your convenience:
MarketOrderRequest request = new(SymbolPair.BTC_EUR, OrderSide.Buy,
size: 11m, sizeInBaseSymbol: false);
ILiveMarketOrder order = await client.CreateOrderAsync(request);
Note the difference between the two approaches. When the size is specified in the base symbol, you are saying “buy 0.00015 BTC for the best possible price” and it may cost you 11 EUR, or it may cost you 12 EUR, or 10 EUR, depending on the current market situation. In the second case, when the size is specified in the quote symbol, you are saying “buy 11 EUR worth of BTC”. Here you will never spend 10 EUR nor 12 EUR, you will spend 11 EUR and for that you may obtain 0.00015 BTC or maybe just 0.00013 BTC.
We mentioned that market orders can lead to losses, so let’s move on to limit orders where your risk is much easier to assess:
ILiveLimitOrder order = await client.CreateLimitOrderAsync(SymbolPair.BTC_EUR,
OrderSide.Sell, price: 75_000m, size: 1.0m);
The sample shows how to create a limit order to sell one bitcoin with the limit price of 75,000 EUR. Notably, you cannot incur a loss in this case as your order might be filled with the minimum price of 75,000 EUR. Yes, you may achieve a higher selling price, if you are fortunate. However, a drawback is that your order might not be fully executed. So while market orders give you reasonable confidence that your trade will be finished “immediately”, limit orders does not offer the same level of certainty.
Note that the previous code sample works only if you decide to buy ScriptApiLib subscription. That’s because ScriptApiLib can be used for free only with limited order sizes. Paying customers can just specify their license key and enjoy unlimited order sizes:
CreateOptions createOptions = new(connectToBinanceSandbox: true,
license: "<YOUR-WHALESSECRET-LICENSE>");
await using ScriptApi scriptApi = await ScriptApi.CreateAsync(createOptions);
// [..]
// License string is specified. No exception is thrown!
ILiveLimitOrder order = await client.CreateLimitOrderAsync(SymbolPair.BTC_EUR,
OrderSide.Sell, price: 75_000m, size: 1.0m);
Without a license, you will be informed about the maximum allowed order size by an exception:
Bot That Trades
In the previous blog posts, we have significantly enhanced our market-watching bot. Now, we can modify it further by trading based on received RSI signals. The idea is simple: Buy when the market is oversold, sell when the market is overbought. Note that this is not an endorsement of this trading strategy, we demonstrate order placing for education purposes. That’s why we use the Testnet to avoid any financial losses.
In C#, this can be implemented as follows:
// Store if we did buy or sell the last time. We do not want the bot to
// do multiple consecutive buys. After each buy, only a sell can follow
// and vice versa.
OrderSide? lastAction = null;
// [..]
OrderSide? action = null;
if ((rsiValue < 30) && (lastAction != OrderSide.Buy)) action = OrderSide.Buy;
else if ((rsiValue > 70) && (lastAction != OrderSide.Sell)) action = OrderSide.Sell;
if (action is not null)
{
lastAction = action;
ILiveMarketOrder order = await tradeClient.CreateMarketOrderAsync(SymbolPair.BTC_EUR, action.Value, size: 0.00015m);
await order.WaitForFillAsync();
// Notify us on Telegram that an order was placed.
string message = $"Bot says: Based on the RSI signal <b>{rsiStr}{interpretation}</b> for BTC/EUR on Binance, a {action.Value} market order with size " +
$"{order.Size} was <b>placed</b>!";
await SendTelegramMessageAsync(message);
}
else
{
string message = interpretation != string.Empty
? $"Bot says: RSI signals <b>{rsiStr}{interpretation}</b> for BTC/EUR on Binance! Current price is {priceStr} EUR."
: $"Bot says: RSI does <b>not</b> provide a clear signal for BTC/EUR on Binance! Current price is {priceStr} EUR. RSI value is {rsiStr}.";
await SendTelegramMessageAsync(message);
}
The following image demonstrates how the bot behaves in practice:
Buy order was placed based on an RSI signal
Conclusion
In this blog post, we demonstrated how to create orders in Whale’s Secret ScriptApiLib and we improved our trading bot to actually trade based on the RSI signals it gets. Next time, we will talk about how to monitor order fills.
Disclaimer: The information provided in this blog post should not be considered financial advice. Always conduct your own research and consider your personal circumstances before acting on any financial information.
Top comments (0)