Crypto arbitrage musings

There has been a lot of talk and speculation about crypto-currency arbitrage, if it works at all and people are doing it and how it can be done. Here is my attempt to summarize the current state of “crypto arbitraging” from my own experience. Following topics:

  • arbitrage between exchanges (deposit / withdrawl)
  • arbitrage between exchanges using coins-swaps with fast coins
  • simultaneous pair trading (classic arbitrage)
  • arbitrage within one exchange

Between exchange arbitrage (deposit / withdrawl)

Since there are many major crypto exchanges, it is helpful to explore cryptocoincharts and see ranking lists of exchanges by traded volume of certain cryptos. For example Bitfinex trades 2.5x the bitcoin (BTC/USD) volume of Kraken.

Prices on different cryptos are different because a) the markets are unregulated, immature and very inefficient and b) because political developments play a major role in how cryptos are traded within a a local ecosystem.

For example, bitcoins on golix, an Zimbabwe based exchange are sometimes sold 2x higher then on other markets. That is because of hyperinflation people in Zimbabwe do not trust the government issued currencies and bonds (they have regular USD, Zimbabwean USD and specially issued government bonds). Before you jump on that big arbitrage opportunity, signing up on golix, be aware that you will not be able to withdraw any USD from Zimbabwe. In order to do that, you would need a trust local person that lives in Zimbabwe to withdraw money to his/her bank account, then exchange those Zimbabwean dollars to real USD on the local black market (with a mark-up of up to 50%), then bring cash USD to the local bank, bribe some government officials to allow you regular big-sized money transactions out of the country and then make an international transfer. Good luck.

If we stick to the regular exchanges, it looks very simple. Buy BTC/USD on exchange 1, send to exchange 2 and withdraw money. Repeat. Sounds easy? Let’s revisit the steps in detail:

Finding stable price differences: those actually exist and are some quite stable over the day. In theory we only need a time window fo 30 minutes to an 60 minutes for a bitcoin transaction. For faster cryptos such as Ripple, Litecoin or Dash, it can be 30 seconds to 2 minutes to buy, transfer and sell.

This looks quite stable over the day. If we buy at Bitfinex, send to OkCoin and withdraw, we make 10%.

Problem 1: Funding. Not all exchanges offer fiat funding at all. For example HITBTC can only be funded with Tether, although their pair trade names are BTC/USD. This is actually wrong as they only trade BTC/USDT (BTC to Tether). Tether is a crypto-currency created by the Bitfinex community, is pegged to 1.00 USD and was created the goal to move around fiat USD quickly between exchanges. However, before you start using Tether you should read more about it and its ramifications. For example start with this blog post by an eToro investor.

In general it is advisable to follow reddit channels for cryptos and the single exchange channels such as the Bitfinex channel, to learn about what is going on and what users are talking about.

Bitfinex is usually very cheap. For sending USD to bitfinex, be aware that it is reported by many users on reddit that bitfinex is not on top of operations, sometimes taking weeks to credit or withdraw either cryptos or fiat money. There are many reports of deposits not credited or withdrawls not arriving at all.

How to solve that? For example by using a third party payment provider such as epay where you can deposit USD in timely manner and buying BTC/USD directly on the payment platform which in turn buys it from Bitfinex.

An alternative would be to buy at another reputable exchange, buy BTC/EUR using a SEPA transfer instead of a SWIFT international transfer. This only takes 1–2 days and works well with Kraken GDAX or CEX.io. However, your arbitrage opportunity will be lower than as for example GDAX is usually more expensive. Also the BTC/EUR rates can be more expensive in general.

In general, there is a funding risk involved that you can only control by monitoring users reports on reddit or experimenting and timing funding methods. From my experience SEPA transfers on GDAX and Kraken work well.

If we want to take it one step further we ccan incorporate FIAT Forex into our strategy. That means for example we could buy BTC/USD and sell for BTC/EUR. Or we buy BTC/GBP at Kraken, sell it to EUR, then buy BTC/EUR, send it to the luno.com exchange in South Africa and sell it to African Rand (ZAR). We would make 50% ROI. Now you have your African rand, how do we get them back? Actually not at all, because luno.com requires you to be a local resident with a local bank account. Which leads me to:

