Notebook
In [97]:
import numpy as np
import pandas as pd
import time
from quantopian.pipeline import Pipeline
import quantopian.pipeline.data as d
import quantopian.research as r
import quantopian.pipeline.factors as fac
import quantopian.pipeline.filters as f
import math
import alphalens as al
import matplotlib.pyplot as plt
import random

def ret(xs):
    return (1+xs).prod()**(1/len(xs))-1

def ra(xs):
    return (((1+xs).prod()**(1/len(xs)))**252-1)/(math.sqrt(252)*xs.std())

def unzip(xs):
    return tuple([list(tup) for tup in zip(*xs)])

def sim(xs, ys):
    x_a = random.random()
    x_b = 1 - x_a
    zs = x_b*ys + x_a*xs
    mu_a = ((1+xs).prod()**(1/len(xs)))-1
    mu_b = ((1+ys).prod()**(1/len(ys)))-1
    sigma_a = xs.std()
    sigma_b = ys.std()
    nret = (x_a*ret(xs)+x_b*ret(ys))
    nvol = math.sqrt(x_a**2*sigma_a**2 +x_b**2*sigma_b**2 + 2*x_a*x_b*xs.corr(ys)*sigma_a*sigma_b)
    anret = (1+nret)**252-1
    anvol = math.sqrt(252)*nvol
    return (anret, anvol, x_a, x_b, anret/anvol)
In [107]:
start = '2010-01-01'
end = '2020-07-01'
aname = 'spy'
bname = 'gld'
spy = 'a'
gld = 'b'
a = r.returns(symbols(aname), start, end)
b = r.returns(symbols(bname), start, end)
In [99]:
ys = [ sim(a, b) for x in range(0, 100)]
In [100]:
y, x, _, _, _ = unzip(ys)
In [101]:
ax = plt.scatter(x, y)
plt.xlabel("Annualized Volatility")
plt.ylabel("Annualized Return")
Out[101]:
<matplotlib.text.Text at 0x7f11df5f7e10>
In [102]:
df = pd.DataFrame()
df['b'] = b
df['a'] = a

df['rho'] = df['a'].rolling(252).corr(df['b'])
df['sigma_a'] = df['a'].rolling(252).std()
df['sigma_b'] = df['b'].rolling(252).std()
df['x_a'] = (df['rho']*df['sigma_a']*df['sigma_b']-df['sigma_b']**2)\
    /(2*df['rho']*df['sigma_a']*df['sigma_b']-df['sigma_a']**2-df['sigma_b']**2)
df['x_b'] = 1 - df['x_a']
df['efp'] = df['x_a']*df['a']+df['x_b']*df['b']

(1+df['a'][df['a'].index > df['efp'].dropna().index[0]]).cumprod().plot(label='S&P 500').legend()
(1+df['b'][df['b'].index > df['efp'].dropna().index[0]]).cumprod().plot(label='Gold').legend()
(1+df['efp'].dropna()).cumprod().plot(label='Portfolio').legend()
Out[102]:
<matplotlib.legend.Legend at 0x7f11ddd90588>
In [103]:
df['x_a'].plot(label='S&P 500 weight').legend()
df['x_b'].plot(label='Gold weight').legend()
Out[103]:
<matplotlib.legend.Legend at 0x7f11ddcd2f60>
In [134]:
print("Portfolio beta", df[spy].cov(df['efp'])/df[spy].var())
print("Gold beta",  df[spy].cov(df[gld])/df[spy].var())
Portfolio beta 0.412555509015
Gold beta 0.00926378374218
In [135]:
print("S&P 500 ann vol", math.sqrt(252)*df[spy].std())
print("Gold ann vol", math.sqrt(252)*df[gld].std())
print("Portfolio ann vol", math.sqrt(252)*df['efp'].std())
S&P 500 ann vol 0.1745812481063075
Gold ann vol 0.1576936054696308
Portfolio ann vol 0.1080168276967514
In [136]:
print("S&P 500 ann ret", ret((1+df[spy])**252-1))
print("Gold ann ret", ret((1+df[gld])**252-1))
print("Portfolio ann ret", ret((1+df['efp'])**252-1))
S&P 500 ann ret 0.124270489548
Gold ann ret 0.0428553754437
Portfolio ann ret 0.0835098001318
In [137]:
print("S&P 500 Sharpe", ra(df[spy]))
print("Gold Sharpe", ra(df[gld]))
print("Portfolio Sharpe", ra(df['efp']))
S&P 500 Sharpe 0.711816443344
Gold Sharpe 0.27176356021
Portfolio Sharpe 0.773118428976
In [ ]: