Risks

Any investment is risky. Usually, the higher the returns the riskier the proposition, and since my strategy showed some promising returns it is worth thinking about where exactly the risks are.

Bitcoins could tank

The first risk is pretty self explanatory. Since I am buying bitcoins whenever the price drops, a large drop would lead to me putting all the money on bitcoins. If the price continued to fall, the portfolio would be wiped out.

This is something that is hard to avoid when investing in any asset. I am thinking about implementing some stop-loss features to minimize the damage, though.

The bitcoin price could explode

If on the other hand the price of bitcoins skyrockets, my strategy would be left holding fiat and therefore not participate in an extraordinary rise. This is not really a risk in the strong sense as it would not decrease the value of the portfolio, but should be noted nonetheless. In effect, the strategy does well when there is a good deal of volatility without too much of a general trend (as was the case in January 2014, for example). In case the bitcoin price really increases by orders of magnitude, no trading strategy will beat a buy and hold strategy.

The exchange could go under

It has happened before and it will happen again - exchanges will go bust or make off with their customer's deposits. I am currently trading via Kraken, a US based digital asset exchange. It is hard to quantify the risk of a particular exchange going under, although I constantly keep track of all news and rumours. In order to mitigate this risk, I am planning on adding other exchanges (bitstamp and/or bitfinex) in order to minimize this risk. Such a diversification also has the advantage of being able to do some arbitrage if prices between the exchanges start to differ.

Bugs in my code

All code has been written by me and although It has been extensively tested (both on dummy data and in a live environment using my own money for trading) there might be some bugs which could cause the program to trade unfavourably. Looking at the track record, and since the behaviour of buys and sells is tracked constantly, I am very certain that no such bugs exist in the current code.

Momentum trading

After the base target weight is set (and before any trade is executed), it can be influenced by any number of factors. I implemented a momentum trading module which changes the trade target depending on the moving average price.

movingavgThe comparison of a the current price with the average price of the last hours or days is a measure of the current trend. Since the price is a product of supply and demand, and since people tend to buy when the price is rising and sell when the price is falling, it is possible to "ride the trend" if it can be anticipated quickly enough.

As the example in the graphic shows, more often than not the price continues to rise when the price is above the moving average (depicted in red), while the value drops whenever the price is below the moving average. When the two are aligned, there tends to be not so much movement either way.

Of course this is by no means a sure method of generating profits. We need to be extremely careful when selecting the window to use for the moving average, and when deciding how strong this momentum trading effect should influence the basic trading strategy. Both of these parameters have been set using backtesting, which brings its own set of problems and pitfalls.

General trading strategy

I am not trying to predict the future price, at least not directly. Instead my goal is to implement a strategy which "buys low and sells high". The problem of course is to determine whether the current price is low or high and compared to what?

My strategy handles this problem by calculating how much weight of the portfolio should be in EUR. That is, if all the money is in BTC, the weight is zero. If the value of the holdings in BTC is exactly as large as the holdings in EUR, then the weight is 1/2. By comparing the current weight with the "target weight" and inferring how many coins need to be traded in order to get from the former to the latter, we can make sure to keep close to the calculated target weight.

To determine this target weight, two prices are defined: pmin and pmax. If the bitcoin price is below pmin, then the target weight is set to zero. If it is is larger than pmax, the target weight is one. In between the target weight is calculated on the linear curve between those points:

weightThis is generally a sensible strategy if we believe that bitcoins fluctuate a lot but do not have any large trend. If the price goes to zero, we are stuck with holding a whole bunch of worthless coins. If the price skyrockets we are missing out on the rise completely since we are 100% in EUR. I do not think this is a weakness though. If BTC will go to the moon, nothing will beat a buy & hold strategy anyway. Should the price tank on the other hand, it is hard to think of any trading strategy which will do well, considering there's no way to short bitcoin.

Of course, this still leaves the problem of determining pmin and pmax. We could of course set pmin = 0 and pmax = 99999 or any other sufficiently high number. This would ensure that we sell a little bit every time the price goes up and buy a little bit every time the price goes down, but that is not a very profitable strategy. In practice this pretty much amounts to a buy and hold strategy where only a small fraction of the portfolio is invested in bitcoins.

The other extreme would be setting pmin = pmax. This would mean that as soon as the price crosses the threshold given by this price, we buy or sell everything, depending on the direction of the move. If we can come up with a way to define this threshold well (and update the definition constantly to take account of the drift in the price), this would be a nice strategy indeed.

My definition of pmin and pmax is somewhere between these extremes. While the exact definition is part of my special sauce, I make sure that the values depend on the historical prices and are updated constantly. If the price moves up (or down) a lot, we must continue trading at this new level. Fine tuning of the parameters was done by backtesting them against the last month's worth of data. Out of sample tests were  performed against the bitcoin price history going all the way back to 2010.

Version 1.1 is out

I just released v1.1. After almost two weeks of no change to the running code, I decided to push the most recent changes to the production system.

New features include:

  • More sophisticated backtesting module, on the fly comparison to buy-and-hold strategy and to actual historical trading performance
  • The minimum trade size is no longer fixed but depends on the current portfolio value. This makes it possible to add (or withdraw) funds at any time without having to change the trader parameters
  • More automatic tracking of trading behavior: logging of recent trades and plotting of last prices and buys/sells

Building an algorithmic BTC trader in python

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.

The bot trades on the Kraken bitcoin exchange, using veox's krakenex exchange API. It is programmed exclusively in python 2.7.6.

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:

  1. calcBaseWeight determines which ratio of fiat/BTC we should be holding, given the current market data.
  2. calcMomentum adjusts this base weight depending on the current momentum of the price
  3. calcCoinsToTrade converts the difference between the target weight and the current portfolio weight into an effective number of coins to be traded
  4. 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.

Preparations

I have been working on an algorithmic bitcoin trading application for a couple of weeks now. This website contains information regarding the setup, strategy and performance.

The bot trades EUR vs BTC and is programmed in python. In the following posts I'd like to discuss the setup, the strategy and the performance of the trader. I'll get into backtesting and performance measurement and keep this site updated with everything I've learned.

I'm always happy to receive any comments, feedback or questions either directly in the comments or through email or twitter (see contact for details).