!pip install yfinance --upgrade --no-cache-dir
Requirement already satisfied: yfinance in /root/venv/lib/python3.7/site-packages (0.1.63)
Requirement already satisfied: numpy>=1.15 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from yfinance) (1.19.5)
Requirement already satisfied: pandas>=0.24 in /root/venv/lib/python3.7/site-packages (from yfinance) (0.25.3)
Requirement already satisfied: multitasking>=0.0.7 in /root/venv/lib/python3.7/site-packages (from yfinance) (0.0.9)
Requirement already satisfied: lxml>=4.5.1 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from yfinance) (4.6.3)
Requirement already satisfied: requests>=2.20 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from yfinance) (2.26.0)
Requirement already satisfied: pytz>=2017.2 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from pandas>=0.24->yfinance) (2021.1)
Requirement already satisfied: python-dateutil>=2.6.1 in /shared-libs/python3.7/py-core/lib/python3.7/site-packages (from pandas>=0.24->yfinance) (2.8.2)
Requirement already satisfied: six>=1.5 in /shared-libs/python3.7/py-core/lib/python3.7/site-packages (from python-dateutil>=2.6.1->pandas>=0.24->yfinance) (1.16.0)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from requests>=2.20->yfinance) (1.26.7)
Requirement already satisfied: certifi>=2017.4.17 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from requests>=2.20->yfinance) (2021.5.30)
Requirement already satisfied: charset-normalizer~=2.0.0 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from requests>=2.20->yfinance) (2.0.6)
Requirement already satisfied: idna<4,>=2.5 in /shared-libs/python3.7/py-core/lib/python3.7/site-packages (from requests>=2.20->yfinance) (3.2)
!pip install PyPortfolioOpt==1.2.1
Requirement already satisfied: PyPortfolioOpt==1.2.1 in /root/venv/lib/python3.7/site-packages (1.2.1)
Requirement already satisfied: cvxpy<2.0.0,>=1.0.28 in /root/venv/lib/python3.7/site-packages (from PyPortfolioOpt==1.2.1) (1.1.15)
Requirement already satisfied: pandas<0.26.0,>=0.25.3 in /root/venv/lib/python3.7/site-packages (from PyPortfolioOpt==1.2.1) (0.25.3)
Requirement already satisfied: numpy in /shared-libs/python3.7/py/lib/python3.7/site-packages (from PyPortfolioOpt==1.2.1) (1.19.5)
Requirement already satisfied: scipy in /shared-libs/python3.7/py/lib/python3.7/site-packages (from PyPortfolioOpt==1.2.1) (1.7.1)
Requirement already satisfied: osqp>=0.4.1 in /root/venv/lib/python3.7/site-packages (from cvxpy<2.0.0,>=1.0.28->PyPortfolioOpt==1.2.1) (0.6.2.post0)
Requirement already satisfied: ecos>=2 in /root/venv/lib/python3.7/site-packages (from cvxpy<2.0.0,>=1.0.28->PyPortfolioOpt==1.2.1) (2.0.7.post1)
Requirement already satisfied: scs>=1.1.6 in /root/venv/lib/python3.7/site-packages (from cvxpy<2.0.0,>=1.0.28->PyPortfolioOpt==1.2.1) (2.1.4)
Requirement already satisfied: qdldl in /root/venv/lib/python3.7/site-packages (from osqp>=0.4.1->cvxpy<2.0.0,>=1.0.28->PyPortfolioOpt==1.2.1) (0.1.5.post0)
Requirement already satisfied: pytz>=2017.2 in /shared-libs/python3.7/py/lib/python3.7/site-packages (from pandas<0.26.0,>=0.25.3->PyPortfolioOpt==1.2.1) (2021.1)
Requirement already satisfied: python-dateutil>=2.6.1 in /shared-libs/python3.7/py-core/lib/python3.7/site-packages (from pandas<0.26.0,>=0.25.3->PyPortfolioOpt==1.2.1) (2.8.2)
Requirement already satisfied: six>=1.5 in /shared-libs/python3.7/py-core/lib/python3.7/site-packages (from python-dateutil>=2.6.1->pandas<0.26.0,>=0.25.3->PyPortfolioOpt==1.2.1) (1.16.0)
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()
[*********************100%***********************] 1 of 1 completed
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 380 entries, 2020-03-02 to 2021-08-31
Data columns (total 6 columns):
Open 380 non-null float64
High 380 non-null float64
Low 380 non-null float64
Close 380 non-null float64
Adj Close 380 non-null float64
Volume 380 non-null int64
dtypes: float64(5), int64(1)
memory usage: 20.8 KB
spy = data.reset_index()
spy.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 7 columns):
Date 380 non-null datetime64[ns]
Open 380 non-null float64
High 380 non-null float64
Low 380 non-null float64
Close 380 non-null float64
Adj Close 380 non-null float64
Volume 380 non-null int64
dtypes: datetime64[ns](1), float64(5), int64(1)
memory usage: 20.9 KB
# filter column adjusted close
spy = spy[['Date','Adj Close', 'Volume']]
spy.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 3 columns):
Date 380 non-null datetime64[ns]
Adj Close 380 non-null float64
Volume 380 non-null int64
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 9.0 KB
# 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)
[*********************100%***********************] 8 of 8 completed
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))
Discrete allocation: {'BTC-USD': 5, 'BILI': 2139, 'ZM': 553, 'PYPL': 447, 'FB': 243, 'AMZN': 22, 'SPY': 113, 'VHT': 188}
Funds remaining: $26270.19
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()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 549 entries, 0 to 548
Data columns (total 2 columns):
Date 549 non-null datetime64[ns]
portfolio_ret 549 non-null float64
dtypes: datetime64[ns](1), float64(1)
memory usage: 8.7 KB
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['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)')
Difference in mean return:
0.2524028442678666
p value is 0.047916505048968494
The difference in mean return is significantly different (reject H0)