-
Notifications
You must be signed in to change notification settings - Fork 2
/
smart_weights.py
152 lines (102 loc) · 4.87 KB
/
smart_weights.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import yfinance as yf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime
from datetime import timedelta, timezone
from risky_smart_weights import generate_risky_portfolio
def last_trading_day():
now = datetime.datetime.now(timezone(timedelta(hours=-5), 'EST'))
# US Markets close at 4pm, but afterhours trading ends at 8pm.
# yFinance stubbornly only gives the day's data after 8pm, so we will wait until 9pm to pull data from
# the current day.
market_close = now.replace(hour=21, minute=0, second=0, microsecond=0)
if now < market_close:
DELTA = 1
# If it is saturday or sunday
elif now.weekday() >= 5:
DELTA = 1
else:
DELTA = 0
start_date = (datetime.datetime.now() - timedelta(days=15)).strftime("%Y-%m-%d")
end_date = (datetime.datetime.now() - pd.tseries.offsets.BDay(DELTA)).strftime("%Y-%m-%d")
MarketIndex = "^GSPC" # We can use the S&P 500's data to see the last day where we have data
market_hist = yf.Ticker(MarketIndex).history(start=start_date, end=end_date).filter(like="Close").dropna()
latest_day = market_hist.index[-1]
return latest_day.strftime("%Y-%m-%d")
def smart_weighted(ticker_list, option, initial_capital):
if option not in ('RISKY', 'SAFE'):
return None
elif option == 'RISKY':
return generate_risky_portfolio(ticker_list, initial_capital)
else:
start_date = (datetime.datetime.now() - timedelta(days=60)).strftime("%Y-%m-%d")
end_date = last_trading_day()
return generate_safe_portfolio(ticker_list, start_date, end_date, initial_capital)
def safe_method(ticker_list, start_date, end_date):
data = yf.download(ticker_list, start=start_date, end=end_date)
data = data['Adj Close']
#Calculate percent change
percent_change = data.pct_change().apply(lambda x: np.log(1 + x))
#Caluclate covariance
cov_matrix = percent_change.cov()
#Calculate STD
corr_matrix = percent_change.corr()
#Caluclate Yearly Expected Returns
data.index = pd.to_datetime(data.index)
ind_expected_returns = data.resample('Y').first().pct_change().mean()
yearly_stats = pd.DataFrame(ind_expected_returns, columns=['Returns'])
trading_days = 250
#Calculate annual std
annual_std = percent_change.std().apply(
lambda x: x * np.sqrt(trading_days)
)
yearly_stats['Volatility'] = annual_std
weights = []
returns = []
volatility = []
for i in range(1000):
individual_weights = np.random.random(len(ticker_list))
individual_weights = individual_weights/np.sum(individual_weights)
weights.append(individual_weights)
individual_returns = np.dot(individual_weights, yearly_stats.Returns)
returns.append(individual_returns)
portfolio_variance = (
cov_matrix.mul(individual_weights, axis = 0)
.mul(individual_weights, axis=1)
.sum()
.sum()
)
standard_deviation = np.sqrt(portfolio_variance)
individual_volatility = standard_deviation * np.sqrt(trading_days)
volatility.append(individual_volatility)
portfolios = pd.DataFrame(index=range(1000))
portfolios['Returns'] = returns
portfolios['Volatility'] = volatility
for i in range (len(ticker_list)):
for j in range (1000):
portfolios[ticker_list[i]] = weights[j][i]
return portfolios
def generate_safe_portfolio(ticker_list, start_date, end_date, initial_capital):
random_portfolios = safe_method(ticker_list, start_date, end_date)
safest_portfolio = random_portfolios.iloc[random_portfolios.Volatility.idxmin()]
pd.DataFrame(safest_portfolio)
date = last_trading_day()
current_day = datetime.datetime.strptime(date, "%Y-%m-%d")
next_day = current_day + timedelta(days=1)
final_portfolio_columns = ["Ticker", "Price", "Shares", "Value", "Weight"]
FinalPortfolio = pd.DataFrame(columns=final_portfolio_columns)
safest_portfolio_data = safest_portfolio[2:]
safest_portfolio_data = safest_portfolio_data.sort_index()
safest_portfolio_tickers = list(safest_portfolio_data.index)
safest_portfolio_weights = list(safest_portfolio_data.values)
prices = yf.download(safest_portfolio_tickers, start=current_day, end=next_day)
current_prices = prices["Adj Close"].loc[date]
FinalPortfolio['Ticker'] = safest_portfolio_tickers
FinalPortfolio['Price'] = current_prices.values
FinalPortfolio['Weight'] = safest_portfolio_weights
FinalPortfolio['Value'] = initial_capital * FinalPortfolio.Weight
FinalPortfolio['Shares'] = FinalPortfolio.Value / FinalPortfolio.Price
FinalPortfolio = FinalPortfolio[['Ticker', 'Shares']]
FinalPortfolio.set_index('Ticker', inplace=True)
return (FinalPortfolio, current_day.strftime("%Y-%m-%d"))