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)