Skip to main content

Python API Client Walkthrough

Python API Client Walkthrough​

Last Updated: Version 2024.08.20

This notebook demonstrates basic functionality offered by the Coin Metrics Python API Client using Coin Metrics Community Data.

Coin Metrics offers a vast assortment of data for hundreds of cryptoassets. The Python API Client allows for easy access to this data using Python without needing to create your own wrappers using requests and other such libraries.

Prerequisites​

First, Python must be installed. Download and install from python.org. The Coin Metrics API Client is best used with Python 3.8 or later.

Then, install the Python API Client:

pip install coinmetrics-api-client

Some of the optional libraries such as pandas, numpy, and seaborn are used in the notebook to make the examples more interactive. These libraries are not required to use the Coin Metrics API Client.

You are now ready to run the code in the rest of the notebook.

Resources​

To understand the data that Coin Metrics offers, feel free to peruse the resources below.

Setup​

from os import environ
import sys
import pandas as pd
import numpy as np
import seaborn as sns
import logging
from datetime import date, datetime, timedelta
from coinmetrics.api_client import CoinMetricsClient

import matplotlib.pyplot as plt
# %matplotlib inline
logging.basicConfig(
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S'
)
# We recommend privately storing your API key in your local environment.
# Uncomment below if you have an API Key. Otherwise we will use Community data.
# try:
# api_key = environ["CM_API_KEY"]
# logging.info("Using API key found in environment")
# except KeyError:
# api_key = ""
# logging.info("API key not found. Using community client")

client = CoinMetricsClient()
# client = CoinMetricsClient(api_key)
assets = ['btc', 'eth']
metrics = ['ReferenceRateUSD', 'CapMrktEstUSD']
start_time = datetime(year=2024, month=9, day=1)
end_time = datetime(year=2024, month=9, day=30)
asset_mapping = {i: assets[i] for i in range(len(assets))}
{0: 'btc', 1: 'eth'}

Catalogs​

The Coin Metrics API contains two types of catalog endpoints (Python client functions in paranthesis): the catalog (catalog_*_v2) and catalog-all (catalog_full_*_v2).

The catalog endpoint displays the set of data available to your API key. The catalog-all endpoint displays the full set of data for our dataset.

asset_metrics_catalog = client.catalog_asset_metrics_v2(assets=assets).to_list()
full_asset_metrics_catalog = client.catalog_full_asset_metrics_v2(assets=assets).to_list()

Catalog objects return a list of dictionaries. For catalog_asset_metrics_v2, each element of the list is an asset, while each dictionary is a set of metadata for that specific asset.

print(f"Asset Metrics Catalog metadata includes: {list(asset_metrics_catalog[0].keys())}")

for i in asset_mapping:
print(f"Asset {asset_mapping[i]} has {len(asset_metrics_catalog[i]['metrics'])} metrics in catalog.")
print(f"Asset {asset_mapping[i]} has {len(full_asset_metrics_catalog[i]['metrics'])} metrics in catalog-all.")
Asset Metrics Catalog metadata includes: ['asset', 'metrics']
Asset btc has 147 metrics in catalog.
Asset btc has 696 metrics in catalog-all.
Asset eth has 146 metrics in catalog.
Asset eth has 699 metrics in catalog-all.
Asset Metrics Catalog metadata includes: ['asset', 'metrics']
Asset btc has 147 metrics in catalog.
Asset btc has 513 metrics in catalog-all.
Asset eth has 146 metrics in catalog.
Asset eth has 500 metrics in catalog-all.

For more details on what metrics are covered, see Coverage

Getting Timeseries Data​

Next, we will pull timeseries data. Typically there are two types of timeseries data that you can pull: raw observations such as trades and aggregated metrics. We will explore these two below.

Asset Metrics​

First, we will use the asset-metrics endpoint to get metrics for BTC and ETH.

btc_metrics = [m['metric'] for m in asset_metrics_catalog[0]['metrics']]
eth_metrics = [m['metric'] for m in asset_metrics_catalog[1]['metrics']]

You can bound your query by time like below:

df_asset_metrics = client.get_asset_metrics(
assets=assets,
metrics=metrics,
start_time=start_time,
end_time=end_time
).to_dataframe()
df_asset_metrics.head()
assettimeCapMrktEstUSDReferenceRateUSD
0btc2024-09-01 00:00:00+00:001132518348250.18627958959.926273
1btc2024-09-02 00:00:00+00:001168286956855.85253957349.080718
2btc2024-09-03 00:00:00+00:001138274882375.74487359159.023888
3btc2024-09-04 00:00:00+00:001146114653782.87841857637.775444
4btc2024-09-05 00:00:00+00:001108213762229.15283258033.39897
assettimeCapMrktEstUSDReferenceRateUSD
0btc2024-08-15 00:00:00+00:001137894996787.0524958840.64668
1btc2024-08-16 00:00:00+00:001163252605521.22778357644.187688
2btc2024-08-17 00:00:00+00:001172900035803.55078158927.276509
3btc2024-08-18 00:00:00+00:001160659435495.43481459414.674335
4btc2024-08-19 00:00:00+00:001172894781992.73388758793.206146
df_asset_metrics.loc[df_asset_metrics.asset=='btc'].plot(x='time', y='ReferenceRateUSD')

