!pip install yfinance --upgrade --no-cache-dir
!pip install PyPortfolioOpt==1.2.1
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import datetime as dt
import yfinance as yf
symbols_list = ['SPY']
start = dt.datetime(2020,3,1)
end = dt.datetime(2021,9,1)
data = yf.download(symbols_list, start=start, end=end)
data.info()
spy = data.reset_index()
spy.info()
# filter column adjusted close
spy = spy[['Date','Adj Close', 'Volume']]
spy.info()
# create variables
spy['day_of_week'] = spy['Date'].dt.dayofweek
spy['return'] = spy['Adj Close'].pct_change()
spy = spy.bfill()
from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt import risk_models
from pypfopt import expected_returns
from pypfopt import cla
from pypfopt.plotting import Plotting
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
from matplotlib.ticker import FuncFormatter
import seaborn as sns
from pypfopt import objective_functions
p_symbols_list = ['PYPL', 'VHT','BTC-USD', 'BILI', 'ZM', 'SPY', 'FB', 'AMZN'] #, '^IRX'
p_start = dt.datetime(2020,3,1)
p_end = dt.datetime(2021,9,1)
p_data = yf.download(p_symbols_list, start=p_start, end=p_end)
p_df = p_data['Adj Close']
# Unique names (e.g., crypto trade on weekends as well but stock do not)
p_df = p_df.ffill()
p_df.head()
sharpe_portfolio_wt = {'AMZN': 0.07631, 'BILI': 0.17167, 'BTC-USD': 0.26975, 'FB': 0.0922, 'PYPL': 0.12928, 'SPY': 0.05111, 'VHT': 0.04954, 'ZM': 0.16014}
latest_prices = get_latest_prices(p_df)
da = DiscreteAllocation(sharpe_portfolio_wt, latest_prices, total_portfolio_value=1000000)
allocation, leftover = da.greedy_portfolio()
print("Discrete allocation:", allocation)
print("Funds remaining: ${:.2f}".format(leftover))
sharpe_portfolio_wt_list = list(sharpe_portfolio_wt.values())
ret_data_s = p_df.pct_change()[1:]
weighted_returns_s = (sharpe_portfolio_wt_list * ret_data_s)
portfolio_ret_s = pd.DataFrame(weighted_returns_s.sum(axis=1))
ret_data_s = ret_data_s.merge(portfolio_ret_s, on="Date", how="left")
ret_data_s = ret_data_s.rename(columns={0: "portfolio_ret"})
ret_data_s=ret_data_s[["portfolio_ret"]]
ret_data_s = ret_data_s.reset_index()
ret_data_s.info()
ret_data_s['day_of_week'] = ret_data_s['Date'].dt.dayofweek
ret_data_s['return'] = ret_data_s['portfolio_ret']
ret_data_s.tail(10)
ret_data_s[ret_data_s["return"]<-100]
df = spy.merge(ret_data_s, how = "inner", on ="Date",suffixes=('_spy', '_sharpe'))
df.head(10)
df['cumulative_sharpe_portfolio_ret'] = (df['return_sharpe'] + 1).cumprod()
df['cumulative_spy_ret'] = (df['return_spy'] + 1).cumprod()
df.tail()
sns.scatterplot('Date', 'cumulative_sharpe_portfolio_ret', data=df)
sns.scatterplot('Date', 'cumulative_spy_ret', data=df)
plt.legend(['cumulative_sharpe_portfolio_ret','cumulative_spy_ret'])
df['return_spy'].hist(bins=100, color='r', alpha=0.5, figsize = (16,8) )
df['return_sharpe'].hist(bins=100, color='g', alpha=0.5)
import scipy.stats as stats
print("Difference in mean return: ")
print((df['return_sharpe'].mean() - df['return_spy'].mean())*100)
stat, p = stats.ttest_ind(df['return_sharpe'], df['return_spy'], equal_var=False, alternative='greater')
# interpret p-value
alpha = 0.05
print("p value is " + str(p))
if p <= alpha:
print('The difference in mean return is significantly different (reject H0)')
else:
print('The difference in mean return is not significantly different (fail to reject H0)')