In the world of finance, arbitrage is a strategy where securities, commodities or currencies are purchased in one market, and then sold at a higher price in another market. The price difference between the two markets minus any trading fee becomes the profit.
For cryptocurrencies, most of the trading activities occur 24/7 across numerous exchanges. The price of an asset is determined by the economics of supply and demand, which may not necessarily be the same across different exchanges. A cross-exchange arbitrage strategy can leverage this difference, and thus provide an opportunity for traders to potentially capitalize on.
In this tutorial, we'll walk through how to build a Python-based arbitrage bot that identifies arbitraging opportunities by tracking crypto prices and other useful metrics across crypto exchanges. Once your bot is set up, you can use a Python Trading Bot to automate trades on exchanges.
We'll be using the Demo endpoints in the CoinGecko API to retrieve crypto price data. These endpoints are free to access but require keyed authentication.
- /exchanges - Endpoint to get a list of all supported exchanges along with relevant data (id, name, country etc.). Note that only those exchanges that have an active trading volume on CoinGecko will be listed.
- /exchanges/{id}/tickers - Endpoint to query a particular ticker based on a given exchange id. Response contains useful data such as time of last trade, last price and volume.
- /exchange_rates - Get a list of exchange rates from BTC to other currencies.
- /exchanges/{id}/volume_chart - Get historical total volume data (in BTC) for a selected exchange with unix timestamps.
However, since our crypto arbitrage bot is intended to run all the time, it is possible to run into rate limits. In that case, a Pro API key can be beneficial.
Disclaimer: Any use or reliance on our content is solely at your own risk and discretion. Do conduct your own research, review, analyze and verify our content before relying on them. Trading is a highly risky activity that can lead to major losses, please therefore consult your financial advisor before making any decisions.
Prerequisites
We will use a Jupyter notebook to create and run the bot. Make sure that Python 3 and the following additional packages are also installed:
pip install jupyterlab
pip install pandas
pip install numpy
pip install pytz
To start coding in a new notebook, execute the following command:
jupyter lab
This should open up a new tab in a browser window. In case you want to make use of the notebook shared via the GitHub repository, clone the repository first, and then open it within the Jupyter environment.
1. Setting Up the Project Environment and API Access
The python packages can be loaded as shown below:
Note that we have set up additional display options for the pandas library using pd.set_option. This will be helpful later since we will be making use of DataFrames to visualize all the data. Also, clear_output is needed once we start running the bot and want our data table to refresh periodically within the notebook.
The demo API key can be read from a file locally. The use_demo header is used in the get_response function, which will make the request for us. Status code 200 indicates that the request was successful.
2. Get the List of All Crypto Exchanges
To get the complete list of all crypto exchanges, make an API call to the /exchanges endpoint in the CoinGecko API. The following query parameters will ensure that we get all the results in a single page.
Using the function defined earlier, we can now make a request. The result can then be converted to a Pandas DataFrame for easy visualization.
To list exchanges by trading volume, the above DataFrame can easily be sorted on the “trade_volume_24h_btc” column.
Exchanges can also be filtered based on the country of registration. This will be useful later since we can target specific markets.
3. Get Crypto Exchange Tickers
For each exchange, data about a number of cryptocurrency tickers (or trading pairs) are available. We want to filter through the list and find the latest trade for our ticker of interest. After making a request to the relevant endpoint, we can loop through the response and find the relevant base and target currency. An empty string is returned when no match is found. This can happen since not all trading pairs are available on all exchanges.
An example for exchange “gdax” (Coinbase) for the trading pair (or ticker) ETH-USD is shown below:
4. Convert Timestamp to a Local Timezone (Python)
As you can see above, the data is returned with a timestamp in a different timezone. When monitoring the activity of our bot, it will be helpful to convert it to our own timezone. This can be easily achieved using the pytz library as done for “Europe/Amsterdam” as an example.
5. Get Crypto Ticker Data for Multiple Exchanges
Now that we know how to get the ticker data for a single exchange, we can extend the same logic to collect data from multiple exchanges. To focus on a certain market, we can also add a filter for the country. From the ticker response, we gather the last trade price, last volume, spread and trade time (converted to local timezone). A warning will be displayed if the trading pair is not listed on a given exchange.
The bid-ask spread percentage is the difference between the lowest price asked for an asset by a seller and the highest bid made by a potential buyer. A lower value of the spread indicates higher liquidity and trading volume for the given asset on the exchange. Conversely, higher spread usually indicates lower liquidity. This metric can therefore be used to judge whether a particular exchange should be considered for executing arbitrage trades or not.
6. Get Bitcoin Exchange Rates for Multiple Currencies
Data for various endpoints (for example, exchange volumes) is reported in units of BTC. For our bot, it will be interesting to additionally determine the percentage of total exchange volume that is being traded for a given ticker, which gives us further insight into the liquidity for a given exchange.
In order to convert BTC to a different target currency, we can get the exchange rate via CoinGecko API, as shown below:
7. Fetch Historical Exchange Volume Data
Using the historical volume data for a given duration, we can determine the latest volume using a simple moving average over a 7-day window. This volume (default in BTC) can then be converted to our currency of interest using the exchange rate as determined in the previous section. Once we know the total exchange volume (all tickers combined), it is straightforward to determine the percentage of our ticker volume as will be shown later.
An example for 30-day volume (only 15 rows shown for brevity) on Kraken is shown below:
8. Aggregate and Display Trades by Crypto Exchange
Before we run our bot, it’s important to think about how data will be aggregated over time. In essence, our bot will fetch the latest trade data at regular intervals. For some exchanges, no new trades might occur during this time; for others, many trades might get executed. Therefore, it’s crucial to remove duplicates. The number of unique values can then be used to determine the number of trades. Also, to build a reliable arbitrage strategy, it would help to collect statistics over a period of time. We will therefore perform a group by operation over exchange id’s, and calculate the mean of all relevant columns.
Additionally, a new column with the percentage of total exchange volume (as shown in previous sections) will be added.
We will further highlight the exchanges with the maximum and minimum prices for better visibility using the function below:
9. Running the Crypto Exchange Arbitrage Bot
Our bot needs to continuously monitor the latest trades on multiple exchanges. We will therefore execute a cell with a while statement. This will make the code run continuously until stopped by the user. To introduce a one-minute delay between updates, we will use a sleep statement. Since the API itself refreshes every minute on the Demo plan, it's not necessary to have a shorter delay.
As an example, we can test the bot for ETH-USDT pair for all exchanges in the United States. After running the bot for about 2 hours, we can see the following:
Highlighted in green are the lowest price (Coinlist) and the highest price (Binance US). An example arbitrage strategy could therefore be to buy ETH at Coinlist and then immediately sell on Binance US.
Another interesting point to note is the correlation between the bid-ask spread and number of trades. On Gemini, the spread is quite high – indicating that liquidity for this trading pair is lower. This is further confirmed by the low number of trades (only 2!) compared to other exchanges for the same time period.
To stop the bot, navigate to the “Kernel” tab at the top and select “Interrupt Kernel”
Conclusion
Harnessing the power of CoinGecko's API and Python programming in a single Jupyter notebook, we are able to continuously monitor the latest trades from various crypto exchanges and highlight cross-exchange arbitrage opportunities.
If you've found this guide helpful, be sure to explore our extensive library of API guides and resources!
Subscribe to the CoinGecko Daily Newsletter!