Arbitrage is the simultaneous purchase and sale of an asset for profit. Arbitrage is based on when the law of one price is not upheld, and if arbitrage is consistently occurring the market is not fully efficient.

Large price differences have been observed in historical data between cryptocurrency exchanges. In late 2017 and in the beginning of 2018 the first major bitcoin bull run took place. Liquidity was low and price differences of over $1,000 could be observed between the exchanges. The term “kimchi premium” was coined in 2016 after observations that the price of Bitcoin was higher on exchanges in South Korea compared to exchanges in the US. The premium reached its peak at nearly 55% in early 2018. During the same time when the price difference between the US and Korea was 20% in fiat currency, it was only 3% on average on the same exchanges between Bitcoin-Ethereum.

The literature shows that cryptocurrency markets have become more efficient since 2018, but there are still price differences between exchanges.

Types of arbitrage on centralized exchanges

The reason why there still exists price differences after the use of these methods is because there are frictions in the systems such as transaction fees, transaction time delays between exchanges, KYC and regional registration obstacles, liquidity constraints, volatility, and so on. The question is if one is able to capitalize on the price differences?

Identify price differences

Most exchanges have both REST APIs for action based calls and Websocket APIs for continuous streaming of data. The Websocket allows us to send a call once and then open up a stream of price data. To get API keys for the exchanges you usually need to register an account. Some exchanges have third party wrappers that can be installed with, e.g, pip.

pip install python-binance

We will use Websockets but if one wants to simply get BTCUSDT price from the API it’s done as,

from binance import Client

client = Client(binance_api_key, binance_api_secret)
btc_price = client.get_symbop_ticker(symbol='BTCUSDT')

Using Websockets we can stream data in the following way,

from binance import ThreadedWebsocketManager

def main():

    symbol = 'BTCUSDT'

    twm = ThreadedWebsocketManager(api_key=binance_key, api_secret=binance_secret)
    # start is required to initialise its internal loop

    def handle_socket_message(msg):
        '''process websocket messages'''
        print(f"message type: {msg['e']}")

    # subscribe to new stream
    twm.start_symbol_ticker_socket(callback=handle_socket_message, symbol=symbol)

if __name__ == "__main__":

This can be done for other exchanges as well, and prices can be compared. If this strategy were to be implemented one would further need to look at the order book to see the depth of the market and identify if the trade would be profitable. If the bid (buy) on exchange A is higher than the ask (sell) on exchange B for a sufficient depth of the order book (to avoid slippage) there is an arbitrage opportunity.