In the months between December 2017 and March 2018, I built a bot which executed around $50 million worth of cryptocurrency market-making trades. This is the story of how I got into market making, the theory behind the bot’s algorithms, and the competition that grew between market-makers.
It’s November 2017 — Bitcoin’s price is rapidly rising towards the $10,000 mark. Its exponential rise in price is pushing it further into mainstream consciousness each week, attracting even more investors, pushing the price further up.
During this time, I’m away on holiday with two friends. Both of these friends had invested not insignificant amounts of their own money into Bitcoin, and were profiting off of the rising price. As the only one of the three who hadn’t even considered investing before, I feel like I’m missing out.
When I get back home from travelling, one of the first things I do is find an online cryptocurrency exchange and deposit $500 into an account. Wanting to ride the wave, my plan is simple: buy $500 worth of Bitcoin, and increase my investment if I see returns.
Before I pull the trigger on my $500 investment though, I notice something strange; the exchange which I was trading on has a large ‘spread’. To understand what a spread is, and why this is significant, we need to look at some basics about how an exchange works.
Typically when we think of an exchange-traded asset, like a stock, we think of it as having a fixed price which we can buy or sell it at. For instance, we might think of an Apple (AAPL) stock having a price of $100. In reality though there isn’t one single price, but rather there are two different prices:
Most buyers are willing to pay less than sellers are willing to sell for, and so the bid price of an asset will always be below the ask price.
In the case of the Apple stock, these two prices are likely to be very close together. The bid price might be $99.99, and the ask price $100.01. The difference between these two numbers ($0.02) is what we call the spread.
The spread is small on a popular, stable stock like Apple. This is because there are always plenty of people willing to buy the stock, which causes the bid price to rise, and plenty willing to sell, which pushes down the ask price. Competition amongst both buyers and sellers pushes the bid and ask prices close to one another.
When I first started looking at Bitcoin exchanges though, the spreads were much larger, often up to $100. Bitcoin was trading at around $10,000 during this time, meaning its spread could be up to 1% of its total value (in comparison to just 0.02% in the Apple example.
The size of the spread on Bitcoin was a consequence of the market chaos that was emerging in December 2017. Retail investors — you, me, the average person on the street — were flooding into the market. Prices were so volatile as a result, that the spreads could never stabilise.
Large spreads might sound like a bad thing, and to an extent they are, but they also present an opportunity to profit.
Let’s say that Bitcoin has a bid price of $9,900, and an ask price of $10,000, giving it a spread of $100. If you’re able to buy 1 bitcoin for $9,900, and then sell it immediately after at $10,000, you’ve just made $100 profit.
If you’re thinking that this sounds too good to be true, then you’re correct. One reason you might be skeptical of the above comes from the question: what about exchange fees? To see how fees fit into this, we have to take another slight detour into how exchanges work.
Let’s say you want to buy bitcoin, which is trading with a $9,900 bid price and a $10,000 ask price. There are broadly two ways you can go about this.
Firstly you could submit a maker order. This is where you specify a price anywhere up to the ask price — so between $0 and $10,000 — and a quantity that you’re willing to buy. Your order sits on the exchange until someone comes along and decides to take you up on that order. This could happen milliseconds or days later, depending on how high your price is and the volume on the exchange.
Alternatively, you could submit a taker order. This is the exact opposite of a maker order, and will allow you to buy bitcoin instantly. The catch though, is that your taker order is matched with the lowest priced of all the sell maker orders. Naturally, this will be at the ask price, because this is the lowest that anyone is willing to sell for.
Before we go forward, there are a couple of important things to note about maker & taker orders:
This last point is crucial, because it helps to explain the fee structure that most exchanges have. Because exchanges want to maximise liquidity, they’ll typically charge higher fees on taker orders than they do on maker orders. Some exchanges, including the one I was using, only charge taker fees: there are 0% fees on maker orders.
Back to our earlier example. If we’re able to buy Bitcoin at $9,900 and sell at $10,000 using maker orders alone, then we have $100 of pure profit for each Bitcoin we transact.
The need to use maker orders isn’t just to avoid fees, but also comes from the fact that if we bought using a taker order, we’d have to pay the ask price — $10,000. If we then sold via a taker order, we’d have to sell at the bid price — $9,900 — losing us $100.
So, using maker orders, we can pretty much guarantee profits by buying at the bid price and selling at the ask price. There is one final problem however, which presented the biggest challenge to making an algorithm which could do this programmatically.
As we touched on earlier, a maker order needs a taker order to come along and ‘take’ it before a trade can occur. Taker orders will always ‘take’ the best price. If you want to buy Bitcoin via a maker order, then in order for taker orders to match against your order, you’ll have to bid just above the bid price. How much above the bid price you offer doesn’t matter, it can be by an amount as small as a single cent, e.g. $9,900.01.
The first step of writing a market making bot therefore, is to be able to put in buy (maker) orders just above the current bid price. This requires one API request to check the bid price, and another to submit your order.
In theory, it’s fine to just bid one cent above the bid price. In practice however, in the time between checking the bid price and submitting your order, the bid price will often change. To ensure that your order sits higher than all of the other buy orders, and so sets the new bid price, it’s often advisable to bid 5–10 ¢ above the current bid price.
This ensures that, if a (taker) sell order comes in, it will be matched against our (maker) buy order, and we’ll have bought however much Bitcoin without losing anything to fees.
We can then do the exact opposite of what we’ve just done, on the sell-side. We check the current ask price, and bid several cents below that. This ensures that if a (taker) buy order comes in, it gets matched against our (maker) sell order.
We’ll have just made a tidy profit roughly equal to the spread (the difference between the bid and ask prices) multiplied by however much bitcoin we were able to trade.
If you’re still thinking that this is too easy to be true, then you’re still correct. Whenever there’s an obvious opportunity for profit, traders pile in, and this creates competition. The most obvious example of this can be seen by looking at the competition created by market-makers jostling amongst one another to set the bid price. (Remember, you have to have your buy order at the bid price in order to execute a trade, the next time a seller’s taker order comes in)
Back in December 2017, the competition was so intense that the bid price would typically change multiple times per second. Often it would only increase by one or two cents, as traders fought amongst each other to maximise the amount of time they set the bid price, whilst also wanting to offer as low a price as possible.
My bot initially set out to check the bid price, and bid 1¢ higher. Sensible as this first seemed, I found that by the time my order went through I would often be several cents below the (constantly changing) bid price.
To get around this, and to ensure that as many as possible of my orders would beat the current bid price, I took measurements of how much the bid price would typically change every 100ms. This allowed my bot to offer a price sufficiently higher than the bid price (~5¢ higher), so that other traders wouldn’t beat my price as my order was being processed.
I also began to consider how the size of the spread would affect how much I was willing to offer over the current bid price. As we saw earlier, profit from any trade is directly proportional to the size of the spread. This made it even more important to beat the bid price when the spread was large. Because of this, I wrote a formula which varied how much higher than the bid price I would offer, based on the size of the spread too.
I’ve so far talked mostly about the buying aspect of market making, but selling works exactly the same. As soon as you’ve bought your Bitcoin, you need to offload it at the (higher) ask price. There’ll be competition on the ask price, just as there was on the bid price, and so you have to undercut your competitors by offering a sell price several cents lower than the current ask price.
Back in late 2017/early 2018 though, there was typically much less competition on the ask price. I assumed at the time that this was because of there being more demand than supply for Bitcoin, explaining why there was more competition amongst buyers than sellers.
Market manipulation refers to a variety of malevolent tactics that traders employ in markets in order to gain an unfair advantage. As an unregulated market, cryptocurrency exchanges were (and still are) ripe with market manipulation. The most frequent form of manipulation was what’s called spoofing, the act of placing orders simply to alter the appearance of market conditions.
To give an example how this works, consider the example from earlier with the $9,900 bid price and $10,000 ask price. Our spread here is $100, which presents a good opportunity to market make. If someone comes along however and places a buy order with a price of $9,999.99, then the spread shrinks to a mere 1¢. With a spread so small, it appears impossible to profit off of market making, and all activity grinds to a halt.
A buyer placing a maker order 1¢ below the ask price isn’t in itself market manipulation. In fact, if your exchange doesn’t charge maker fees, this is a quick & efficient way of buying Bitcoin. The issue however was that whenever these buy orders appeared, they would typically be for the smallest amount possible; 0.00001 Bitcoin, worth roughly 10¢.
The reason another market maker might place such a small buy order, right below the ask price, is genius. If another market maker has just been able to buy Bitcoin at the bid price, they then have an incentive to sell it at the ask price as soon as possible. The longer it takes them to sell their Bitcoin, the greater the risk of the ask price (and thus the spread) moving, and of their profit varying.
Sure, you might say there’s just as much chance of the price rising in this time as there is of it falling. A market maker doesn’t care about this though; their job isn’t to speculate on price, it’s to get in and out as quickly as possible.
In order to stop the price falling, and to stop competition on the sell side from pushing the ask price down, the market maker places their sell order just below the ask price, and inserts a (‘spoofed’) buy order just below the new ask price. This latter order will have as small an order size as possible (0.00001 Bitcoin).
This has two effects:
This second point is crucial, as it explains why virtually all market making bots switch off when a spoofed buy order goes in just below the ask price. In reality though, even though the spread appears to be just 1¢, there’s still opportunity to be had.
Let’s say that the next seller’s taker order comes in for 1 Bitcoin. The first 0.00001 Bitcoin will be sold to the market maker with the spoofed order, taking that order out of the exchange. The next 0.99999 Bitcoin will be sold to the order at the new bid price, the highest priced order below the spoofed order.
One of the biggest improvements I made to my bot was allowing it to ignore spoofed orders in calculating the spread. Even though the ask price might only be 1¢ higher than the bid price, my bot would look past spoofed orders, to find what the spread would be if not for the spoofed orders (which could still be $50–$100). If this spread was large enough to present an opportunity, it would compete to place the highest priced buy order after any spoofed order. When sellers’ taker orders came in, this meant that a few cents worth of Bitcoin would be sold to the spoofers, and then the rest to me.
The first few months of 2018 were turbulent. After Bitcoin’s rise to $20k in December, the wheels had started to come off, and the price was falling quickly.
Though bad for investors, this provided huge opportunity for market makers. The high levels of volume on both the buy and sell side (which meant more taker orders coming in) massively increased the amount of trades per day that an efficient market maker could execute.
This period of opportunity was relatively short-lived though. After the frenzy of January and February, volumes started to dry up, meaning fewer opportunities to profit. Despite the falling trade volumes, the number of market-makers kept increasing, as new bots entered the exchange.
More market makers on exchanges led to more competition on bid and ask prices, in turn narrowing the spreads. The additional competitors also meant that orders would typically be at the bid price for a shorter period of time, as there were more competitors ready to outbid you as soon as your order had been submitted.
Due to the increased competition and fewer opportunities to profit, I’d turned all my bots off by March, and haven’t turned them back on since. Increased maker fees on many exchanges have deterred me from getting back into the market making game, but there’s likely still opportunity out there for anyone who’s clever enough to pick their moments.
All in all, I’d traded around $50 million worth of Bitcoin between December 2017 and March 2018, with an ROI of 20.2.