How to get historical crypto prices

Make your own candlestick charts and get the data to find patterns on the prices of your favorite crypto!

S. Alexander Zaman
Coinmonks
Published in
11 min readJan 9, 2022

--

A friend of mine recently asked me about finding historical open, high, low, and close (OHLC) data for cryptocurrency pairs. I knew how to look up prices on CoinGecko, but I actually didn’t know how to collect historical data. For people looking to do some algorithmic analysis on cryptocurrency prices, or even just to maintain excel spreadsheets that would help them track their performance, this is useful information.

Surely, this data must be readily available!

What would the promise of decentralized, public blockchains be for if you couldn’t get something as simple as price history freely and easily!

With a bit of research, I was able to figure this out, and now I will show you how to do it as well.

Finding the API Provider

Photo by Compare Fibre on Unsplash

A chef creating a fresh, subtle entree knows that it all rests on picking high quality ingredients. Likewise, this job relies on finding a perfect API to provide the information we need so we can whip together a script to process it.

Let’s try CoinGecko

First thing, I did was check CoinGecko. Their website is the main source I use to track price performance on my crypto portfolio, and I knew they had an API. Perhaps, they had a way to get high/low/open/close price information.

You can find the Coingecko API documentation here. They labelled themselves as “ The Most Comprehensive Cryptocurrency API” AND they had a free plan for me to play around with so I was excited by this lead!

https://www.coingecko.com/en/api

I eagerly clicked ‘Explore Docs’ and looked for the data I needed.

Indeed, they had all sorts of interesting data, and I encourage you to see what they have available. Maybe you’ll muster up some ideas for other interesting projects or analysis such using trend data to jump on momentum trades or finding new coins to explore based on category data!

When looking at price data however, I only saw current price data, and historical price data that could be pulled from a specific date.

request param only allows a specific date

Coingecko might have historical price data but there, is only 1 field for date. Getting a range of historical price data would have been very inefficient and cumbersome.

I needed to find a better option for historical Open, High, Low, Close (OHLC) price data.

[An aside on OHLC for cryptocurrencies]

Open, high, low, and close pricing is a bit of a weird concept if you think about it. For the regular stock market, they make plenty of sense because stock markets are localized to a location and they have market hours where trading starts and ends.

Cryptocurrency markets don’t have a location, nor do they have market hours.

The terms are not clear for crypto as they are for the stock market:

  • What does ‘Open’ or ‘Close’ mean when a market is always open?
  • What are the ‘High’ and ‘Low’ prices when price information is a continuous uninterrupted stream?

To continue, we have to make assumptions based on our needs. In my case, I didn’t care too much exactly when the start and end time was but I wanted to see data that roughly had a daily period and view OHLC performance across the span of many days.

Thus, the time for open and close doesn’t matter as long as they’re roughly 24 hours apart from the next open and close. Highs and lows, in turn, can be collected for each of these 24 hour-ish periods.

Finding a better source

I did some google searching for the data sources, and found this article which helped me find a few good lead. The site gives some good reviews, feel free to try different ones out. For my purposes though, I settled on the first option: Cryptowatch.

I chose Cryptowatch because it offered the following features:

  • It has a free-tier with a very generous daily limit for my needs
  • It has information from a wide range of exchanges and trading pairs
  • It had an ‘/ohlc’ api endpoint that did all the aggregation work for me

The endpoint we’re most interested in is the following:

https://docs.cryptowat.ch/rest-api/markets/ohlc

Note how the endpoint has parameters to select the pair, a date range, and even the size of periods.

This is exactly what we were looking for!

Time to get our hands dirty!

Photo by Max Duzij on Unsplash

Now that we have a good source, we need to create a script to fetch data.

Python has some handy tools to do this clearly and easily. Jupyter notebooks specifically allow you do this in a ‘trial-and-error’ way, and is great for playing around with the data. (This is one reason why python and Jupyter notebooks are a favorite tool for data scientists!)

Setup

Setting up your environment is beyond the scope of this article but you can find resources here:

  • Anaconda Setup : The Anaconda python distribution is probably the easiest way to install python and jupyter notebooks, especially if you have a PC. Refer to their installation documents to get set up
  • Requests: This a basic library used to get REST API requests. generally after your environment is set up you can just type pip install requests. The link has official documentation for installation and usage.

