Blogs

Creating Coin Market Cap Based Portfolios

In this example I will show the code at once instead of breaking down to parts. This is partly due to its incompleteness. 

The program creates 4 equal weighted (assumes theoretically constant rebalancing) portfolios. 4 portfolios are large, mid, small and micro cap coins. Marketcaps are based on the most recent day's value (yes, it is data snooping). 

Data sources are CoinMarketCap for marketcap data and Binance for historical prices. 

Here's the code:

import requests
import json
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats

binance_data = json.loads(requests.get('https://api.binance.com/api/v3/ticker/24hr').text)
binance_symbols = [_['symbol'] for _ in binance_data]

session = requests.Session()
session.headers.update({'Accepts': 'application/json', 'X-CMC_PRO_API_KEY': 'd3ec12e9-0065-4099-8f66-36492e71ba60',})
data = json.loads(session.get('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=600&market_cap_min=50000000').text)
symbols = [_['symbol'] for _ in data['data']]
marketcaps = [data['data'][idx]['quote']['USD']['market_cap'] for idx in range(len(data['data']))]

df = pd.DataFrame([symbols, marketcaps]).T
df.columns = ['symbol','marketcap']
df['marketcap (M)'] = df['marketcap']/(10**6)
df = df.sort_values(by='marketcap (M)', ascending=False).drop('marketcap',axis=1)
df.symbol += 'USDT' # to mach binance symbols

df = df[[_ in binance_symbols for _ in df.symbol]].reset_index(drop=True) # selected common coins between two APIs

largecap_symbols = df[df['marketcap (M)'] > 10000]['symbol'].values
midcap_symbols = df[(df['marketcap (M)'] > 2000) & (df['marketcap (M)'] < 10000)]['symbol'].values
smallcap_symbols = df[(df['marketcap (M)'] > 300) & (df['marketcap (M)'] < 2000)]['symbol'].values
microcap_symbols = df[(df['marketcap (M)'] > 50) & (df['marketcap (M)'] < 300)]['symbol'].values

all_coins, interval, limit = [], '1d', 90
for symbol in df.symbol:
    coin = json.loads(requests.get(f'https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}').text)
    all_coins.append([float(_[4]) for _ in coin])

coins = pd.DataFrame(all_coins).T
coins.columns = df.symbol
#drop exceptions (coins.max().sort_values())
coins.drop('LUNAUSDT',axis=1, inplace=True)
microcap_symbols = np.delete(microcap_symbols, 4)

allmarket = coins.pct_change().mean(axis=1)
largecap = coins[largecap_symbols].pct_change().mean(axis=1)
midcap = coins[midcap_symbols].pct_change().mean(axis=1)
smallcap = coins[smallcap_symbols].pct_change().mean(axis=1)
microcap = coins[microcap_symbols].pct_change().mean(axis=1)


# METRICS
def calculate_metrics(df):
    df.dropna(inplace=True)
    df_ret = df.mean()*252
    df_std = df.std()*np.sqrt(252)
    df_neg_std = df[df < 0].std()*np.sqrt(252)
    df_sharpe = df_ret/df_std
    sf_sortino = df_ret/df_neg_std
    df_cumret = (df+1).cumprod()
    df_peak = df_cumret.expanding(min_periods=1).max()
    df_maxdd = ((df_cumret/df_peak)-1).min()
    return [df_ret, df_sharpe, sf_sortino, df_maxdd]

def calculate_beta(df, market):
    corr = scipy.stats.pearsonr(market, df)
    beta = (df.std()*np.sqrt(252)) / (market.std()*np.sqrt(252)) * corr[0]
    return beta

portfolios = [allmarket, largecap,midcap,smallcap,microcap]
portfolios_df = pd.DataFrame([calculate_metrics(_) for _ in portfolios]).T
portfolios_df.columns = ['AllMarket','LargeCap', 'MidCap','SmallCap', 'MicroCap']
portfolios_df.index = ['Return','Sharpe','Sortino','Max DD']

betas = [calculate_beta(_, allmarket) for _ in portfolios]
portfolios_df.loc['Betas'] = betas


portfolios_df.plot(kind='bar', figsize=(10,6))
plt.title("Coin MarketCap Portfolios' Performance Metrics")
plt.show()

for i in range(len(portfolios)):
    (portfolios[i]+1).cumprod().plot(label=portfolios_df.columns[i], figsize=(10,6))
plt.title('Coin MarketCap Portfolios'' Cumilative Returns')
plt.legend()
plt.show()