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 to python-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,
package python-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.