Once your environment is set up, create a jupyter notebook and start your script by importing requests.

import requests

Selecting a trading pair

To get the data we need we need to select an exchange and the trading pair we want on the exchange. The api has a wide variety of exchanges to choose from. To see the list you can query as per below:

# Fetch list of exchanges
resp = requests.get('https://api.cryptowat.ch/exchanges')

Make a separate jupyter cell to play around with the resp object to find the exchange name you’d like. e.g.,

# Get list of exchange values you can use
exchange_names = [e['symbol'] for e in resp.json()['result'] \
if e['active']]
exchange_names
### You should see a response similar to the following:
['coinone',
'uniswap-v2',
'ftx',
'coinbase-pro',
'gemini',
'binance',
...
]

You could theoretically pick anything from this list but we’re going to pick ‘gemini’ in our script.

After selecting the exchange, we can then see the list of trading pairs:

# Select Gemini
EXCHANGE = 'gemini'
# Fetch markets on the exchange
exchange_resp = requests.get(f'https://api.cryptowat.ch/markets/{EXCHANGE}')

In a separate cell, process the response

# See all the pairs in the marketpairs = [i['pair'] for i in exchange_resp.json()['result'] \
if i['active']]
pairs
### You should see a response similar to this
['btcusd',
'ethbtc',
'ethusd',
'zecusd',
'zecbtc',
'zeceth',
'ltcusd',
...
]

Let’s continue our script selecting the ‘ethusd’ pair (a.k.a. Ethereum vs US Dollar). We’ll set the parameter by adding the line PAIR = 'ethusd' in a new cell.

Note: It’s usually easier to figure out the pair you want in advance. e.g., if I know ethereum is ETH and US Dollars are (USD) so I can probably assume ETHUSD is the pairing

