Predictive Hacks

Cryptocurrency Portfolio Optimization in Python

efficient frontier

In this tutorial, we will show you how to build optimized portfolios in Python using the PyPortfolioOpt library. In another tutorial, we have shown you how to build diversified portfolios from scratch using Python. For this task, we will build the optimized portfolios based on the Efficient Frontier. We will build one portfolio that maximized the Sharpe Ratio and another that minimizes the volatility. The chart below shows the location of the portfolios that we mentioned above on the efficient frontier.

Image source

The flowchart below represents the different functionalities of the PyPorfolioOpt library.

Load the Required Libraries

For this tutorial, we will need to use some libraries. If you want to follow along with the reproducible examples, you should have installed these libraries. Let’s load them.

import pandas as pd
import requests
import time

from pypfopt import risk_models
from pypfopt.risk_models import CovarianceShrinkage
from pypfopt import expected_returns
from pypfopt.efficient_frontier import EfficientFrontier

Get the Data

We will consider the daily prices of the cryptocurrencies in USD ($) since “2020-01-01” which means 2 years and 4 months of data (today is: 2022-04-01). We will use the Kraken API and all the available cryptocurrencies. Note that we will remove any cryptocurrency that has missing data during this time period. We will keep the closing daily prices. Note that the date is in Unix timestamp.

# get the starting date in unix timestamp
date_time = '2020-01-01 00:00:00'
pattern = '%Y-%m-%d %H:%M:%S'
epoch = int(time.mktime(time.strptime(date_time, pattern)))

# get all the cryptocurrencies in USD

resp = requests.get('')

resp = resp.json()

# Keep all the cryptos over USD
dollar_pairs = []
for pair in resp['result']:
    if pair.endswith('USD'):

# get all the unixtimestamps
tmp_url = f'{epoch}&interval=1440'.format(epoch)
resp = requests.get(tmp_url)
dummy_df = pd.DataFrame(resp.json()['result']['XXBTZUSD'])[[0]]

# create a pandas data frame and add the closing prices of each asset
df = pd.DataFrame(index=dummy_df[0])

for pair in dollar_pairs:
    tmp_url = f'{pair}&since={epoch}&interval=1440'.format(pair,epoch)
    resp = requests.get(tmp_url)
    tmp_df = pd.DataFrame(resp.json()['result'][pair])[[0,4]]
    tmp_df.columns = ['unixtimestap', pair]
    tmp_df[pair] = tmp_df[pair].astype(float)
    df = pd.concat([df,tmp_df.set_index('unixtimestap')], axis=1)

# remove the last row since it is not a full day
df = df[:-1].copy()

# drop the columns with a least one NA
df.dropna(axis='columns', inplace=True)

# remove the other fiat currencies liker EURO and the stable coins like Tether and DAI
df.drop(columns=['USDCUSD', 'USDTZUSD', 'DAIUSD', 'ZGBPZUSD','ZEURZUSD', 'PAXGUSD'], axis=1, inplace=True)

We ended up with 29 cryptocurrencies of 720 daily closing prices.

Get the Efficient Frontier

For the efficient frontier, we will need to pass the expected returns mu and the variance-covariance matrix Sigma. There are many variations of the mu and Sigma respectively. For example, for mu we have the following options:

  • mean_historical_return
  • ema_historical_return
  • returns_from_prices

and for Sigma we have the following options:

  • sample_cov
  • semicovariance
  • exp_cov
  • ledoit_wolf
  • ledoit_wolf_constant_variance
  • ledoit_wolf_single_factor
  • ledoit_wolf_constant_correlation
  • oracle_approximating

In this case, we will work with the exponential mean and variance in order to give more weight to the most recent observations. Feel free to play with the other options too.

# calculate the mean and variance
mu = expected_returns.ema_historical_return(df, frequency=365)
Sigma = risk_models.exp_cov(df, frequency=365)

From the EMA returns, we can see that the Wave, the DogeCoin the Cosmos and the ETC have performed extremely well compared to the rest cryptocurrencies.

# get the efficient frontier
ef = EfficientFrontier(mu, Sigma)

Maximum Sharpe Ratio Portfolio

We can get the weights of the optimum portfolio in terms of Sharpe Ratio as follows. Note that we have set the risk-free interest rate to be 0. If you would like to set another value, you can pass it to the max_sharpe() function.

sharpe_weights = ef.max_sharpe()

The optimum portfolio that maximizes the Sharpe Ratio is to invest in Wave (70%) and in DogeCoin (30%). We can also get the performance of the portfolio.


Minimum Variance Portfolio

We can also get the weights of the portfolio that minimizes the risk and it is on the Efficient Frontier.

ef = EfficientFrontier(mu, Sigma)
min_vol_weights = ef.min_volatility()

According to our data, the weights of the lowest variance portfolio are 50% BTC, 35% TRX, 10% REP and 5% MLN.

The performance of this portfolio is:


The Takeaways

Our goal was to show you how to apply the Markowitz portfolio theory to cryptocurrencies using Python. Personally, I believe that we didn’t get reliable results because:

  • Many good cryptocurrencies were not included because we did not have 2.5 years data. Some examples are the DOT, AAVE, LUNA, AVAX and so on.
  • There are some alt-coins that can have extremely high returns and this affects our data

However, I believe that you can apply these techniques by taking into consideration a shorter time period and by focusing on specific cryptocurrencies.

Want some Free Cryptos?

You can get $25 in Bitcoin by investing $100 in Nexo

Share This Post

Share on facebook
Share on linkedin
Share on twitter
Share on email

Leave a Comment

Subscribe To Our Newsletter

Get updates and learn from the best

More To Explore


Image Captioning with HuggingFace

Image captioning with AI is a fascinating application of artificial intelligence (AI) that involves generating textual descriptions for images automatically.


Intro to Chatbots with HuggingFace

In this tutorial, we will show you how to use the Transformers library from HuggingFace to build chatbot pipelines. Let’s