Parthjain9925 commited on
Commit
1b4d990
·
1 Parent(s): d5bd80d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -0
app.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from pandas_datareader.data import DataReader
3
+ from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
4
+ from pypfopt import EfficientFrontier
5
+ from pypfopt import risk_models
6
+ from pypfopt import expected_returns
7
+ from pypfopt import plotting
8
+ import copy
9
+ import numpy as np
10
+ import pandas as pd
11
+ import plotly.express as px
12
+ import matplotlib.pyplot as plt
13
+ import seaborn as sns
14
+ from datetime import datetime
15
+ from io import BytesIO
16
+
17
+ def plot_cum_returns(data, title):
18
+ daily_cum_returns = 1 + data.dropna().pct_change()
19
+ daily_cum_returns = daily_cum_returns.cumprod()*100
20
+ fig = px.line(daily_cum_returns, title=title)
21
+ return fig
22
+
23
+ def plot_efficient_frontier_and_max_sharpe(mu, S):
24
+ # Optimize portfolio for max Sharpe ratio and plot it out with efficient frontier curve
25
+ ef = EfficientFrontier(mu, S)
26
+ fig, ax = plt.subplots(figsize=(6,4))
27
+ ef_max_sharpe = copy.deepcopy(ef)
28
+ plotting.plot_efficient_frontier(ef, ax=ax, show_assets=False)
29
+ # Find the max sharpe portfolio
30
+ ef_max_sharpe.max_sharpe(risk_free_rate=0.02)
31
+ ret_tangent, std_tangent, _ = ef_max_sharpe.portfolio_performance()
32
+ ax.scatter(std_tangent, ret_tangent, marker="*", s=100, c="r", label="Max Sharpe")
33
+ # Generate random portfolios
34
+ n_samples = 1000
35
+ w = np.random.dirichlet(np.ones(ef.n_assets), n_samples)
36
+ rets = w.dot(ef.expected_returns)
37
+ stds = np.sqrt(np.diag(w @ ef.cov_matrix @ w.T))
38
+ sharpes = rets / stds
39
+ ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")
40
+ # Output
41
+ ax.legend()
42
+ return fig
43
+
44
+ st.set_page_config(page_title = "Bohmian's Stock Portfolio Optimizer", layout = "wide")
45
+ st.header("Bohmian's Stock Portfolio Optimizer")
46
+
47
+ col1, col2 = st.columns(2)
48
+
49
+ with col1:
50
+ start_date = st.date_input("Start Date",datetime(2013, 1, 1))
51
+
52
+ with col2:
53
+ end_date = st.date_input("End Date") # it defaults to current date
54
+
55
+ tickers_string = st.text_input('Enter all stock tickers to be included in portfolio separated by commas \
56
+ WITHOUT spaces, e.g. "MA,FB,V,AMZN,JPM,BA"', '').upper()
57
+ tickers = tickers_string.split(',')
58
+
59
+ try:
60
+ # Get Stock Prices using pandas_datareader Library
61
+ stocks_df = DataReader(tickers, 'yahoo', start = start_date, end = end_date)['Adj Close']
62
+ # Plot Individual Stock Prices
63
+ fig_price = px.line(stocks_df, title='Price of Individual Stocks')
64
+ # Plot Individual Cumulative Returns
65
+ fig_cum_returns = plot_cum_returns(stocks_df, 'Cumulative Returns of Individual Stocks Starting with $100')
66
+ # Calculatge and Plot Correlation Matrix between Stocks
67
+ corr_df = stocks_df.corr().round(2)
68
+ fig_corr = px.imshow(corr_df, text_auto=True, title = 'Correlation between Stocks')
69
+
70
+ # Calculate expected returns and sample covariance matrix for portfolio optimization later
71
+ mu = expected_returns.mean_historical_return(stocks_df)
72
+ S = risk_models.sample_cov(stocks_df)
73
+
74
+ # Plot efficient frontier curve
75
+ fig = plot_efficient_frontier_and_max_sharpe(mu, S)
76
+ fig_efficient_frontier = BytesIO()
77
+ fig.savefig(fig_efficient_frontier, format="png")
78
+
79
+ # Get optimized weights
80
+ ef = EfficientFrontier(mu, S)
81
+ ef.max_sharpe(risk_free_rate=0.02)
82
+ weights = ef.clean_weights()
83
+ expected_annual_return, annual_volatility, sharpe_ratio = ef.portfolio_performance()
84
+ weights_df = pd.DataFrame.from_dict(weights, orient = 'index')
85
+ weights_df.columns = ['weights']
86
+
87
+ # Calculate returns of portfolio with optimized weights
88
+ stocks_df['Optimized Portfolio'] = 0
89
+ for ticker, weight in weights.items():
90
+ stocks_df['Optimized Portfolio'] += stocks_df[ticker]*weight
91
+
92
+ # Plot Cumulative Returns of Optimized Portfolio
93
+ fig_cum_returns_optimized = plot_cum_returns(stocks_df['Optimized Portfolio'], 'Cumulative Returns of Optimized Portfolio Starting with $100')
94
+
95
+ # Display everything on Streamlit
96
+ st.subheader("Your Portfolio Consists of {} Stocks".format(tickers_string))
97
+ st.plotly_chart(fig_cum_returns_optimized)
98
+
99
+ st.subheader("Optimized Max Sharpe Portfolio Weights")
100
+ st.dataframe(weights_df)
101
+
102
+ st.subheader("Optimized Max Sharpe Portfolio Performance")
103
+ st.image(fig_efficient_frontier)
104
+
105
+ st.subheader('Expected annual return: {}%'.format((expected_annual_return*100).round(2)))
106
+ st.subheader('Annual volatility: {}%'.format((annual_volatility*100).round(2)))
107
+ st.subheader('Sharpe Ratio: {}'.format(sharpe_ratio.round(2)))
108
+
109
+ st.plotly_chart(fig_corr) # fig_corr is not a plotly chart
110
+ st.plotly_chart(fig_price)
111
+ st.plotly_chart(fig_cum_returns)
112
+
113
+
114
+
115
+ except:
116
+ st.write('Enter correct stock tickers to be included in portfolio separated\
117
+ by commas WITHOUT spaces, e.g. "MA,FB,V,AMZN,JPM,BA"and hit Enter.')
118
+
119
+ hide_streamlit_style = """
120
+ <style>
121
+ #MainMenu {visibility: hidden;}
122
+ footer {visibility: hidden;}
123
+ </style>
124
+ """
125
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)