shyam gupta commited on
Commit
2f2929a
2 Parent(s): f6db2ed cf46b3a

Merge pull request #2 from Carsten134/refactoring

Browse files
.gitignore CHANGED
@@ -6,3 +6,9 @@
6
  *.idea
7
  *app.py
8
  *.env
 
 
 
 
 
 
 
6
  *.idea
7
  *app.py
8
  *.env
9
+
10
+ # VSCode settings
11
+ .vscode
12
+
13
+ # Pycache
14
+ */__pycache__
main.py CHANGED
@@ -1,255 +1,18 @@
1
- import yfinance as yf
2
- import numpy as np
3
  import pandas as pd
4
 
5
- import streamlit as st
6
-
7
  from utilities.py.styling import streamlit_style
8
- from utilities.py import plots
9
- from utilities.py import summary_tables
10
- # from utilities.py import mongodb
11
-
12
- from pypfopt import EfficientFrontier
13
- from pypfopt import risk_models
14
- from pypfopt import expected_returns
15
- from pypfopt import HRPOpt, hierarchical_portfolio
16
 
17
- import plotly.express as px
18
- import plotly.graph_objects as go
19
 
20
  streamlit_style()
21
-
22
  company_list_df = pd.read_csv("utilities/data/Company List.csv")
23
 
