Step 3, UnProfit: A Naive Experiment in Cryptocurrency Trading

A couple of years back I took it upon myself to build a trading bot.  I’d just finished a contract, had a month to kill and it seemed like a challenging project.  I had no illusions about getting rich but hell, if it worked it might become a nice passive income.

I started from the hypothesis that given a full knowledge of historical prices and a the ability to compare the present to all history, a bot might be able to predict what’ll happen to BTC in the next few minutes.  Not perfectly, but you only need to be right 51% of the time to make money.  This became the guts of an algorithm named ‘shapefit’.

The core task seemed to be finding a representation for history that:

  1. Was normalised, so I could match the ‘shape’ of the market and not absolute prices (i.e. BTC is trading at a different level today to 2011, but the market’s behaviour is still valid)
  2. Could be rapidly searched to find the closest N-minute-long fit for ‘now’ (which meant it’d need to fit in RAM)
  3. Could be persisted to disk (don’t want to re-train every startup!)
  4. Was efficient enough to run in Python.  I do not pretend to be a C programmer.

 

Like a monkey scientist armed with sharp tools and big ideas, I set about making a Python 3 application.  I named it – whimsically – the Lucky Horse Trading Framework.

 

Sundry features included:

  • Adjustment of trade size to fit a perceived level of confidence in predictions
  • Awareness of exchange fees when examining potential trades, including how those fees change with volume
  • Numerous algorithms (only one running at once; I’d had the idea of letting them compete to use the most profitable at any given time)
  • Pluggable interfaces for exchanges (I only used one but had the idea of doing a bit of arbitrage on the side)
  • Pluggable system of inhibitors/enablers that individual bots could choose to use
  • Pluggable market signals – file-based dump of history for testing plus…
    • WebSockets interface to BitStamp via Pusher, to consume live market data and keep the internal representation of the orderbook updated.
    • Signal data recorded to a database, in its own thread, for later (& potentially online) update of the training data
  • Plenty of unit tests for the logical building blocks.  Be paranoid where money is involved.
  • Unit testing the complex behaviour of your algorithm, however, is much harder.  I wonder how grown-ups do this.
  • A test mode where it would run against all market history and simulate trading.  I suspect a lot of people skimp on this (e.g. they assume 100% of every order will be filled, or that no-one will ever beat them to an attractive order) and lose a lot of money when they plug in their bot for real.
  • Graphing (CSV files -> GNUPlot) to visualise the bot’s performance

 

The most promising algorithm, shapefit, represented historical fluctiations as a tree of normalized values averaged over N seconds (I tried 60<=N<=900).  This made lookups very fast.  Using Numpy to do some of the calculations sped up the training mode; by the end of the project I was able to import BitStamp’s history in a few minutes and backtest against all of it in half an hour.  [NB: just a test; I know why you shouldn’t train & backtest on the same data]

Trouble was, it didn’t quite make money.  Even in a blindly optimistic test-mode that assumed no-one would ever beat me to the orderbook.  In a rising market it would just about grind out a profit, only to chuck it all away entering some daft trade just before a big correction.  Compared to “build time machine, go back 3 years, buy BTC and sit on it” the results were pitiful.

I spent a lot of time massaging the algorithm.  Making it more or less paranoid about trading.  Scaling the matching window.  Checking a standard deviation of price in the last N minutes to suspend trading when the market got too volatile.  Generating certainty-measurements from predictions.  Adding all those fudge factors books about trading tell you not to.  Implementing a couple of other, toy algorithms to see how they performed.

I did not try machine learning approaches.  This was 2014: the libraries weren’t so advanced as today, and I’m a hacker, not a domain expert in statistics or machine learning.  In retrospect I should have given it a go.

Drawing comedy graphs is more entertaining than losing imaginary money.  Repeated prayers to Imhotep (the deity of shit trading) went unanswered.

 

But nothing I tried would coax it into making money long-term.  Disheartened I gave up; fed the thing a BTC out of bloody-mindedness and watched for a few days as the money trickled away.

Then I killed it off for good.

Apart from the not-making-money thing the bot worked well and I’m still proud of a few of the ideas.  Doubtless they’re old hat to the pros, but coming from first principles I’d like to think I had a few good ones.  The main takeaway was that for any chaotic (or at least fast-evolving) system it’s a fallacy to believe past behaviour can be used to infer the future.

Another thing I’ve come to believe is that the barrier to cryptocurrency trading is so low you’re up against every smart kid in the world, not to mention algo traders from real banks playing about in their spare time.  I learned a lot building Lucky Horse, but to make any money you need a far better grasp of the math & stats than mine.  At least I was smart enough to test the thing before feeding it real money: all I lost was a couple of hundred dollars and a month of time.

I’ve stuck the code on GitHub.  If by some unlikely miracle it makes you rich, Imhotep requires you buy me a beer.