Profile picture

Co-founder @ RMOTR

Coin API Live Docs

Last updated: December 5th, 20182018-12-05Project preview

CoinAPI.io offers a free tier that consists in 100 daily requests. There are multiple endpoints and the docs are great (check them out).


This is an interactive demo, you can make a copy of this project and work on it interactively with the button on the right šŸ‘‰


Let's get started! First a couple of imports we need:

InĀ [6]:
import os
import requests
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

%matplotlib inline

API AuthenticationĀ¶

Before we begin, you MUST get a free API key from CoinAPI: https://www.coinapi.io/pricing?apikey. After getting the API Key, you can set it as an environment variable (as I've done) or just replace it where it says 'YOUR-API-KEY'.

InĀ [7]:
API_KEY = os.environ.get('COINAPI_KEY', 'YOUR-API-KEY')
InĀ [8]:
headers = {
    'X-CoinAPI-Key': API_KEY
}

EndpointsĀ¶

CoinAPI offers multiple endpoints. Some with "Metadata", as a list of exchanges (bitstamp, bitfinex, etc):

ExchangesĀ¶
InĀ [11]:
resp = requests.get('https://rest.coinapi.io/v1/exchanges', headers=headers)
InĀ [12]:
resp
Out[12]:
<Response [200]>
InĀ [13]:
exchanges = resp.json()
InĀ [34]:
print(f"There are {len(exchanges)} exchanges")
There are 108 exchanges
InĀ [35]:
exchanges[:2]
Out[35]:
[{'exchange_id': 'OKCOIN_CNY',
  'website': 'https://www.okcoin.cn/',
  'name': 'OKCoin CNY',
  'data_start': '2013-06-12',
  'data_end': '2018-03-09',
  'data_quote_start': '2015-02-15T12:53:50.3430000Z',
  'data_quote_end': '2018-03-09T00:00:00.0000000Z',
  'data_orderbook_start': '2015-02-15T12:53:50.3430000Z',
  'data_orderbook_end': '2018-03-09T00:00:00.0000000Z',
  'data_trade_start': '2013-06-12T14:24:24.0000000Z',
  'data_trade_end': '2017-11-01T00:00:00.0000000Z',
  'data_trade_count': 2085401174,
  'data_symbols_count': 2},
 {'exchange_id': 'HUOBI',
  'website': 'https://www.huobi.com/',
  'name': 'Huobi',
  'data_start': '2015-03-29',
  'data_end': '2018-03-09',
  'data_quote_start': '2015-03-29T21:46:06.2630000Z',
  'data_quote_end': '2018-03-09T00:00:00.0000000Z',
  'data_orderbook_start': '2015-03-29T21:46:06.2630000Z',
  'data_orderbook_end': '2018-03-09T00:00:00.0000000Z',
  'data_trade_start': '2015-03-29T21:46:08.7030000Z',
  'data_trade_end': '2018-03-09T00:00:00.0000000Z',
  'data_trade_count': 538686774,
  'data_symbols_count': 2}]
InĀ [36]:
[e for e in exchanges if 'bitstamp' in e['website']]
Out[36]:
[{'exchange_id': 'BITSTAMP',
  'website': 'https://www.bitstamp.net/',
  'name': 'Bitstamp Ltd.',
  'data_start': '2011-09-13',
  'data_end': '2018-11-30',
  'data_quote_start': '2014-02-24T17:43:05.0000000Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2014-02-24T17:43:05.0000000Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2011-09-13T13:53:36.0000000Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_count': 51653022,
  'data_symbols_count': 15}]
AssetsĀ¶

Assets represent cryptocurrencies or fiat currencies. Example: Bitcoin, US Dollar, Euro, etc).

InĀ [15]:
resp = requests.get('https://rest.coinapi.io/v1/assets', headers=headers)
InĀ [16]:
resp
Out[16]:
<Response [200]>
InĀ [18]:
assets = resp.json()
InĀ [30]:
print(f"There are {len(assets)} assets")
There are 3712 assets
InĀ [38]:
assets[:3]
Out[38]:
[{'asset_id': 'BTC',
  'name': 'Bitcoin',
  'type_is_crypto': 1,
  'data_start': '2010-07-17',
  'data_end': '2018-11-30',
  'data_quote_start': '2014-02-24T17:43:05.0000000Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2014-02-24T17:43:05.0000000Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2010-07-17T23:09:17.0000000Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_count': 4190459268,
  'data_symbols_count': 11092},
 {'asset_id': 'CNY',
  'name': 'Yuan Renminbi',
  'type_is_crypto': 0,
  'data_start': '2011-06-13',
  'data_end': '2018-11-29',
  'data_quote_start': '2015-02-11T16:50:54.6130000Z',
  'data_quote_end': '2018-11-29T00:00:00.0000000Z',
  'data_orderbook_start': '2015-02-11T16:50:54.6130000Z',
  'data_orderbook_end': '2018-11-29T00:00:00.0000000Z',
  'data_trade_start': '2011-06-13T05:13:24.0000000Z',
  'data_trade_end': '2018-09-07T00:00:00.0000000Z',
  'data_trade_count': 2814365939,
  'data_symbols_count': 177},
 {'asset_id': 'ETH',
  'name': 'Ethereum',
  'type_is_crypto': 1,
  'data_start': '2015-08-07',
  'data_end': '2018-11-30',
  'data_quote_start': '2015-08-07T14:50:38.1774950Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2015-08-07T14:50:38.1774950Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2015-08-07T15:21:48.1062520Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_count': 519490265,
  'data_symbols_count': 5030}]

'USD' asset:

InĀ [22]:
[a for a in assets if a['asset_id'] == 'USD']
Out[22]:
[{'asset_id': 'USD',
  'name': 'US Dollar',
  'type_is_crypto': 0,
  'data_start': '2010-07-17',
  'data_end': '2018-11-30',
  'data_quote_start': '2014-02-24T17:43:05.0000000Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2014-02-24T17:43:05.0000000Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2010-07-17T23:09:17.0000000Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_count': 474168311,
  'data_symbols_count': 5604}]
SymbolsĀ¶

Symbols are a little bit more difficult to understand if you don't use derivatives like futures or options. If that's the case, don't worry about it and just use SPOT. For example, the regular Bitcoin price you see on Bitstamp is: BITSTAMP_SPOT_BTC_USD. As you can see, the symbol fully qualifies the asset, the exchange and the conversion unit. For BITSTAMP_SPOT_BTC_USD it's "spot price of Bitcoin on Bitstamp expressed in US Dollars.

InĀ [23]:
resp = requests.get(
    'https://rest.coinapi.io/v1/symbols',
    params={
        'filter_symbol_id': 'btc'
    },
    headers=headers)
InĀ [24]:
resp
Out[24]:
<Response [200]>
InĀ [26]:
symbols = resp.json()
InĀ [32]:
print(f"There are {len(symbols)} symbols containing 'btc'.")
There are 12037 symbols containing 'btc'.

Example of symbols:

InĀ [33]:
symbols[:2]
Out[33]:
[{'symbol_id': 'BITMEX_FTS_BTC_USD_181228',
  'exchange_id': 'BITMEX',
  'symbol_type': 'FUTURES',
  'asset_id_base': 'BTC',
  'asset_id_quote': 'USD',
  'future_delivery_time': '2018-12-28T12:00:00.0000000Z',
  'data_start': '2018-07-02',
  'data_end': '2018-11-30',
  'data_quote_start': '2018-07-02T01:17:16.2902120Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2018-07-02T01:17:16.2902120Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2018-07-02T01:22:36.1275970Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'volume_1hrs': 7435285.0,
  'volume_1hrs_usd': 29525681762.14,
  'volume_1day': 95484189.0,
  'volume_1day_usd': 379169833803.24,
  'volume_1mth': 4961183550.0,
  'volume_1mth_usd': 19700969991176.7},
 {'symbol_id': 'BITMEX_FTS_BTC_USD_190329',
  'exchange_id': 'BITMEX',
  'symbol_type': 'FUTURES',
  'asset_id_base': 'BTC',
  'asset_id_quote': 'USD',
  'future_delivery_time': '2019-03-29T12:00:00.0000000Z',
  'data_start': '2018-09-17',
  'data_end': '2018-11-30',
  'data_quote_start': '2018-09-17T03:24:14.5348710Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2018-09-17T03:24:14.5348710Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2018-09-17T03:27:44.0626620Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'volume_1hrs': 3841728.0,
  'volume_1hrs_usd': 15255587155.66,
  'volume_1day': 65513912.0,
  'volume_1day_usd': 260157198641.96,
  'volume_1mth': 2375276963.0,
  'volume_1mth_usd': 9432277539660.13}]

Symbol for BTC-USD on Bitstamp:

InĀ [40]:
[s for s in symbols if s['exchange_id'] == 'BITSTAMP' and s['asset_id_quote'] == 'USD']
Out[40]:
[{'symbol_id': 'BITSTAMP_SPOT_BTC_USD',
  'exchange_id': 'BITSTAMP',
  'symbol_type': 'SPOT',
  'asset_id_base': 'BTC',
  'asset_id_quote': 'USD',
  'data_start': '2011-09-13',
  'data_end': '2018-11-30',
  'data_quote_start': '2014-02-24T17:43:05.0000000Z',
  'data_quote_end': '2018-11-30T00:00:00.0000000Z',
  'data_orderbook_start': '2014-02-24T17:43:05.0000000Z',
  'data_orderbook_end': '2018-11-30T00:00:00.0000000Z',
  'data_trade_start': '2011-09-13T13:53:36.0000000Z',
  'data_trade_end': '2018-11-30T00:00:00.0000000Z',
  'volume_1hrs': 902.03969623,
  'volume_1hrs_usd': 3582019.65,
  'volume_1day': 15971.662045071,
  'volume_1day_usd': 63423824.47,
  'volume_1mth': 345345.117390795,
  'volume_1mth_usd': 1371373126.14}]

Exchange RatesĀ¶

Exchange rates just give you simplified price quotes for a pair of assets. For example, Bitcoin / US Dollar:

InĀ [41]:
resp = requests.get(
    'https://rest.coinapi.io/v1/exchangerate/BTC/USD',
    headers=headers)
InĀ [42]:
resp
Out[42]:
<Response [200]>
InĀ [43]:
resp.json()
Out[43]:
{'time': '2018-11-30T14:22:53.6235790Z',
 'asset_id_base': 'BTC',
 'asset_id_quote': 'USD',
 'rate': 3967.2526293857827}

OHLCV (Open High Low Close Volume)Ā¶

This is usually the most useful endpoint, the one returning the prices (and volumes) of the cryptocurrencies. To use it you must specify the symbol and a "period of time" (1 minute, 5 minutes, 1 hour, 1 day, etc).

InĀ [45]:
symbol_id = 'BITSTAMP_SPOT_BTC_USD'
period_id = '1MIN'
limit = '100'
InĀ [46]:
resp = requests.get(
    f'https://rest.coinapi.io/v1/ohlcv/{symbol_id}/latest?period_id={period_id}&limit={limit}',
    headers=headers)

The result by default is JSON, we can create a pandas DataFrame with the results:

InĀ [58]:
data = pd.read_json(resp.text, orient='records', dtype={
    'time_close': np.datetime64,
    'time_open': np.datetime64,
    'time_period_end': np.datetime64,
    'time_period_start': np.datetime64,
})
InĀ [59]:
data.head()
Out[59]:
price_close price_high price_low price_open time_close time_open time_period_end time_period_start trades_count volume_traded
0 3968.21 3969.65 3968.21 3969.65 2018-11-30 14:34:20 2018-11-30 14:34:05 2018-11-30 14:35:00 2018-11-30 14:34:00 3 0.728143
1 3970.85 3974.29 3970.85 3974.29 2018-11-30 14:33:46 2018-11-30 14:33:01 2018-11-30 14:34:00 2018-11-30 14:33:00 13 1.723623
2 3974.29 3974.29 3971.03 3971.03 2018-11-30 14:32:33 2018-11-30 14:32:02 2018-11-30 14:33:00 2018-11-30 14:32:00 6 0.757827
3 3972.57 3973.61 3966.15 3973.61 2018-11-30 14:31:57 2018-11-30 14:31:12 2018-11-30 14:32:00 2018-11-30 14:31:00 24 7.384487
4 3975.71 3983.47 3975.71 3983.47 2018-11-30 14:30:51 2018-11-30 14:30:01 2018-11-30 14:31:00 2018-11-30 14:30:00 6 8.247007
InĀ [60]:
data.set_index('time_period_start', inplace=True)
InĀ [63]:
data['price_close'].plot(figsize=(14, 7))
Out[63]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7753ce8b00>

CSV OutputĀ¶

Optionally, CoinAPI supports a CSV as output format, that might be more convenient to create DataFrames and to dump info to files. Same example as before using CSV:

InĀ [65]:
symbol_id = 'BITSTAMP_SPOT_BTC_USD'
period_id = '1MIN'
limit = '100'
InĀ [72]:
resp = requests.get(
    f'https://rest.coinapi.io/v1/ohlcv/{symbol_id}/latest?period_id={period_id}&limit={limit}',
    params={'output_format': 'csv'},
    headers=headers)
InĀ [89]:
# Needed to do the proper "read_csv"
from io import StringIO
InĀ [79]:
data = pd.read_csv(
    StringIO(resp.text), sep=';',
    parse_dates=['time_close', 'time_open', 'time_period_end', 'time_period_start'])
InĀ [80]:
data.head()
Out[80]:
time_period_start time_period_end time_open time_close price_open price_high price_low price_close volume_traded trades_count
0 2018-11-30 14:42:00 2018-11-30 14:43:00 2018-11-30 14:42:00 2018-11-30 14:42:24 3972.61 3972.62 3969.44 3969.44 0.363738 4
1 2018-11-30 14:41:00 2018-11-30 14:42:00 2018-11-30 14:41:04 2018-11-30 14:41:45 3965.50 3970.41 3962.93 3970.41 1.053105 9
2 2018-11-30 14:40:00 2018-11-30 14:41:00 2018-11-30 14:40:03 2018-11-30 14:40:58 3964.62 3964.90 3960.00 3964.90 9.863871 14
3 2018-11-30 14:39:00 2018-11-30 14:40:00 2018-11-30 14:39:00 2018-11-30 14:39:56 3967.08 3968.97 3963.93 3967.21 7.373984 10
4 2018-11-30 14:38:00 2018-11-30 14:39:00 2018-11-30 14:38:06 2018-11-30 14:38:53 3971.75 3973.45 3963.35 3963.35 6.729236 26
InĀ [81]:
data.set_index('time_period_start', inplace=True)
InĀ [82]:
data['price_close'].plot(figsize=(14, 7))
Out[82]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7753bec4e0>

Subscription infoĀ¶

You can also check the number of requests that you've made so far with the subscription/usage endpoint.

InĀ [9]:
resp = requests.get(
    'https://rest.coinapi.io/v1/subscription/usage/rest/history',
    headers=headers)
InĀ [10]:
resp.json()
Out[10]:
[{'date': '2018-11-30', 'requests': 6}]

Wrapping upĀ¶

There are a few more endpoints to investigate (trades, quotes and order book) which behave similarly to the other ones specified before.

Notebooks AI
Notebooks AI Profile20060