24
- company_name = company_list_df["Name"].to_list()
25
- company_symbol = (company_list_df["Ticker"] + ".NS").to_list()
26
-
27
- name_to_symbol_dict = dict()
28
- symbol_to_name_dict = dict()
29
-
30
- for CSymbol, CName in zip(company_symbol, company_name):
31
- name_to_symbol_dict[CName] = CSymbol
32
-
33
- for CSymbol, CName in zip(company_symbol, company_name):
34
- symbol_to_name_dict[CSymbol] = CName
35
-
36
- streamlit_company_list_input = st.multiselect(
37
- "Select Multiple Companies", company_name, default=None
38
- )
39
-
40
- optimisation_method = st.selectbox(
41
- "Choose an optimization method accordingly",
42
- (
43
- "Efficient Frontier",
44
- "Hierarchical Risk Parity",
45
- ),
46
- )
47
-
48
- parameter_for_optimisation = 0
49
- if optimisation_method == "Efficient Frontier":
50
- parameter_for_optimisation = st.selectbox(
51
- "Choose an optimization parameter accordingly",
52
- (
53
- "Maximum Sharpe Ratio",
54
- "Efficient Risk",
55
- "Minimum Volatility",
56
- "Efficient Return",
57
- ),
58
- )
59
-
60
- company_name_to_symbol = [name_to_symbol_dict[i] for i in streamlit_company_list_input]
61
-
62
- number_of_symbols = len(company_name_to_symbol)
63
-
64
- start_date = st.date_input(
65
- "Start Date",
66
- format="YYYY-MM-DD",
67
- value=pd.Timestamp("1947-08-15"),
68
- max_value=pd.Timestamp.now(),
69
- )
70
-
71
- initial_investment = st.number_input("How much would you want to invest?", value=45000)
72
-
73
- if number_of_symbols > 1:
74
- company_data = pd.DataFrame()
75
-
76
- for cname in company_name_to_symbol:
77
- stock_data_temp = yf.download(
78
- cname, start=start_date, end=pd.Timestamp.now().strftime("%Y-%m-%d")
79
- )["Adj Close"]
80
- stock_data_temp.name = cname
81
- company_data = pd.merge(
82
- company_data,
83
- stock_data_temp,
84
- how="outer",
85
- right_index=True,
86
- left_index=True,
87
- )
88
-
89
- company_data.dropna(axis=1, how="all", inplace=True)
90
-
91
- company_data.dropna(inplace=True)
92
-
93
- for i in company_data.columns:
94
- company_data[i] = company_data[i].abs()
95
-
96
- st.write(
97
- f"Note: Due to unavailability of full data, this Analysis uses data from the date: {company_data.index[0]}"
98
- )
99
-
100
- number_of_symbols = len(company_data.columns)
101
-
102
- st.dataframe(company_data, use_container_width=True)
103
-
104
- if number_of_symbols > 1:
105
- company_stock_returns_data = company_data.pct_change().dropna()
106
-
107
- mu = 0
108
- S = 0
109
- ef = 0
110
- company_asset_weights = 0
111
-
112
- if optimisation_method == "Efficient Frontier":
113
- mu = expected_returns.mean_historical_return(company_data)
114
- S = risk_models.sample_cov(company_data)
115
-
116
- ef = EfficientFrontier(mu, S)
117
-
118
- if parameter_for_optimisation == "Maximum Sharpe Raio":
119
- ef.max_sharpe()
120
- elif parameter_for_optimisation == "Minimum Volatility":
121
- ef.min_volatility()
122
- elif parameter_for_optimisation == "Efficient Risk":
123
- ef.efficient_risk(0.5)
124
- else:
125
- ef.efficient_return(0.05)
126
-
127
- company_asset_weights = pd.DataFrame.from_dict(
128
- ef.clean_weights(), orient="index"
129
- ).reset_index()
130
- elif optimisation_method == "Hierarchical Risk Parity":
131
- mu = expected_returns.returns_from_prices(company_data)
132
- S = risk_models.sample_cov(company_data)
133
-
134
- ef = HRPOpt(mu, S)
135
-
136
- company_asset_weights = ef.optimize()
137
- company_asset_weights = pd.DataFrame.from_dict(
138
- company_asset_weights, orient="index", columns=["Weight"]
139
- ).reset_index()
140
-
141
- company_asset_weights.columns = ["Ticker", "Allocation"]
142
-
143
- company_asset_weights_copy = company_asset_weights
144
-
145
- company_asset_weights["Name"] = [
146
- symbol_to_name_dict[i] for i in company_asset_weights["Ticker"]
147
- ]
148
-
149
- company_asset_weights = company_asset_weights[["Name", "Ticker", "Allocation"]]
150
-
151
- st.dataframe(company_asset_weights, use_container_width=True)
152
-
153
- ef.portfolio_performance()
154
-
155
- (
156
- expected_annual_return,
157
- annual_volatility,
158
- sharpe_ratio,
159
- ) = ef.portfolio_performance()
160
-
161
- st_portfolio_performance = pd.DataFrame.from_dict(
162
- {
163
- "Expected annual return": (expected_annual_return * 100).round(2),
164
- "Annual volatility": (annual_volatility * 100).round(2),
165
- "Sharpe ratio": sharpe_ratio.round(2),
166
- },
167
- orient="index",
168
- ).reset_index()
169
-
170
- st_portfolio_performance.columns = ["Metrics", "Summary"]
171
-
172
- if optimisation_method == "Efficient Frontier":
173
- st.write(
174
- "Optimization Method - ",
175
- optimisation_method,
176
- "---- Parameter - ",
177
- parameter_for_optimisation,
178
- )
179
- else:
180
- st.write("Optimization Method - ", optimisation_method)
181
-
182
- st.dataframe(st_portfolio_performance, use_container_width=True)
183
-
184
- plots.pie_chart_company_asset_weights(company_asset_weights)
185
-
186
- portfolio_returns = (
187
- company_stock_returns_data * list(ef.clean_weights().values())
188
- ).sum(axis=1)
189
-
190
- annual_portfolio_returns = portfolio_returns.resample("Y").apply(
191
- lambda x: (x + 1).prod() - 1
192
- )
193
-
194
- cumulative_returns = (portfolio_returns + 1).cumprod() * initial_investment
195
-
196
- tab1, tab2, tab3 = st.tabs(["Plots", "Annual Returns", "Montly Returns"])
197
-
198
- with tab1:
199
- plots.plot_annual_returns(annual_portfolio_returns)
200
- plots.plot_cummulative_returns(cumulative_returns)
201
-
202
- with tab2:
203
- annual_portfolio_returns = summary_tables.annual_returns_dataframe(
204
- annual_portfolio_returns
205
- )
206
- annual_cumulative_returns = (
207
- summary_tables.annual_cumulative_returns_dataframe(cumulative_returns)
208
- )
209
- annual_stock_returns = summary_tables.company_wise_annual_return(
210
- company_stock_returns_data, company_asset_weights
211
- )
212
-
213
- merged_annual_returns_data = pd.merge(
214
- annual_portfolio_returns,
215
- annual_cumulative_returns,
216
- on="Year",
217
- suffixes=("_portfolio", "_cumulative"),
218
- )
219
-
220
- merged_annual_returns_data = pd.merge(
221
- merged_annual_returns_data, annual_stock_returns, on="Year"
222
- )
223
-
224
- st.write("Annual Returns")
225
- st.dataframe(merged_annual_returns_data, use_container_width=True)
226
-
227
- with tab3:
228
- monthly_portfolio_return = summary_tables.monthly_returns_dataframe(
229
- portfolio_returns
230
- )
231
- monthly_stock_return = summary_tables.company_wise_monthly_return(
232
- company_stock_returns_data, company_asset_weights
233
- )
234
- monthly_cumulative_returns = (
235
- summary_tables.monthly_cumulative_returns_dataframe(cumulative_returns)
236
- )
237
-
238
- merged_monthly_returns_data = pd.merge(
239
- monthly_portfolio_return,
240
- monthly_cumulative_returns,
241
- on=["Year", "Month"],
242
- how="inner",
243
- )
244
 
