The basic setup of the trading application is straightforward. In this post I will explain the general structure of the program. I will go into some detail regarding the used classes and functions later.
Without further ado, here's the main code:
t = trader(...) p = portfolio(...) m = marketData(...) while True: p, m = getData(API, p, m, t) t.calcBaseWeight(m) t.calcMomentum(m, ...) t.calcCoinsToTrade(m, p, ...) t.checkTradeSize(m, p, ...) cancelOrders(krakenAPI, t) placeOrder(krakenAPI, m, t) printLogLine(p, m, t, logFileName) t = trader(...) time.sleep(delay)
First, three classes are initialized:
- The portfolio class holds all information regarding the current holdings in fiat and BTC, the value of the portfolio and the weight currently attributed to each currency.
- The marketData class contains current bid and ask prices as well as historic prices (for calculating moving averages).
- Finally, the trader class is where most of the work is taking place. It contains all the parameters which determine the trading behaviour and the most important variable: coinsToTrade. This variable is the outcome of calculations in various functions and gives the number of coins to be traded (bought or sold), depending on the current market data, the historical trend and the strategy parameters.
In the main loop, the portfolio and market data classes are updated first. Then, the number of coins to be traded is checked in a number of steps:
- calcBaseWeight determines which ratio of fiat/BTC we should be holding, given the current market data.
- calcMomentum adjusts this base weight depending on the current momentum of the price
- calcCoinsToTrade converts the difference between the target weight and the current portfolio weight into an effective number of coins to be traded
- checkTradeSize makes sure that only trades larger than a certain threshold are actually carried out. On the one hand, this is to reduce transaction costs. On the other hand, higher thresholds mean that we can profit from higher price variations, while smaller thresholds make it more likely that trades are actually executed. Finding a balance between those two is mostly a matter of backtesting.
Next, any outstanding open orders are cancelled, if any, and a new order is placed. Finally, the current status (market data and trading activity, if any, as well as any errors) are written to a log file for later analysis and backtesting, and the trader instance is updated to reflect the latest changes.