<jupyter_start><jupyter_text>Capital Assets Pricing Model (CAPM) with Cryptocurrencies This is just out of curiosity and just for fun, i.e., **this is not financial advice**. Note that I learned most of the concepts used here from <NAME>'s videos in [Python for Financial Analysis and Algorithmic Trading](https://www.udemy.com/course/python-for-finance-and-trading-algorithms/) and <NAME>'s Coursera course [Financial Markets](https://www.coursera.org/learn/financial-markets-global).  CAPM in a nutshellThe return or our portfolio $r_p$ is the weighted sum of the returns of each asset in it $r_i$:$r_p(t) = \sum_{i}^{n} w_i r_i(t)$The return of each asset $r_i$ can be modelled as a linear regression of its value vs the market return $r_m$:$r_i(t) = \beta_i r_m(t) + \alpha_i$Then, the return of our portfolio is also modelled as a multivariate linear regression:$r_p(t) = \sum_{i}^{n} \beta_i r_m(t) + \sum_{i}^{n} w_i \alpha_i = \beta_p r_m(t) + \sum_{i}^{n} w_i \alpha_i$Here, the key values are $\alpha$ and $\beta$:- `beta` is the multiplication/scaling of the market return in our stock; low values indicate lower returns and lower risk (in general, low `betas` are preferable)- `alpha` is the intercept, i.e., the gains independent from the market behavior. **CAMPM states that `alpha` is random, cannot be predicted and should tend to ZERO; however, commonly that is not followed, instead, investors try to find assets with a high `alpha`! That is what hedge funds do, and apparently it works for them.** HedgingFinding higher `alpha` values means hedging against volatility: the assets with higher returns (with higher risks) are traded off for assets that will yield higher average returns with probably less jumps.Summary of ways of hedging against risk:- Assets with high `alpha` and low `beta`- A diversified portfolio  Alpha & Beta of BTC & ETH<jupyter_code>import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
from scipy import stats
# Load and prepare datasets
df_global = pd.read_csv('data/Global_Crypto_Marketcap_Statista_Monthly_Formated_2010_2021.csv',header=0)
df_global['Date'] = pd.to_datetime(df_global['Date'])
df_global.set_index('Date',inplace=True)
df_btc = pd.read_csv('data/Bitcoin_Marketcap_Statista_Monthly_Formated_2013_2021.csv',header=0)
df_btc['Date'] = pd.to_datetime(df_btc['Date'])
df_btc.set_index('Date',inplace=True)
df_eth = pd.read_csv('data/Ethereum_Marketcap_Statista_Monthly_Formated_2015_2021.csv',header=0)
df_eth['Date'] = pd.to_datetime(df_eth['Date'])
df_eth.set_index('Date',inplace=True)
# Compute maximum possible rane in the data we have
date_start = max(df_global.index[0], df_btc.index[0], df_eth.index[0])
date_end = min(df_global.index[-1], df_btc.index[-1], df_eth.index[-1])
print(date_start,date_end)
# Take daily close values
df = pd.DataFrame()
df["Global"] = df_global["Marketcap USD"].loc[date_start:date_end]
df["BTC"] = df_btc["Marketcap USD"].loc[date_start:date_end]
df["ETH"] = df_eth["Marketcap USD"].loc[date_start:date_end]
df.head()
df.shape
# Monthly return
df["Global Return"] = df["Global"].pct_change(1)
df["BTC Return"] = df["BTC"].pct_change(1)
df["ETH Return"] = df["ETH"].pct_change(1)
# Compute alpha and beta values with linear regression
result_btc = stats.linregress(x=df['Global Return'].iloc[1:],y=df['BTC Return'].iloc[1:])
# Unpack the result values
# Slope: beta
# Intercept: alpha
beta_btc,alpha_btc,r_value_btc,p_value_btc,std_err_btc = result_btc
# Alpha
# According to CAPM, alpha -> 0
# We see it is not really 0, but it has some residual value
# Even small alpha values can mean a difference:
# that is the return offset we have wrt market
# Beta
# Every market move is scaled with beta to yield our stock moves
print(alpha_btc,beta_btc)
print(r_value_btc,p_value_btc)
# Compute alpha and beta values with linear regression
result_eth = stats.linregress(x=df['Global Return'].iloc[1:],y=df['ETH Return'].iloc[1:])
# Unpack the result values
beta_eth,alpha_eth,r_value_eth,p_value_eth,std_err_eth = result_eth
print(alpha_eth,beta_eth)
print(r_value_eth,p_value_eth)<jupyter_output>0.5734834443939182 7.538385988074451e-08<jupyter_text>Plots<jupyter_code># Plot monthly return: SCATTERPLOT + Regression lines
plt.figure(figsize=(7,7))
# Modelled lines
min_global = df["Global Return"].dropna().values.min()
max_global = df["Global Return"].dropna().values.max()
global_line = np.linspace(min_global,max_global,100)
y_btc = global_line*beta_btc + alpha_btc
y_eth = global_line*beta_eth + alpha_eth
# Plots
plt.scatter(df["Global Return"],df["BTC Return"],alpha=0.25,c='b',s=30)
plt.scatter(df["Global Return"],df["ETH Return"],alpha=0.25,c='r',s=30)
plt.plot(global_line,y_btc,c='blue')
plt.plot(global_line,y_eth,c='red')
plt.xlabel('Global market crypto')
plt.ylabel('BTC & ETH')
plt.legend(['BTC','ETH','BTC','ETH'])
plt.title('Monthly Returns')
plt.show()<jupyter_output><empty_output><jupyter_text>We can compute the **hedged return** of an asset = its return minus the modelled beta part applied to the market values.The hedged return is expected to be less bumpy.<jupyter_code># Hedged BC & ETH returns
df["BTC Return Hedged"] = df["BTC Return"] - df["Global Return"]*beta_btc
df["ETH Return Hedged"] = df["ETH Return"] - df["Global Return"]*beta_eth
# Plot monthly return: time series with and without beta
plt.figure(figsize=(16,6))
# Modelled lines
min_global = df["Global Return"].dropna().values.min()
max_global = df["Global Return"].dropna().values.max()
global_line = np.linspace(min_global,max_global,100)
y_btc = global_line*beta_btc + alpha_btc
y_eth = global_line*beta_eth + alpha_eth
# Plots
plt.plot(df["Global Return"],c='green')
plt.plot(df["BTC Return"],c='red')
plt.plot(df["ETH Return"],c='blue')
plt.plot(df["BTC Return Hedged"],'r--',alpha=0.5)
plt.plot(df["ETH Return Hedged"],'b--',alpha=0.5)
plt.title('Monthly returns')
plt.ylabel('Return')
plt.legend(['Global','BTC','ETH','BTC hedged','ETH hedged'])
plt.show()
# Histogram of BTC returns: regular vs hedged
df["BTC Return"].hist(bins=50,figsize=(6,6),alpha=0.5)
df["BTC Return Hedged"].hist(bins=50,figsize=(6,6),alpha=0.5)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13823243768209775, 'fraction_numerical': 0.018452573648429914, 'mean_word_length': 6.7334167709637045, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '592561', 'license': 'MIT', 'n_tokens_mistral': 2268, 'n_tokens_neox': 2134, 'n_words': 584, 'path': '03_CryptoCAPM.ipynb', 'repo_name': 'mxagar/crypto_analysis', 'size': '6193'}