In this article we will be calling API to get Bitcoin, Ethereum (or any cryptocurrency) historical price data. The API serves the data in JSON format and the actual useful payload is in an array of dictionaries. Turns out that Pandas library can easily convert these into the dataframe. Once the data is in dataframe, further processing is rather straightforward. Subsequently we will visualize the historical Bitcoin price data via matplotlib library.

This historical data can eventually be used for time series analysis, price alarming script or even for creation of simple trading bot.

Import libraries

In [168]:
import pandas as pd
import matplotlib.pyplot as plt
import requests
from datetime import datetime
# pretty printing of pandas dataframe
pd.set_option('expand_frame_repr', False)  

Call the API to get data

How to call the API:

The API call consists of two parts,
first is baseurl


and second are parameters that we provide for the call

  • fsym=BTC&tsyms=USD

We can serve the actual paramaters as a dictionary with requests.get() method. This is very convenient when we want to pass it multiple arguments.

Get current price data

We start first by implementing simpler case first, we will just get current price (optionally we can specify target currency - USD, EUR, JPY ...). This implementation can be used in the future to create for example simple price watchbot that would run from cron periodically.

In [169]:
def get_current_data(from_sym='BTC', to_sym='USD', exchange=''):
    url = ''    
    parameters = {'fsym': from_sym,
                  'tsyms': to_sym }
    if exchange:
        print('exchange: ', exchange)
        parameters['e'] = exchange
    # response comes as json
    response = requests.get(url, params=parameters)   
    data = response.json()
    return data   

Get Bitcoin/USD price data from Coinbase cryptocurrency exchange

In [170]:
exchange:  coinbase
{'USD': 8314.6}

Get historical price data

Our main focus will be on getting the historical price data for given cryptocurrency. Regarding the series of historical data, we can download daily, hourly and even minute historical data. There is a limit of 2000 time datapoints with each API call. Theoretically we can even write a script that would chain these calls together so we get minute data for all of the trading history. Another option is to choose aggreagation option with the call, this way we can aggregate hourly data for example to 6 hour blocks. This way each candle data will be 6 hour timeframe.

Examples of daily, hourly and minute calls:

We can se that it will be convenient to use baseurl

  • and then append to it day, hour or minute based on our needs.

The parameters will be again in a dictionary.

API call details

API call

results in following JSON payload:

Response: "Success"
Message: ""
HasWarning: false
Type: 100
 RateLimit: Object
 Data: Object
Aggregated: false
TimeFrom: 1577059200
TimeTo: 1577923200
 Data: Array [11]
 0: Object
time: 1577059200
high: 7694.65
low: 7275.28
open: 7517.58
volumefrom: 44770.93
volumeto: 336425000.06
close: 7326.6
conversionType: "direct"
conversionSymbol: ""

important are Data: Object and Data: Array [11]

The Data: Array [11] contains dictionaries.

To get to the dictionary payload, we will need to use data = response.json()['Data']['Data']

Alternative JSON response representation:


So we need to access the dictionaries and transform them into Pandas dataframe. Pandas makes this process simple.

Code implementation

Download the JSON via Cryptocompare API:

In [171]:
def get_hist_data(from_sym='BTC', to_sym='USD', timeframe = 'day', limit=2000, aggregation=1, exchange=''):
    url = ''
    url += timeframe
    parameters = {'fsym': from_sym,
                  'tsym': to_sym,
                  'limit': limit,
                  'aggregate': aggregation}
    if exchange:
        print('exchange: ', exchange)
        parameters['e'] = exchange    
    print('baseurl: ', baseurl) 
    print('timeframe: ', timeframe)
    print('parameters: ', parameters)
    # response comes as json
    response = requests.get(baseurl, params=parameters)   
    data = response.json()['Data']['Data'] 
    return data      

Transform JSON paylod into Pandas dataframe:

In [172]:
def data_to_dataframe(data):
    #data from json is in array of dictionaries
    df = pd.DataFrame.from_dict(data)
    # time is stored as an epoch, we need normal dates
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.set_index('time', inplace=True)
    return df

Plot the historical price data via matplotlib library:

In [173]:
def plot_data(df, cryptocurrency, target_currency):
    # got his warning because combining matplotlib 
    # and time in pandas converted from epoch to normal date
    # To register the converters:
    # 	>>> from pandas.plotting import register_matplotlib_converters
    # 	>>> register_matplotlib_converters()
    #  warnings.warn(msg, FutureWarning)
    from pandas.plotting import register_matplotlib_converters
    plt.title('{} / {} price data'.format(cryptocurrency, target_currency))
    plt.plot(df.index, df.close)
    return None

Finally, specify the cryptocurrency (in this case Bitcoin) and call the defined functions.

In [174]:
cryptocurrency = 'BTC'
target_currency = 'USD'

data = get_hist_data(cryptocurrency, target_currency, 'day', 1000)
df = data_to_dataframe(data)

plot_data(df, cryptocurrency, target_currency)
timeframe:  day
parameters:  {'fsym': 'BTC', 'tsym': 'USD', 'limit': 1000, 'aggregate': 1}
              close conversionSymbol conversionType     high      low     open  volumefrom      volumeto
2020-01-04  7357.50                          direct  7405.75  7278.60  7339.70    22083.57  1.621069e+08
2020-01-05  7359.96                          direct  7501.42  7330.07  7357.50    24084.13  1.791477e+08
2020-01-06  7762.69                          direct  7799.63  7355.11  7359.96    46443.66  3.522862e+08
2020-01-07  8160.36                          direct  8218.63  7736.57  7762.69    75423.75  6.000545e+08
2020-01-08  8314.27                          direct  8458.65  8154.92  8160.36    49640.75  4.135966e+08