hhatefi

Curious about computing, modeling and analysis

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 every g_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 with g_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 as g_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 method symbol_book_ticker_socket of class BinanceSocketManager. 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 in self._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 by fetch_price and computes the moving averages. At the beginning the algorithm waits for the first g_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.