# you an verify that it is the correct pairing by checking here
PAIR = ‘ethusd’
# Verify Pair exists
pair_resp = requests.get(f’https://api.cryptowat.ch/pairs/{PAIR}')
pair_resp.json()### You should see a response similar to this
{'result': {'id': 125,
'symbol': 'ethusd',
'base': {'id': 77,
'symbol': 'eth',
'name': 'Ethereum',
'fiat': False,
'route': 'https://api.cryptowat.ch/assets/eth'},
'quote': {'id': 98,
'symbol': 'usd',
'name': 'United States Dollar',
'fiat': True,
'route': 'https://api.cryptowat.ch/assets/usd'},
'route': 'https://api.cryptowat.ch/pairs/ethusd',
'markets': [{'id': 672,
'exchange': 'zonda',
'pair': 'ethusd',
'active': True,
'route': 'https://api.cryptowat.ch/markets/zonda/ethusd'},
...
],
...
}

Selecting the date range

Besides the trading pair, we also have to select our date range. We also want to set the period to daily. Below I set a range of a month and the period of daily.

# Date Parameters
START_DATE = '12/8/2021'
END_DATE = '1/8/2022'
PERIOD = 86400 # Time period in seconds (e.g., 1 day = 86400)

If you pay close attention to the API, you’ll notice that you actually need to use timestamps (i.e., seconds since the beginning of Jan 1, 1970 UTC) instead of date strings. Luckily, we can convert it pretty easily in python using the built-in datetime library. Include the below in your script to make the conversion

# Convert the dates to timestamps
from datetime import datetime
def to_timestamp(dateString):
element = datetime.strptime(dateString, '%m/%d/%Y')
return int(datetime.timestamp(element))
# Will be used later to convert back
def to_date(timestamp):
dt = datetime.fromtimestamp(timestamp)
return dt.strftime('%m/%d/%Y')
start_ts = to_timestamp(START_DATE)
end_ts = to_timestamp(END_DATE)

Calling the API

Created on memegenerator.net

Now that we have all the parameters we need, it’s time to call the Cryptowatch API endpoint.

# Fetch the data
params = {
'after': start_ts,
'before': end_ts,
'periods': PERIOD,
}
ohlc_resp = requests.get(
f'https://api.cryptowat.ch/markets/{EXCHANGE}/{PAIR}/ohlc',
params=params)
ohlc_resp.json()['result'][f'{PERIOD}']

This call should give us a bunch of results in a list of tuples with the data we’re looking for.

Manipulating the data

Photo by Earl Wilcox on Unsplash

Now that we have the data, we can play around with it to manipulate, analyze, and present it. At this point, you can really do whatever you want with the data. To demonstrate this we’ll do the following:

  • Place the data into structured python objects and get a user-friendly printout
  • Create a candlestick chart

Printing read-friendly objects

The code below defines a class object, and how it will print out.

import json
import pprint as pp
class Ohlc():
def __init__(self, tuple):
(self.close_ts,
self.open,
self.high,
self.low,
self.close,
self.volume,
self.quote_volume) = tuple
self.close_dt = to_date(self.close_ts)
def __repr__(self):
return pp.pformat({
'close_dt': self.close_ts,
'price': {
'open': self.open,
'high': self.high,
'low': self.low,
'close': self.close,
},
})

The `__init__` function will take the tuple objects returned from the API call and put them into the class. The `__repr__` function determines the string representation of the object and will allow us to print the response in the way that we want it.

Now all we have to do is feed the data through the class and print the results. We can do this easily with a single list comprehension expression

ohlcs = [Ohlc(i) for i in ohlc_resp.json()['result'][f'{PERIOD}']]
ohlcs
### You should see a response similar to this
[{'close_dt': 1639008000,
'price': {'close': 4440.15, 'high': 4456.05, 'low': 4229.99, 'open': 4310.34}},
{'close_dt': 1639094400,
'price': {'close': 4106.69, 'high': 4490.84, 'low': 4077.15, 'open': 4441.35}},
{'close_dt': 1639180800,
'price': {'close': 3900.4, 'high': 4200, 'low': 3888.88, 'open': 4113.06}},
...
]

Creating a candlestick graph

Candlestick graphs are usually used in analyzing price performance of stocks. They are a concise way of representing open, close, high, and low data through thick bars for the open/close range and lines called ‘wicks’ for the high-low range.

You can search around for python plotting libraries to help you turn this data into candlestick graphs. Below we’ll collect the data into dataframes using a library called pandas. Then we’ll use the data frame to make the plot with a python library called cufflinks.

First we need to install the prerequisites:

In the command console you should be able to install it as follows:

python -m pip install --upgrade pip 
pip install pandas
pip install plotly

[See: Plotly - Getting started for troubleshooting info]

Note: if you’re using vscode, you might need the following for the plot to show up

import plotly.io as pio
pio.renderers.default = "vscode"

Next we’ll create the data frame with the following code:

# Convert timestamp to date object in each row
data = [tuple([datetime.fromtimestamp(i[0])] + i[1:]) \
for i in ohlc_resp.json()['result'][f'{PERIOD}']]
# Create dataframe
columns = ['date', 'open', 'high', 'low','close',\
'volume', 'qt_volume']
df = pandas.DataFrame.from_records(data, columns=columns)
df.tail()

You should see a result similar to the following:

Now we use plotly to turn this dataframe into a candlestick chart

qf = cufflinks.QuantFig(
df, title="", name='ETHUSD')
qf.iplot()

These few lines may take a bit of time but they’ll generate a wonderful plot as follows:

import plotly.graph_objects as gofig = go.Figure(data=[
go.Candlestick(x=df['date'],
open=df["open"],
high=df["high"],
low=df["low"],
close=df["close"])
])
fig.update_layout(
title=f"ETH/USD Candlesticks",
yaxis_title="ETH Price (USD)"
)

And, voilá! You now have a candlestick plot. Did I mention that it’s also interactive!

You can zoom in and out with the nav on the bottom of the plot

Go out and explore!

Above you learned how to do the following:

  • Find an appropriate API
  • Grab historical price data using python
  • Massage the data into objects and data frames
  • Plot the data into a candlestick chart

This process can be repeated with any API and you can manipulate the data any which way you want.

Now all that is left is to go out there and try things! Good luck!

Disclaimer:

I am not a financial advisor and views expressed in this article are not financial advice. Cryptocurrencies and smart contracts are complex instruments and come with high risk of losing money. You should carefully consider whether you understand how these instruments work and whether you can afford to take the high risk of losing your money. I encourage you to perform your own research before making any investment decision, and to avoid investing in any financial instrument which you do not fully understand how it works and what are the risks involved.

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also Read

--

--