-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
38a2f6d
commit 853da4d
Showing
4 changed files
with
646 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
import dash | ||
import pandas as pd | ||
import numpy as np | ||
import dash_daq as daq | ||
import plotly.graph_objs as go | ||
import plotly.express as px | ||
import plotly.figure_factory as ff | ||
from dash import Dash, html, dcc | ||
import dash_bootstrap_components as dbc | ||
from dash.dependencies import Input, Output, State | ||
from datetime import date | ||
import layout | ||
import dataload | ||
|
||
|
||
|
||
|
||
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) | ||
|
||
server = app.server | ||
|
||
|
||
################################################################## | ||
# The layout section | ||
################################################################## | ||
|
||
app.layout = layout.Financial_Portfolio_Layout | ||
|
||
|
||
################################################################## | ||
# The callback section | ||
################################################################## | ||
@app.callback( | ||
[ | ||
Output('store-data', 'data'), | ||
Output("alert-wip-data", "is_open") | ||
], | ||
[ | ||
Input("id-company-dropdown","value"), | ||
Input("id-start-date","date"), | ||
Input("id-end-date","date") | ||
] | ||
) | ||
def update_storeData(company, start_date, end_date): | ||
"""_summary_ | ||
Args: | ||
company (List): Loads the data DCC data store with the stock data | ||
Returns: | ||
Dataframe: Returns a dataframe which has price data for selected companies | ||
""" | ||
s_year = int(start_date[0:4]) | ||
s_month = int(start_date[5:7]) | ||
s_day = int(start_date[8:10]) | ||
|
||
e_year = int(end_date[0:4]) | ||
e_month = int(end_date[5:7]) | ||
e_day = int(end_date[8:10]) | ||
|
||
s_date = date(s_year,s_month,s_day) | ||
e_date = date(e_year,e_month,e_day) | ||
|
||
try: | ||
dataset = dataload.load_stock_data(s_date, e_date, company) | ||
|
||
dataset.reset_index(inplace = True) | ||
return dataset.to_dict('records'), True | ||
except Exception as e: | ||
print(f'An exception occurred while updating the data store: {e}') | ||
|
||
|
||
|
||
@app.callback( | ||
[ | ||
Output("id_low_risk", 'value'), | ||
# Output("id_lowrisk_returns", 'value'), | ||
Output("id_high_risk", 'value'), | ||
# Output("id_highrisk_returns", 'value'), | ||
Output("fig_allocation_low", 'figure'), | ||
Output("alert-wip", "is_open"), | ||
Output("fig_allocation_high", 'figure'), | ||
Output("id-info_low", 'children'), | ||
Output("id-info_high", 'children'), | ||
], | ||
[ | ||
Input('id-btn-create', 'n_clicks'), | ||
State('id-company-dropdown', 'value'), | ||
State('store-data', 'data'), | ||
State("alert-wip", "is_open") | ||
], | ||
prevent_initial_call = True | ||
) | ||
def update_allocation(btn_create, company, data, val_is_open): | ||
"""_summary_ | ||
Args: | ||
company (List): Loads the data DCC data store with the stock data | ||
data (Dataframe): The DCC data store which has the stock data | ||
val_is_open (Boolean): A boolean value for displaying alert on successful generation of portfolio | ||
Returns: | ||
_type_: _description_ | ||
""" | ||
button_id = dash.callback_context.triggered[0]['prop_id'].split('.')[0] | ||
global df_risk | ||
|
||
if button_id == 'id-btn-create': | ||
|
||
try: | ||
ddf = pd.DataFrame.from_records(data, index=['Date']) | ||
ddf = ddf[ddf.columns & company] | ||
|
||
ddf_returns = ddf.pct_change().dropna() | ||
dd_returns = ddf_returns.copy() | ||
|
||
ddf_cumulative = ddf_returns.copy() | ||
ddf.reset_index(inplace = True) | ||
ddf_returns.reset_index(inplace = True) | ||
|
||
|
||
low_risk_wts, high_risk_wts, low_risk_return, low_risk_volatility, high_risk_return, high_risk_volatility, df_risk = dataload.sim_bootstrap(dd_returns, company) | ||
|
||
fig_allocation_low_risk = px.pie(values = low_risk_wts, names = company, hole= 0.3) | ||
fig_allocation_high_risk = px.pie(values = high_risk_wts, names = company, hole= 0.3) | ||
|
||
|
||
|
||
return [low_risk_volatility, | ||
# low_risk_return, | ||
high_risk_volatility, | ||
# high_risk_return, | ||
fig_allocation_low_risk, | ||
True, | ||
fig_allocation_high_risk, | ||
html.Div(f'At 95% confidence, the maximum loss expected will be {low_risk_volatility} %', id="id-info_low",style={'display': 'block', 'color': 'blue', 'fontSize': 15, 'font-weight': 'bold', "text-align": "center"}), | ||
html.Div(f'At 95% confidence, the maximum loss expected will be {high_risk_volatility} %', id="id-info_low",style={'display': 'block', 'color': 'blue', 'fontSize': 15, 'font-weight': 'bold', "text-align": "center"}), | ||
] | ||
|
||
|
||
except Exception as e: | ||
print(f'An exception occurred while executing update_trendsChart(): {e}') | ||
|
||
else: | ||
return [None, | ||
# None, | ||
None, | ||
# None, | ||
layout.blank_fig(), | ||
None, | ||
layout.blank_fig(), | ||
None, | ||
None] | ||
|
||
|
||
|
||
|
||
|
||
@app.callback( | ||
Output("fig_trends", 'figure'), | ||
[ | ||
Input('id-btn-create', 'n_clicks'), | ||
Input('id-analysis-options', 'value'), | ||
State('id-company-dropdown', 'value'), | ||
State('store-data', 'data') | ||
], | ||
prevent_initial_call=True | ||
) | ||
def update_trends(btn_create, option_selected, company, data): | ||
|
||
""" Stock trends analysis | ||
Returns: | ||
String: The radio button selection value | ||
""" | ||
|
||
|
||
try: | ||
|
||
ddf = pd.DataFrame.from_records(data, index=['Date']) | ||
ddf = ddf[ddf.columns & company] | ||
|
||
ddf_returns = ddf.pct_change().dropna() | ||
dd_returns = ddf_returns.copy() | ||
|
||
ddf_cumulative = ddf_returns.copy() | ||
|
||
ddf.reset_index(inplace = True) | ||
ddf_returns.reset_index(inplace = True) | ||
|
||
# low_risk_wts, high_risk_wts, low_risk_return, low_risk_volatility, high_risk_return, high_risk_volatility, df_risk = dataload.sim_bootstrap(dd_returns, company) | ||
|
||
|
||
if option_selected == 'STOCK PRICE TRENDS': | ||
|
||
fig_price = px.line(ddf, x="Date", y = ddf.columns, template="simple_white") | ||
return fig_price | ||
|
||
elif option_selected == 'STOCK RETURNS TRENDS': | ||
|
||
fig_returns = px.line(ddf_returns, x="Date", y = ddf_returns.columns, template="simple_white") | ||
return fig_returns | ||
|
||
elif option_selected == 'CUMULATIVE RETURNS': | ||
|
||
df_cumulative = (ddf_cumulative+1).cumprod() | ||
df_cumulative.reset_index(inplace = True) | ||
|
||
fig_cumulative = px.line(df_cumulative, x="Date", y = df_cumulative.columns, template="simple_white") | ||
return fig_cumulative | ||
|
||
elif option_selected == 'VOLATILITY IN RETURNS': | ||
# df_risk['Risk'] = df_risk['Risk'].abs() | ||
df_risk['Risk'] = df_risk['Risk'] * 100 | ||
fig_risk_returns = px.scatter(df_risk, x = 'Risk', y = 'Returns') | ||
return fig_risk_returns | ||
|
||
else: | ||
return layout.blank_fig() | ||
|
||
except Exception as e: | ||
print(f'An exception occurred while executing update_trendsChart(): {e}') | ||
|
||
|
||
|
||
|
||
|
||
|
||
if __name__ == "__main__": | ||
app.run_server(debug=True, use_reloader=False) | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import pandas as pd | ||
import numpy as np | ||
import datetime | ||
from datetime import date | ||
from nsepy import get_history as gh | ||
|
||
|
||
|
||
################################################################## | ||
# Data Loading | ||
################################################################## | ||
def load_stock_data(start_date, end_date, ticker): | ||
"""_summary_ | ||
Args: | ||
start_date (Date): Start data for stock selection | ||
end_date (Date): End date for stock selection | ||
ticker (List): List of stocks | ||
Returns: | ||
Dataframe: price data for selected stock for a selected period | ||
""" | ||
try: | ||
df = pd.DataFrame() | ||
|
||
for i in range(len(ticker)): | ||
data = gh(symbol=ticker[i],start= start_date, end=end_date)[['Symbol','Close']] | ||
data.rename(columns={'Close':data['Symbol'][0]},inplace=True) | ||
data.drop(['Symbol'], axis=1,inplace=True) | ||
if i == 0: | ||
df = data | ||
|
||
if i != 0: | ||
df = df.join(data) | ||
|
||
|
||
return df | ||
except Exception as e: | ||
print(f'An exception occurred while executing data load: {e}') | ||
|
||
|
||
|
||
|
||
################################################################## | ||
# Data Loading | ||
################################################################## | ||
|
||
def sim_portfolio(weights, dd_returns): | ||
"""_summary_ | ||
Args: | ||
weights (List): Weights for each of the stock | ||
Returns: | ||
Float: Returns the risk at 95% percentile | ||
""" | ||
try: | ||
tmp_pp = (weights * dd_returns.values).sum(axis=1) | ||
var_sim_port = np.percentile(tmp_pp, 5, interpolation = 'lower') | ||
return var_sim_port | ||
except Exception as e: | ||
print(f'An exception occurred while executing sim_portfolio: {e}') | ||
|
||
|
||
def sim_bootstrap(dd_returns, company): | ||
"""_summary_ | ||
Args: | ||
dd_returns (Dataframe): the dataframe which has stock returns. | ||
company (List): List of stocks | ||
Returns: | ||
int: returns various metrics | ||
""" | ||
|
||
try: | ||
|
||
port_returns = [] | ||
port_volatility = [] | ||
port_weights = [] | ||
|
||
num_assets = len(company) | ||
num_portfolios = 100 | ||
np.random.seed(1357) | ||
for port in range(num_portfolios): | ||
weights = np.random.random(num_assets) | ||
weights = weights/sum(weights) | ||
port_weights.append(weights) | ||
df_wts_returns = dd_returns.mean().dot(weights) | ||
port_returns.append(df_wts_returns*100) | ||
|
||
var_port_95 = sim_portfolio(weights, dd_returns) | ||
port_volatility.append(var_port_95) | ||
|
||
|
||
port_weights = [wt for wt in port_weights] | ||
dff = {'Returns': port_returns, 'Risk': port_volatility, 'Weights': port_weights} | ||
df_risk = pd.DataFrame(dff) | ||
|
||
min_risk = df_risk.iloc[df_risk['Risk'].idxmax()] | ||
|
||
# low_risk_return = f'{round(abs(min_risk[0]),4)*100:.2f}' | ||
# low_risk_volatility = f'{round(abs(min_risk[1]),4)*100:.2f}' | ||
low_risk_return = f'{round((min_risk[0]),4)*100:.2f}' | ||
low_risk_volatility = f'{round((min_risk[1]),4)*100:.2f}' | ||
low_risk_wts = min_risk[2] | ||
|
||
print(f'{low_risk_volatility} and {low_risk_return}') | ||
|
||
|
||
max_risk = df_risk.iloc[df_risk['Risk'].idxmin()] | ||
# high_risk_return = f'{round(abs(max_risk[0]),4)*100:.2f}' | ||
# high_risk_volatility = f'{round(abs(max_risk[1]),4)*100:.2f}' | ||
high_risk_return = f'{round((max_risk[0]),4)*100:.2f}' | ||
high_risk_volatility = f'{round((max_risk[1]),4)*100:.2f}' | ||
high_risk_wts = max_risk[2] | ||
|
||
print(f'{high_risk_volatility} and {high_risk_return}') | ||
|
||
return low_risk_wts, high_risk_wts, low_risk_return,low_risk_volatility, high_risk_return, high_risk_volatility, df_risk | ||
|
||
except Exception as e: | ||
print(f'An exception occurred while executing sim_bootstrap: {e}') |
Oops, something went wrong.