Lirsen Myrtaj
Updated variable names in ef.py (#16)
58ea282
raw
history blame
5.55 kB
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)