Coin Metrics supports several metrics for various data types such as exchanges, markets, and asset-pairs.

You can also bound your queries by using the limit parameter.

df_asset_metrics_limit = client.get_asset_metrics(
assets=assets,
metrics=btc_metrics[:5],
start_time=start_time,
end_time=end_time,
limit_per_asset=2
).to_dataframe()
df_asset_metrics_limit
assettimeAdrActCntAdrBal1in100KCntAdrBal1in100MCntAdrBal1in10BCntAdrBal1in10KCnt
0btc2024-09-01 00:00:00+00:006607709283304658720365534973
1btc2024-09-02 00:00:00+00:007176739284304690420359814972
2eth2024-09-01 00:00:00+00:0054861169071836310279961841221
3eth2024-09-02 00:00:00+00:0048835469021836617280083691218
assettimeAdrActCntAdrBal1in100KCntAdrBal1in100MCntAdrBal1in10BCntAdrBal1in10KCnt
0btc2024-08-15 00:00:00+00:007156329229305472420292616973
1btc2024-08-16 00:00:00+00:007003359231305501020300505977
2eth2024-08-15 00:00:00+00:0060335368621837926279728121226
3eth2024-08-16 00:00:00+00:0054126368711837366279625071223

Market Observations​

The other common timeseries data type that you will encounter are individual observations.

First, we will need to familiarize ourselves with the market convention which we can find on faqs. You can see a full list of markets by using the reference-data endpoint.

df_coinbase_btc_markets = client.reference_data_markets(asset='btc', exchange='coinbase').to_dataframe()
df_coinbase_btc_markets.head()
marketexchangebasequotepairsymboltypesize_assetmargin_assetstrike...order_price_incrementorder_price_minorder_price_maxorder_size_minorder_taker_feeorder_maker_feemargin_trading_enabledexperimentalbase_nativequote_native
0coinbase-1inch-btc-spotcoinbase1inchbtc1inch-btc1INCH-BTCspot<NA><NA><NA>...0.00.0<NA>0.000016<NA><NA>False<NA><NA><NA>
1coinbase-aave-btc-spotcoinbaseaavebtcaave-btcAAVE-BTCspot<NA><NA><NA>...0.0000010.000001<NA>0.000016<NA><NA>False<NA><NA><NA>
2coinbase-ada-btc-spotcoinbaseadabtcada-btcADA-BTCspot<NA><NA><NA>...0.00.0<NA>0.000016<NA><NA>False<NA><NA><NA>
3coinbase-algo-btc-spotcoinbasealgobtcalgo-btcALGO-BTCspot<NA><NA><NA>...0.00.0<NA>0.000016<NA><NA>False<NA><NA><NA>
4coinbase-ankr-btc-spotcoinbaseankrbtcankr-btcANKR-BTCspot<NA><NA><NA>...0.00.0<NA>0.000016<NA><NA>False<NA><NA><NA>

5 rows × 39 columns

marketexchangebasequotepairsymboltypesize_assetmargin_assetstrike...order_amount_minorder_amount_maxorder_price_incrementorder_price_minorder_price_maxorder_size_minorder_taker_feeorder_maker_feemargin_trading_enabledexperimental
0coinbase-1inch-btc-spotcoinbase1inchbtc1inch-btc1INCH-BTCspot<NA><NA><NA>...<NA><NA>0.00.0<NA>0.000016<NA><NA>False<NA>
1coinbase-aave-btc-spotcoinbaseaavebtcaave-btcAAVE-BTCspot<NA><NA><NA>...<NA><NA>0.0000010.000001<NA>0.000016<NA><NA>False<NA>
2coinbase-ada-btc-spotcoinbaseadabtcada-btcADA-BTCspot<NA><NA><NA>...<NA><NA>0.00.0<NA>0.000016<NA><NA>False<NA>
3coinbase-algo-btc-spotcoinbasealgobtcalgo-btcALGO-BTCspot<NA><NA><NA>...<NA><NA>0.00.0<NA>0.000016<NA><NA>False<NA>
4coinbase-ankr-btc-spotcoinbaseankrbtcankr-btcANKR-BTCspot<NA><NA><NA>...<NA><NA>0.00.0<NA>0.000016<NA><NA>False<NA>

5 rows × 37 columns