Problem 2 withdrawal: as mentioned, many users currently complain about Bitfinex both not depositing and withdrawing money in time and reliably. Thus the same rule applies here, one has to carefully check and monitor withdrawals channels on the different exchanges or just stick to EUR/SEPA and only do small arbitrage trades (3% to 5%, sometimes more). To summarize:

  • Some exchanges only have Tether, you will have to buy Tether on Kraken (price usually USD + 2–3%) or buy your crypto somewhere else and transfer it to make the following trades
  • Withdrawl fiat other then EUR or USD can belimited to having a local bank account or credit card in a country. For example you can withdraw Russian RUB on CEX.io, but they require a VISA card issued by the Russian federation.
  • Non-SEPA withdrawals using SWIFT can take weeks
  • withdrawls on credit cards are sometimes possible, but you pay 3%+ mark-up fees and the withdrawl can also take several 3 days (not instant)
  • many exchanges block withdrawls to US bank accounts (nice to live in Switzerland)
  • withdrawals using third party providers is sometimes offered, but they are usually shady and there is no guarantee you will ever get your money or they take horrendous fees of 5% and more

To take it one step further, not only can you incorporate a FOREX conversion into your strategy, but also coin swaps. For example we could do:

Buy BTC/USD (bitcoin) on Bitfinex, Swap to ETH (Ethereum), send to another exchange and sell the ETH to EUR and withdraw with SEPA

For monitoring all those several thousand different strategies, I built myself a tool using R, Python and ShinyR that ranks and visualizes all the possible strategies and lets me filter by deposit and withdrawal currencies. Data for all pairs is free and available across most of the important exchanges for example via cryptowach API

In case the best strategy has a deposit exchange that does not accept fiat deposits, you could instead buy BTC/USD on a third exchange with the cheapest rate and then send the BTC to your entry exchange to execute the strategy.

When writing algorithms to construct these strategies it is important to note that there are 2 types of swaps. If I own BTC, you can:

  • buy ETH/BTC = buy order, buying and receiving ETH for BTC
  • sell BTC/ETH = sell order, selling BTC to receive ETH

For automated trading using APIs, this can be very confusing, also some exchanges use different pairs for names on the front-end, and again a different name on the API level (Kraken uses XBT instead of BTC). More to that in another post regarding APIs and data feeds.

In the matrix above you can see 5 branches to generate strategies, below an example with actual pairs. Note that you can replace BTC and USD with any crypto or fiat.

  • buy BTC/USD send and sell to USD
  • buy BTC/USD, swap-sell, send, sell back to USD
  • buy BTC/USD, swap-buy, send and sell to USD
  • buy BTC/USD, sell to EUR, buy ETH/EUR, send, sell to USD
  • buy BTC/USD, send, sell to EUR, buy ETH/USD, sell to USD

Between exchanges using coins-swaps

The idea of coin-swaps leads us to a next set of strategies. As already mentioned one can easily swap BTC to ETH or different other coins. In this way we could construct a strategy that relies on just sending coins between exchanges with the goal to increase the number of coins without cashing out. For example:

Send BTC on exchange 1 to exchange 2, swap to ETH, send back, swap to BTC.

However, that requires us to have fast coins. As Bitcoin or Ethereum transactions can take 30 minutes or more, one can use the faster coins, such as Dash (DASH), Ripple (XRP) or Stellar (XLM) that can be transferred within seconds depending on the average confirmation time on the blockchain and the exchange operations. Kraken has a list here or you can review bitinfocharts

As already mentioned, Tether was invented with the goal to move around FIAT currency value easily on the blockchain. Thus, we can use Tether as a transport vehicle and create strategies where we swap Tethers around to increase the number of Tethers and finally selling them on Kraken to USD.

Start: assume you own Tether

buy BTC, send to Kraken, sell to USD, buy USDT, send back
buy BTC, send to Kraken, swap to ETH, sell ETH to USD, buy USDT, send back

Simultaneous pair trading

This is a classic market-neutral arbitrage strategy used on regular stock markets. The idea is to execute both long and short positions on the same asset being traded on different markets and bet on the difference in spread.