245
- merged_monthly_returns_data = pd.merge(
246
- merged_monthly_returns_data,
247
- monthly_stock_return,
248
- on=["Year", "Month"],
249
- how="inner",
250
- )
251
 
252
- st.write("Montly Return")
253
- st.dataframe(merged_monthly_returns_data, use_container_width=True)
254
 
255
- # mongodb.mongodb_push_data(company_name_to_symbol, number_of_symbols)
 
 
 
 
1
  import pandas as pd
2
 
 
 
3
  from utilities.py.styling import streamlit_style
4
+ from utilities.py.composer import CapiPortApp
 
 
 
 
 
 
 
5
 
 
 
6
 
7
  streamlit_style()
8
+ # data import
9
  company_list_df = pd.read_csv("utilities/data/Company List.csv")
10
 
11
+ capi_port = CapiPortApp(company_list_df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ capi_port.render_user_input()
 
 
 
 
 
14
 
15
+ ready_to_render_results = len(capi_port.user_input.get_selected_comp_ids()) > 1
 
16
 
17
+ if ready_to_render_results:
18
+ capi_port.render_results()
utilities/py/__pycache__/plots.cpython-311.pyc ADDED
Binary file (3.54 kB). View file
 
utilities/py/__pycache__/styling.cpython-311.pyc ADDED
Binary file (1.69 kB). View file
 
utilities/py/__pycache__/summary_tables.cpython-311.pyc ADDED
Binary file (6.03 kB). View file
 
utilities/py/composer.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import streamlit as st
3
+
4
+ from utilities.py.data_management import CompData, PortfolioOptimizer
5
+ from utilities.py.ui_elements import UserInput
6
+ from utilities.py import plots, summary_tables
7
+
8
+
9
+ class CapiPortApp:
10
+ def __init__(self, company_df):
11
+ """
12
+ Class for composing the apps UI on a high level. Is meant to provide a readable overview, of what happens inside the app, without being concerned with unnecessary details.
13
+
14
+ Uppon initializing the composer fetches the data within the apps source code (for now) and let's a dedicated class handle the raw data.
15
+ """
16
+ self.comp_data = CompData(company_df)
17
+
18
+ # get all the necessary ui elements
19
+ self.user_input = UserInput(self.comp_data)
20
+
21
+ def render_user_input(self):
22
+ self.user_input.company_selection()
23
+ self.user_input.opt_method_selection()
24
+ self.user_input.start_date()
25
+ self.user_input.initial_investment()
26
+
27
+
28
+ def render_results(self):
29
+ """
30
+ CAUTION: the composer assumes, that the user has given all the necessary data.
31
+
32
+ NECESSARY DATA:
33
+ - at least two companies
34
+ - an optimization method
35
+ - a start date
36
+ - initial investment
37
+
38
+ Check the conditions the necessary conditions beforehand :)
39
+ """
40
+ # fetch user input
41
+ user_input_data = self.user_input.get_user_input_data()
42
+
43
+ # optimize the chosen portfolio according to the specifications
44
+ portfolio_opt = PortfolioOptimizer(self.comp_data,
45
+ self.user_input.get_selected_comp_ids(),
46
+ user_input_data.start_date)
47
+
48
+ company_asset_weights = portfolio_opt.optimize(user_input_data.opt_method,
49
+ user_input_data.ef_parameter)
50
+
51
+ # show first the stock data...
52
+ st.dataframe(portfolio_opt.stock_data, use_container_width=True)
53
+
54
+ # print disclaimer
55
+ first_date_available = portfolio_opt.stock_data.index[0]
56
+ opt_header = f"Used {user_input_data.opt_method}" if user_input_data.ef_parameter is None else f"Used {user_input_data.opt_method} with {user_input_data.ef_parameter}"
57
+
58
+
59
+ st.write(
60
+ f"Note: Due to unavailability of full data, this Analysis uses data from the date: {first_date_available}")
61
+
62
+ st.write(opt_header)
63
+
64
+ # show asset weights, portfolio performance and the pie chart
65
+ st.dataframe(company_asset_weights, use_container_width=True)
66
+
67
+ st.dataframe(portfolio_opt.get_portfolio_performance(),
68
+ use_container_width=True)
69
+
70
+ plots.pie_chart_company_asset_weights(company_asset_weights)
71
+
72
+ # summarize the resulting data
73
+ portfolio_returns = portfolio_opt.get_portfolio_returns()
74
+ annual_portfolio_returns = portfolio_opt.get_annual_portfolio_returns()
75
+
76
+ cumulative_returns = (portfolio_returns +
77
+ 1).cumprod() * user_input_data.init_invest
78
+
79
+ # render the tabs
80
+ tab1, tab2, tab3 = st.tabs(
81
+ ["Plots", "Annual Returns", "Montly Returns"])
82
+
83
+ with tab1:
84
+ plots.plot_annual_returns(annual_portfolio_returns)
85
+ plots.plot_cummulative_returns(cumulative_returns)
86
+
87
+ with tab2:
88
+ annual_portfolio_returns = summary_tables.annual_returns_dataframe(
89
+ annual_portfolio_returns
90
+ )
91
+ annual_cumulative_returns = (
92
+ summary_tables.annual_cumulative_returns_dataframe(
93
+ cumulative_returns)
94
+ )
95
+ annual_stock_returns = summary_tables.company_wise_annual_return(
96
+ portfolio_opt.stock_data_returns, company_asset_weights
97
+ )
98
+
99
+ merged_annual_returns_data = pd.merge(
100
+ annual_portfolio_returns,
101
+ annual_cumulative_returns,
102
+ on="Year",
103
+ suffixes=("_portfolio", "_cumulative"),
104
+ )
105
+
106
+ merged_annual_returns_data = pd.merge(
107
+ merged_annual_returns_data, annual_stock_returns, on="Year"
108
+ )
109
+
110
+ st.write("Annual Returns")
111
+ st.dataframe(merged_annual_returns_data, use_container_width=True)
112
+
113
+ with tab3:
114
+ monthly_portfolio_return = summary_tables.monthly_returns_dataframe(
115
+ portfolio_returns
116
+ )
117
+ monthly_stock_return = summary_tables.company_wise_monthly_return(
118
+ portfolio_opt.stock_data_returns, company_asset_weights
119
+ )
120
+ monthly_cumulative_returns = (
121
+ summary_tables.monthly_cumulative_returns_dataframe(
122
+ cumulative_returns)
123
+ )
124
+
125
+ merged_monthly_returns_data = pd.merge(
126
+ monthly_portfolio_return,
127
+ monthly_cumulative_returns,
128
+ on=["Year", "Month"],
129
+ how="inner",
130
+ )
131
+
132
+ merged_monthly_returns_data = pd.merge(
133
+ merged_monthly_returns_data,
134
+ monthly_stock_return,
135
+ on=["Year", "Month"],
136
+ how="inner",
137
+ )
138
+
139
+ st.write("Montly Return")
140
+ st.dataframe(merged_monthly_returns_data, use_container_width=True)
utilities/py/data_management.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import yfinance as yf
3
+
4
+ from pypfopt import EfficientFrontier
5
+ from pypfopt import risk_models
6
+ from pypfopt import expected_returns
7
+ from pypfopt import HRPOpt, hierarchical_portfolio
8
+
9
+
10
+ class CompData:
11
+ def __init__(self, company_data):
12
+ """
13
+ Class that manages company and stock data
14
+ """
15
+ self.df = company_data
16
+ self.company_names = self.df["Name"].to_list()
17
+ self.company_symbols = (self.df["Ticker"] + ".NS").to_list()
18
+
19
+ # utilities for tranlation
20
+ name_to_id_dict = dict()
21
+ id_to_name_dict = dict()
22
+
23
+ for CSymbol, CName in zip(self.company_symbols, self.company_names):
24
+ name_to_id_dict[CName] = CSymbol
25
+
26
+ for CSymbol, CName in zip(self.company_symbols, self.company_names):
27
+ id_to_name_dict[CSymbol] = CName
28
+
29
+ self.name_to_id = name_to_id_dict
30
+ self.id_to_name = id_to_name_dict
31
+
32
+ def fetch_stock_data(self, company_ids: list, start_date: str) -> pd.DataFrame:
33
+ """
34
+ Use yfinance client sdk to fetch stock data from the yahoo finance api
35
+ """
36
+ company_data = pd.DataFrame()
37
+
38
+ # get the stock data for the companies
39
+ for cname in company_ids:
40
+ stock_data_temp = yf.download(
41
+ cname, start=start_date, end=pd.Timestamp.now().strftime("%Y-%m-%d")
42
+ )["Adj Close"]
43
+ stock_data_temp.name = cname
44
+ company_data = pd.merge(
45
+ company_data,
46
+ stock_data_temp,
47
+ how="outer",
48
+ right_index=True,
49
+ left_index=True,
50
+ )
51
+
52
+ # cleaning the data
53
+ company_data.dropna(axis=1, how="all", inplace=True)
54
+
55
+ company_data.dropna(inplace=True)
56
+
57
+ for i in company_data.columns:
58
+ company_data[i] = company_data[i].abs()
59
+
60
+ return company_data
61
+
62
+ def comp_id_to_name(self, list_of_ids: list):
63
+ return [self.id_to_name[i] for i in list_of_ids]
64
+
65
+ def comp_name_to_id(self, list_of_names: list):
66
+ return [self.name_to_id[i] for i in list_of_names]
67
+
68
+
69
+ class PortfolioOptimizer:
70
+
71
+ def __init__(self, comp_data: CompData, company_ids: list, start_date: str):
72
+ self.comp_data = comp_data
73
+ self.stock_data = self.comp_data.fetch_stock_data(
74
+ company_ids, start_date)
75
+ self.stock_data_returns = self.stock_data.pct_change().dropna()
76
+
77
+ def optimize(self, method: str, ef_parameter=None):
78
+ company_asset_weights = 0
79
+
80
+ # Do the portfolio optimization
81
+ if method == "Efficient Frontier":
82
+ mu = expected_returns.mean_historical_return(self.stock_data)
83
+ S = risk_models.sample_cov(self.stock_data)
84
+
85
+ self.ef = EfficientFrontier(mu, S)
86
+
87
+ if ef_parameter == "Maximum Sharpe Raio":
88
+ self.ef.max_sharpe()
89
+ elif ef_parameter == "Minimum Volatility":
90
+ self.ef.min_volatility()
91
+ elif ef_parameter == "Efficient Risk":
92
+ self.ef.efficient_risk(0.5)
93
+ else:
94
+ self.ef.efficient_return(0.05)
95
+
96
+ company_asset_weights = pd.DataFrame.from_dict(
97
+ self.ef.clean_weights(), orient="index"
98
+ ).reset_index()
99
+
100
+ elif method == "Hierarchical Risk Parity":
101
+ mu = expected_returns.returns_from_prices(self.stock_data)
102
+ S = risk_models.sample_cov(self.stock_data)
103
+
104
+ self.ef = HRPOpt(mu, S)
105
+
106
+ company_asset_weights = self.ef.optimize()
107
+ company_asset_weights = pd.DataFrame.from_dict(
108
+ company_asset_weights, orient="index", columns=["Weight"]
109
+ ).reset_index()
110
+
111
+ # cleaning the returned data from the optimization
112
+ company_asset_weights.columns = ["Ticker", "Allocation"]
113
+
114
+ company_asset_weights["Name"] = self.comp_data.comp_id_to_name(
115
+ company_asset_weights["Ticker"])
116
+
117
+ company_asset_weights = company_asset_weights[[
118
+ "Name", "Ticker", "Allocation"]]
119
+
120
+ return company_asset_weights
121
+
122
+ def get_portfolio_performance(self):
123
+ if self.ef is not None:
124
+ (
125
+ expected_annual_return,
126
+ annual_volatility,
127
+ sharpe_ratio,
128
+ ) = self.ef.portfolio_performance()
129
+
130
+ st_portfolio_performance = pd.DataFrame.from_dict(
131
+ {
132
+ "Expected annual return": (expected_annual_return * 100).round(2),
133
+ "Annual volatility": (annual_volatility * 100).round(2),
134
+ "Sharpe ratio": sharpe_ratio.round(2),
135
+ },
136
+ orient="index",
137
+ ).reset_index()
138
+
139
+ st_portfolio_performance.columns = ["Metrics", "Summary"]
140
+
141
+ return st_portfolio_performance
142
+ else:
143
+ return None
144
+
145
+ def get_portfolio_returns(self):
146
+ return (
147
+ self.stock_data_returns * list(self.ef.clean_weights().values())
148
+ ).sum(axis=1)
149
+
150
+ def get_annual_portfolio_returns(self):
151
+ return self.get_portfolio_returns().resample("Y").apply(lambda x: (x + 1).prod() - 1)
utilities/py/ui_elements.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ import streamlit as st
4
+ from utilities.py.data_management import CompData
5
+
6
+ class UserInputData:
7
+ def __init__(self, company_list, opt_method, start_date, init_invest, ef_parameter = None):
8
+ self.company_list = company_list
9
+ self.opt_method = opt_method
10
+ self.ef_parameter = ef_parameter
11
+ self.start_date = start_date
12
+ self.init_invest = init_invest
13
+
14
+
15
+ class UserInput:
16
+
17
+ def __init__(self, company_data: CompData):
18
+ """
19
+ Class that renders the user selection (company, optimization technique, etc.)
20
+ """
21
+ self.comp_data = company_data
22
+ self.ef_parameter_input = None
23
+ self.company_list_input = None
24
+ self.opt_method_input = None
25
+ self.start_date_input = None
26
+ self.initial_investment_input = None
27
+
28
+ def company_selection(self):
29
+ self.company_list_input = st.multiselect(
30
+ "Select Multiple Companies", self.comp_data.company_names, default=None
31
+ )
32
+
33
+ def opt_method_selection(self):
34
+ self.opt_method_input = st.selectbox(
35
+ "Choose an optimization method accordingly",
36
+ (
37
+ "Efficient Frontier",
38
+ "Hierarchical Risk Parity",
39
+ ),
40
+ )
41
+
42
+ if self.opt_method_input == "Efficient Frontier":
43
+ self.ef_parameter_input = st.selectbox(
44
+ "Choose an optimization parameter accordingly",
45
+ (
46
+ "Maximum Sharpe Ratio",
47
+ "Efficient Risk",
48
+ "Minimum Volatility",
49
+ "Efficient Return",
50
+ ),
51
+ )
52
+
53
+ def start_date(self):
54
+ self.start_date_input = st.date_input(
55
+ "Start Date",
56
+ format="YYYY-MM-DD",
57
+ value=pd.Timestamp("1947-08-15"),
58
+ max_value=pd.Timestamp.now(),
59
+ )
60
+
61
+ def initial_investment(self):
62
+ self.innit_invest_input = st.number_input("How much would you want to invest?", value=45000)
63
+
64
+ def get_selected_comp_ids(self):
65
+ if self.company_list_input is not None:
66
+ return self.comp_data.comp_name_to_id(self.company_list_input)
67
+ print("WARINING: Selected company ids accessed, eventhough company not yet rendered in UI")
68
+ return None
69
+
70
+ def get_user_input_data(self) -> UserInputData:
71
+ return UserInputData(self.company_list_input,
72
+ self.opt_method_input,
73
+ self.start_date_input,
74
+ self.innit_invest_input,
75
+ self.ef_parameter_input)