We can then pass these markets onto the timeseries/market-* endpoints. Below is an example of how to pull individual market trades.

df_coinbase_btc_trades = client.get_market_trades(
markets=["coinbase-btc-usd-spot"],
start_time=datetime.now()-timedelta(seconds=60),
end_time=datetime.now(),
).to_dataframe()
df_coinbase_btc_trades.head()
markettimecoin_metrics_idamountpricedatabase_timeside
0coinbase-btc-usd-spot2024-10-25 15:22:44.919441+00:007059668540.00000468353.272024-10-25 15:22:45.721609+00:00buy
1coinbase-btc-usd-spot2024-10-25 15:22:44.919441+00:007059668550.00001268353.272024-10-25 15:22:45.721609+00:00buy
2coinbase-btc-usd-spot2024-10-25 15:22:44.919441+00:007059668560.00218768354.372024-10-25 15:22:45.721609+00:00buy
3coinbase-btc-usd-spot2024-10-25 15:22:44.919441+00:007059668570.00252368354.382024-10-25 15:22:45.721609+00:00buy
4coinbase-btc-usd-spot2024-10-25 15:22:45.078614+00:007059668580.00104368353.272024-10-25 15:22:45.721609+00:00buy
markettimecoin_metrics_idamountpricedatabase_timeside
0coinbase-btc-usd-spot2024-09-13 16:55:02.663733+00:006916984410.00859491.62024-09-13 16:55:03.253369+00:00sell
1coinbase-btc-usd-spot2024-09-13 16:55:02.670644+00:006916984420.00859491.612024-09-13 16:55:03.253369+00:00buy
2coinbase-btc-usd-spot2024-09-13 16:55:03.057923+00:006916984430.00118659491.612024-09-13 16:55:03.771512+00:00buy
3coinbase-btc-usd-spot2024-09-13 16:55:03.143752+00:006916984440.1574259491.62024-09-13 16:55:03.771512+00:00sell
4coinbase-btc-usd-spot2024-09-13 16:55:03.143816+00:006916984450.07628159491.62024-09-13 16:55:03.771512+00:00sell

Examples from State of the Network​

The Python API Client is often used for transforming data for State of the Network. Below are some examples of data transformations done to produce the data visualizations.

Example 1: Get returns by coin in the CM reference rates universe over the last 10-years

In State of the Network #128, we looked at the returns for each asset dating back the last 10 years.

returns-10-yr

We can generate this data by weaving in the catalog_asset_metrics_v2 and get_asset_metrics endpoint. The code snippets below demonstrate how to do this with a small list of assets.


# Get all assets that have a reference rate
assets_refrate = client.catalog_asset_metrics_v2(metrics="ReferenceRateUSD")
# Get list of assets with daily ref rate
# uncomment the top line to look at *every* asset with reference rates
# asset_with_ref_rates = assets_refrate[0]["frequencies"][0]["assets"]
asset_with_ref_rates = ['btc', 'eth', 'bnb', 'ada', 'doge', 'xrp']
#Query API for prices, daily CM reference rates as dataframe
metrics = "ReferenceRateUSD"
frequency = "1d"

logging.info("Getting prices...")
df_prices = client.get_asset_metrics(
assets=asset_with_ref_rates,
metrics=metrics,
frequency=frequency,
start_time=start_time,
end_time=end_time
).to_dataframe()
# Assign datatypes
df_prices["time"] = pd.to_datetime(df_prices.time)
df_prices["ReferenceRateUSD"] = df_prices.ReferenceRateUSD.astype(float)

# Reshape dataset so assets are in columns, dates are the rows, and the values are prices
df_prices_pivot = df_prices.pivot(
index="time",
columns="asset",
values="ReferenceRateUSD"
)

