Testing Trading Strategies using Binance testnet API
Algo traders most often test their strategies before jumping into live trading. Backtesting certainly helps to evaluate and to estimate the performance and the risk of trading strategies. However, it is often required to examine trade strategies using a demo account with virtual money, as past performance is no guarantee of future results. In this article, I focus on cryptocurrency trading in Binance and explain how to test trading strategies there using a demo account.
Introduction
Binance provides test platforms for spot, future and vanilla options. Depending on the type of trading, any of these platforms can be employed to emulate strategies. In this post, I focus on spot trading and explain with an example how to use it on binance testnet platform. Note that there is one limitation of spot testnet platform currently, that is it resets the positions roughly every month. That might be problematic for low-frequency trading strategies. The advantage is, thanks topython-binance
, the implemented strategy on testnet platform can be directly used for real live spot trading simply by changing the API key and the secret!
Before starting with the implementation, the environment must be set up. We need python 3 with package python-binance
, an API key and an API secret to establish connection to the binance testnet. First, packagepython-binance
is required to be installed. In a development environment with python 3, this can be done by:
pip install python-binance
The next step is to log into spot testnet platform. To do this, at the time of writing this post, it is required to have a github account. After login, click on Generate HMAC_SHA256 Key
to create an API key and secret and then save them for later to be used in the algorithm. That is all we need.
Strategy implementation
Now it is the time to implement a simple strategy, which is the “hello world” trading algorithm moving average crossover. The idea is to keep track of moving price average of an asset for a long- and a short-term period, then, use these values to determine when to enter and exit the market. When the short-term moving average goes above the long-term moving average we will go long; otherwise we go short, of course if we hold a position in the asset. The following parameters are defined for the strategy:
g_symbol
is the symbol name of the asset,g_cycle
is the operating cycle of the algorithm in seconds, that means everyg_cycle
second(s) the algorithm takes the most recent asset price, updates the moving averages and submits orders if any,g_longterm
is the number of cycles of the long-term moving average. For instance if it equals 50 withg_cycle
being 60, the average over the last 50 minutely prices will be computed as the long-term moving average,g_shortterm
is the same asg_longterm
but for the short-term moving average,g_quantity
is the number of shares of the asset in buy and sell orders.
The complete implementation of the algorithm comes below. The code block to define all of the parameters is located between line 4 to 9.
The logic of the algorithm is implemented in SmaCrossOver
class. The class also handles establishing and closing the connection to the binance testnet platform. Moreover, it continuously fetches the current price of the asset to be used for computing the short- and the long-term moving averages. The class handles its requests to binance platform in an asynchronous manner. That is why, all of its method definitions are followed by async
keyword. It implies that the methods can operate concurrently, specially if the response to a request in a method is not ready yet, it does not block the execution of the other methods. For instance, while fetch_price
should wait to get the latest price of the asset, the execution can switch to run
to update moving averages on already available price data. This way leads to making better use of CPU cycles by avoiding unnecessary waiting time. The two main methods of the class are explained in detail.
fetch_price
uses websocket to fetch price information of the asset continuously using methodsymbol_book_ticker_socket
of classBinanceSocketManager
. The price information contains the current price and the quantity of the asset available for sell (bid) or buy (ask). This information is actually the head item in the corresponding order book, which is stored inself._price_info
as a dictionary:{
'u': 4751315, # order book updateId
's': 'BNBUSDT', # symbol name
'b': '277.50000000', # best bid price
'B': '0.04000000', # best bid quantity
'a': '370.00000000', # best ask price
'A': '0.87000000' # best ask quantity
}run
executes the algorithm. Each cycle, it gets the newest price data, which are fetched byfetch_price
and computes the moving averages. At the beginning the algorithm waits for the firstg_longterm
price ticks to come such that it has enough data points to compute the moving averages. Afterwards, in each cycle it updates the moving averages, then compares them and submits the appropriate order if they cross each others. It is done between line 54 to 68.
Now it is the time to put all the pieces together to execute the algorithm, which is done in function main
. It creates an instance of class SmaCrossOver
, which needs the API key and the API secret generated by binance testnet platform. Note that one can also pass those from binance spot platform and set testnet
to False
to go live with real money instead of virtual one. After creating an instance of SmaCrossOver
, the function executes fetch_price
and run
methods concurrently using async.gather
in line 84, which actually runs the strategy.
Conclusion
Binance provides platforms to test trading algorithms with virtual money. This enables an strategy to be evaluated in a setting that is very close to the real trading environment with live price data. Testnet platform is well supported by python-binance
package. The implemented algorithm can be used for real live trading only by changing the API key and secret and resetting a flag.
Originally published at https://hhatefi.github.io on June 17, 2021.