File size: 5,548 Bytes
408579e f2ae133 408579e f2ae133 08c23df 408579e f2ae133 408579e f2ae133 408579e f2ae133 408579e f2ae133 58ea282 408579e f2ae133 58ea282 f2ae133 408579e f2ae133 408579e f2ae133 408579e |
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 |
import pandas as pd
import numpy as np
from datetime import datetime as dt
from pypfopt.efficient_frontier import EfficientFrontier
import streamlit as st
import plotly.graph_objects as go
import plotly.express as px
### START AND RUN STREAMLIT
#https://docs.streamlit.io/library/get-started/installation
def ef_viz(stock_df,choices):
#st.write("EF Visualization KOI EDITS")
# st.header('CAPM Model and the Efficient Frontier')
# """
# CAPM model measure systematic risks, however it has unrealistic assumptions and relies heavily on a linear interpretation
# of the risks vs. returns relationship. It is better to use CAPM model in conjunction with the Efficient Frontier to better
# graphically depict volatility (a measure of investment risk) for the defined rate of return. <br>
# Each circle depicted above is a variation of the portfolio with the same input assest, only different weights.
# Portfolios with higher volatilities has a yellower shade of hue, while portfolios with a higher return has a bigger radius. <br>
# As you input different porfolio assets, take note of how diversification can improve a portfolio's risk versus reward profile.
# """
symbols, weights, investment, rf, A_coef = choices.values()
tickers = symbols
#tickers.append('sp500')
#st.write(tickers)
#st.write(stock_df)
# Yearly returns for individual companies
#https://stackoverflow.com/questions/69284773/unable-to-resample-the-pandas-with-date-column-typeerror-only-valid-with-dateti
stock_dff = stock_df.copy()
stock_dff['Date'] = pd.to_datetime(stock_dff['Date'])
# ind_er_df = stock_dff.set_index('Date')
#st.write(stock_dff.columns)
ind_er_df = stock_dff.resample('Y', on = 'Date').last().pct_change().mean()
ind_er = ind_er_df[tickers]
#st.write(ind_er)
ann_sd = stock_df[tickers].pct_change().apply(lambda x: np.log(1+x)).std().apply(lambda x: x*np.sqrt(250))
assets = pd.concat([ind_er, ann_sd], axis=1) # Creating a table for visualising returns and volatility of assets
assets.columns = ['Returns', 'Volatility']
assets
#st.write(assets)
ln_pct_change = stock_df[tickers].pct_change().apply(lambda x: np.log(1+x))[1:]
#Cov Matrix
cov_matrix =ln_pct_change.cov()
## CREATE PORFOLIOS WEIGHTS
p_ret = [] # Define an empty array for portfolio returns
p_vol = [] # Define an empty array for portfolio volatility
p_weights = [] # Define an empty array for asset weights
num_assets = len(tickers)
num_portfolios = 10000
for portfolio in range(num_portfolios):
weights = np.random.random(num_assets)
weights = weights/np.sum(weights)
p_weights.append(weights)
returns = np.dot(weights, ind_er) # Returns are the product of individual expected returns of asset and its
# weights
p_ret.append(returns)
var = cov_matrix.mul(weights, axis=0).mul(weights, axis=1).sum().sum()# Portfolio Variance
sd = np.sqrt(var) # Daily standard deviation
ann_sd = sd*np.sqrt(250) # Annual standard deviation = volatility
p_vol.append(ann_sd)
data = {'Returns':p_ret, 'Volatility':p_vol}
for counter, symbol in enumerate(stock_df[tickers].columns.tolist()):
#print(counter, symbol)
data[symbol] = [w[counter] for w in p_weights]
port_ef_df = pd.DataFrame(data)
#st.write(port_ef_df[tickers].T)
## NEEDS INPUT INSTEAD OF HARD CODE
#a = 5 #the coefficient of risk aversion is A. If an invest is less risk averse A is small. We assume 25 < A < 35.
#rf = 0.041
min_vol_port = port_ef_df.iloc[port_ef_df['Volatility'].idxmin()]
optimal_risky_port = port_ef_df.iloc[((port_ef_df['Returns']-rf)/port_ef_df['Volatility']).idxmax()]
## CREATE CAPM LINE #https://www.youtube.com/watch?v=JWx2wcrSGkk
cal_x = []
cal_y = []
utl = []
for er in np.linspace(rf, max(data['Returns']),20):
sd = (er - rf)/ ((optimal_risky_port[0] - rf)/ optimal_risky_port[1])
u = er - 0.5*A_coef*(sd**2)
cal_x.append(sd)
cal_y.append(er)
utl.append(u)
data2 = {'Utility':utl, 'cal_x':cal_x, 'cal_y':cal_y}
utl_df = pd.DataFrame(data2)
## Create Figure
# fig = go.Figure()
# fig.add_trace(go.Scatter(x=port_ef_df['Volatility'], y=port_ef_df['Returns'], \
# color=port_ef_df['Volatility'], mode='markers', name='markers'))
fig = px.scatter(port_ef_df, 'Volatility', 'Returns', size='Returns', size_max=20, color='Volatility', \
custom_data=tickers)
fig.update_traces(hovertemplate="<br>".join([
"%{tickers[0]}:%{custom_data[0]}",
"%{tickers[1]}:%{custom_data[1]}",
"%{tickers[2]}:%{custom_data[2]}",
"%{tickers[3]}:%{custom_data[3]}"
])
)
fig1 = px.line(utl_df, x="cal_x", y="cal_y")
fig1.update_traces(line=dict(color = 'rgba(11,156,49,1)'))
#https://stackoverflow.com/questions/59057881/python-plotly-how-to-customize-hover-template-on-with-what-information-to-show
#https://stackoverflow.com/questions/65124833/plotly-how-to-combine-scatter-and-line-plots-using-plotly-express
fig3 = go.Figure(data=fig.data + fig1.data)
st.plotly_chart(fig3, use_container_width=True)
#st.write(stock_df) |