# Index each asset's time series to 1
for col in df_prices_pivot.columns:
logging.info(f"Calculating Reference rate for {col}....")
# First price in time series
first_price = df_prices_pivot[df_prices_pivot[col].notnull()][col].iloc[0]
# Index time series
df_prices_pivot[col] = df_prices_pivot[col]/first_price
# Fill forward for Null values
df_prices_pivot[col] = df_prices_pivot[col].ffill()
2024-10-25 15:23:44 INFO Getting prices...
2024-10-25 15:23:45 INFO Calculating Reference rate for ada....
2024-10-25 15:23:45 INFO Calculating Reference rate for bnb....
2024-10-25 15:23:45 INFO Calculating Reference rate for btc....
2024-10-25 15:23:45 INFO Calculating Reference rate for doge....
2024-10-25 15:23:45 INFO Calculating Reference rate for eth....
2024-10-25 15:23:45 INFO Calculating Reference rate for xrp....
2024-09-13 16:56:10 INFO Getting prices...
2024-09-13 16:56:11 INFO Calculating Reference rate for ada....
2024-09-13 16:56:11 INFO Calculating Reference rate for bnb....
2024-09-13 16:56:11 INFO Calculating Reference rate for btc....
2024-09-13 16:56:11 INFO Calculating Reference rate for doge....
2024-09-13 16:56:11 INFO Calculating Reference rate for eth....
2024-09-13 16:56:11 INFO Calculating Reference rate for xrp....
df_prices_pivot.tail()
assetadabnbbtcdogeethxrp
time
2024-09-26 00:00:00+00:001.1021371.1006171.0695341.0703471.0244271.030510
2024-09-27 00:00:00+00:001.1622041.1185401.1034241.1640251.0462761.042040
2024-09-28 00:00:00+00:001.1657241.1417721.1154651.2224461.0735261.040046
2024-09-29 00:00:00+00:001.1586671.1276931.1155121.2671281.0641761.084632
2024-09-30 00:00:00+00:001.1514771.1191181.1129211.2327891.0568561.133519
assetadabnbbtcdogeethxrp
time
2024-09-09 00:00:00+00:001.0088260.9601970.9323360.9360400.8624890.930312
2024-09-10 00:00:00+00:001.0247440.9907480.9710261.0118670.8857290.948722
2024-09-11 00:00:00+00:001.0242880.9882990.9800111.0013510.8960310.950876
2024-09-12 00:00:00+00:001.0518651.0110610.9756720.9877340.8783280.940610
2024-09-13 00:00:00+00:001.0619011.0369810.9878311.0018740.8858370.987858

Example 2: Get daily spot trading volume on Coinbase for USDC markets​

In State of the Network #126, we looked at spot volume on trusted exchanges over time.

vol-over-time

We can replicate similar data behind chart using just coinbase spot markets at 2021. Here, we derive volume from our get_market_candles endpoint.

candles_coinbase = client.get_market_candles(
markets="coinbase-*-usdc-spot", # wildcards can be passed to get all asset pairs
start_time="2024-01-01",
end_time="2024-09-30",
frequency="1d"
).to_dataframe()
candles_coinbase["candle_usd_volume"] = candles_coinbase.candle_usd_volume.astype(float)
candles_coinbase["time"] = pd.to_datetime(candles_coinbase.time)
2024-10-25 15:23:45 INFO Sleeping for a rate limit window because 429 (too many requests) error was returned. Pleasesee Coin Metrics APIV4 documentation for more information: https://docs.coinmetrics.io/api/v4/#tag/Rate-limits
candles_coinbase.head()
markettimeprice_openprice_closeprice_highprice_lowvwapvolumecandle_usd_volumecandle_trades_count
0coinbase-eurc-usdc-spot2024-08-23 00:00:00+00:001.1211.1191.1211.1181.120121997787.01.117636e+06140
1coinbase-eurc-usdc-spot2024-08-24 00:00:00+00:001.121.121.131.1191.1205471122215.01.257359e+06412
2coinbase-eurc-usdc-spot2024-08-25 00:00:00+00:001.1211.121.1321.1191.1214332796276.03.135467e+061727
3coinbase-eurc-usdc-spot2024-08-26 00:00:00+00:001.121.1181.1261.1161.1188831999004.02.236406e+06882
4coinbase-eurc-usdc-spot2024-08-27 00:00:00+00:001.1171.1191.1221.1161.1188491505368.01.684066e+061227
markettimeprice_openprice_closeprice_highprice_lowvwapvolumecandle_usd_volumecandle_trades_count
0coinbase-eurc-usdc-spot2024-08-23 00:00:00+00:001.1211.1191.1211.1181.120121997787.01.117636e+06140
1coinbase-eurc-usdc-spot2024-08-24 00:00:00+00:001.121.121.131.1191.1205471122215.01.257357e+06412
2coinbase-eurc-usdc-spot2024-08-25 00:00:00+00:001.1211.121.1321.1191.1214332796276.03.135472e+061727
3coinbase-eurc-usdc-spot2024-08-26 00:00:00+00:001.121.1181.1261.1161.1188831999004.02.236419e+06882
4coinbase-eurc-usdc-spot2024-08-27 00:00:00+00:001.1171.1191.1221.1161.1188491505368.01.684074e+061227

We can also break this down by month. Note that for this example, the volume numbers will look smaller because we are using fewer exchanges.

vol-by-month

month_order = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
]


candles_coinbase.groupby(
candles_coinbase.time.dt.month_name()
)[['candle_usd_volume']].sum().reindex(month_order).dropna()
candle_usd_volume
time
January4.401994e+08
February1.227417e+08
March2.522828e+08
April1.476761e+08
May2.575348e+08
June9.312749e+08
July1.331209e+09
August2.433962e+09
September1.849214e+09