We assume that one asset should always be near same price between markets. However, when an asset, such as Bitcoin, is overpriced at one exchange, and we know from historical data, that they are usually near same price, one could assume that the price difference (spread) will revert back to 0 later. In that scenario, we can open a short position on the overpriced BTC (Bitfinex) and at the same time a long position for BTC (Bitstamp). In that way we make money if Bitfinex BTC has a higher relative price movement than Bitstamp BTC which it will have when it reverts back to a near 0 price difference.

This strategy has the following advantages:

  • market neutral: it doesnt matter if the market crashes, because you bet on the relative spread between 2 assets.
  • you can trade in parallel on 2 exchanges without having to transfer funds

If still unclear, read more about it here:

A very popular trading bot for that is Blackbird which is open source and you can download, compile and execute on your own server.

Arbitrage within one exchange (high frequency)

Having already introduced swapping of pairs, that is of course also possible within one exchange.

For example, you could have your algorithm continuously check pair swaps for small price differences and execute trades automatically.

buy BTC/USD, sell BTC/ETH, sell ETH/USD

I had my engine log short term arbitrage opportunities > 1% on Bitfinex, Kraken, CEX.oi, HITBTC and Poloniex. Let’s look at some real data from the last 24 hours:

As we can see, there were 38 potential >1% swaps with EUR pairs, 71 with USD pairs and 6 with Tether pairs (usdt). From the below table we can see that the pairs can also be high volume pairs such as BTC (Bitcoin) and XRP (Ripple) and not only rare pairs that have low order book liquidity.

When you actually want to execute this kind of strategy, things get complicated. First you will need pairs with enough liquidity in the order book, otherwise you get stuck in the middle. If you execute trades one at a time, you can either choose to do market orders or limit orders. Market orders always take the latest available price in the order book, while in a limit order you define the price you want to buy or sell, otherwise the trade is not executed.

First it might be safe to assume that just executing market is easiest. I ran some experiments on Bitfinex executing market orders in sequence and observed some unexpected behavior.

Turned out that Bitfinex is sometimes not crediting me cryptos that I should have earned after certain trades according to the API and account balance log files. Bitfinex conveniently only shows trades volume, trade price and fee, but not the resulting balance.

For example, my engine detected an arbitrage window and executed:

buy NEO/USD, swap NEO to ETH, sell ETH to USD

In terms of numbers, it executed (numbers rounded for readability)

  • trade 1: buy 0.84 NEO at price 119.00 (=$100.00)
  • trade 2: sell 0.84 NEO to ETH at price 0.0936

Now that would have left me with roughly 0.0786798[…] ETH to sell at $1293.00 to have an 1.7% profit. However, after trade 2, Bitfinex only credited me 0.070 ETH. Yet, a user will never find out when executing market orders, because Bitfinex conveniently only displays price and amount but NOT resulting Account balance after each trade (see chart below). I can infer this with 100% certainty, because my engine queried the Account balance after trade 2 and only found less ETH to execute trade 3. The fees are so minor that they dont really make a difference here. Even a day later, the remaining ETH did not show up on my Account balance.

In fact Bitfinex does have asynchronous processes to subtract fees or credit balance. So 2 things can happen:

  1. cryptos are credited with delay up to several minutes and not available for fruther trading (which means you have to fill up reserve coins for every pair which is very inconvenient)
  2. A user can have negative account balances for a while, which is really confusing users

I emailed support several times and never received an answer, of course. That leads to the following assumptions:

  1. Bitfinex does not correctly display market order data
  2. Bitfinex does not correctly display partial fills
  3. Bitfinex commits systematic fraud by subtracting small amounts from market orders without users noticing

What does it mean now?

When doing within exchange arbitrage, one should use limit orders or FOK (fill-or-kill) orders. This is less convenient than market orders but gives more control. Furthermore, to spot these windows, one will have to integrate with Socket APIs to get market data in real time (which is a lot of hassle) and ideally use machine learning to predict the next opportunities by inspecting order books and place FOK order in advance. This requires a lot work before hand.

UPDATE June 8, 2018:

5 months later Bitfinex reacted to my complaints and credited my missing trading proceeds! You can make your own conclusions from this, if this is systematic manipulation or just a little bug in the system :)