Professional Documents
Culture Documents
[1]:
!pip install yfinance --upgrade --no-cache-dir -q > /dev/null 2>&1
In [2]:
!pip install jupyter-dash==0.4.1 -q > /dev/null 2>&1
In [3]:
!pip install jupyter-dash -q > /dev/null 2>&1
In [4]:
!pip install "notebook>=5.3" "ipywidgets>=7.5" -q > /dev/null 2>&1
In [5]:
!pip install dash-bootstrap-components -q > /dev/null 2>&1
In [6]:
!pip install dash-table -q > /dev/null 2>&1
In [7]:
!pip install copulas -q > /dev/null 2>&1
In [8]:
!pip install dash-bootstrap-templates -q > /dev/null 2>&1
In [9]:
!pip install pandas-datareader -q > /dev/null 2>&1
In [10]:
import pandas as pd
import numpy as np
import datetime as dt
import yfinance as yf
import plotly.express as px
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
from datetime import datetime, timedelta
from scipy.stats import norm, multivariate_normal
from jupyter_dash import JupyterDash
#Additionnal imports
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import dash_bootstrap_templates as dbt
import plotly.graph_objs as go
from dash import dash_table
from scipy.stats import norm, gaussian_kde
from copulas.bivariate import Frank, Gumbel, Clayton
from statsmodels.distributions.empirical_distribution import ECDF
import pandas_datareader as pdr
import plotly.figure_factory as ff
This code should download the historical stock prices for all the companies in the S&P500 for the last 10 years and store the data in a pandas dataframe called data. You can then use this dataframe to build your app.
In [11]:
# Define the date range
end_date = datetime.today().strftime('%Y-%m-%d')
start_date = (datetime.today() - timedelta(days=365 * 10)).strftime('%Y-%m-%d')
sp500_symbols = get_sp500_symbols()
stock_data_cache = None
def get_risk_free_rate():
try:
end_date = datetime.today()
start_date = end_date - pd.Timedelta(days=365)
risk_free_rate_data = pdr.get_data_fred('GS3M', start_date, end_date)
return risk_free_rate_data.iloc[-1].item() / 100 # Convert to decimal
except Exception as e:
print(f"Error fetching risk-free rate: {e}")
return 0.02 # Default risk-free rate if fetching fails
2 Failed downloads:
- BRK.B: No timezone found, symbol may be delisted
- BF.B: No data found for this date range, symbol may be delisted
This code first calculates the percentage change in adjusted closing prices for each stock using the pct_change() function, and then drops the first row which will be NaN. The resulting DataFrame sp500_returns will contain the daily returns for each
stock in the S&P500.
In [12]:
# Calculate the daily returns for all the stocks in the S&P500
def get_stock_log_returns(portfolio, start_date, end_date):
stock_data = get_stock_data(portfolio, start_date=start_date, end_date=end_date)
stock_log_returns = np.log(stock_data / stock_data.shift(1)).dropna()
return stock_log_returns[portfolio]
In [13]:
# Define the benchmark portfolio
benchmark_portfolio = sp500_symbols
# Calculate benchmark_log_returns
benchmark_log_returns = sp500_index_log_returns.copy()
benchmark_log_returns_filtered = sp500_index_log_returns.loc[start_date:end_date]
[*********************100%***********************] 1 of 1 completed
Code pour tout ce qui est weight related
In [14]:
# Add this function to calculate equal weights
def equal_weights(n):
return np.ones(n) / n
In [15]:
def rolling_correlation(portfolio_log_returns, benchmark_log_returns, window=30):
df = pd.concat([portfolio_log_returns, benchmark_log_returns], axis=1)
df.columns = ["portfolio", "benchmark"]
rolling_corr = df.rolling(window=window).corr().xs("portfolio", level=1, drop_level=True)["benchmark"]
return rolling_corr
In [16]:
# Calculate the VaR and ES for a portfolio
def calculate_var_es(portfolio_returns, alpha=0.05):
if not portfolio_returns.empty:
mu = np.mean(portfolio_returns)
sigma = np.std(portfolio_returns)
z_score = norm.ppf(alpha)
var = -1 * (mu - z_score * sigma)
es = -1 * (mu + (sigma / alpha) * norm.pdf(z_score))
return round(var, 4), round(es, 4)
else:
return 0, 0
In [17]:
def transform_to_uniform(data):
transformed_data = pd.DataFrame(index=data.index)
for column in data.columns:
ecdf = ECDF(data[column])
transformed_data[column] = ecdf(data[column])
return transformed_data
In [18]:
def create_chart(portfolio_cumulative_returns, benchmark_cumulative_returns):
fig = go.Figure()
fig.add_trace(go.Scatter(x=portfolio_cumulative_returns.index, y= portfolio_cumulative_returns,
mode='lines', name='Portfolio Returns'))
fig.add_trace(go.Scatter(x=benchmark_cumulative_returns.index, y=benchmark_cumulative_returns,
mode='lines', name='Benchmark Returns', line=dict(color='red')))
fig.update_layout(title='Portfolio and Benchmark Returns Over Time',
xaxis_title='Date',
yaxis_title='Returns',
yaxis_tickformat=".0%",
showlegend=True)
return fig
fig = ff.create_distplot(
hist_data,
group_labels,
bin_size=[bin_size], # Provide the bin size as a list
histnorm="probability density",
show_hist=False,
show_rug=False,
)
fig.update_layout(
title=title,
xaxis_title="Returns",
)
fig.add_shape(
type="line",
x0=var,
x1=var,
y0=0,
y1=1,
yref="paper",
line=dict(color="red", width=2),
)
fig.add_shape(
type="line",
x0=es,
x1=es,
y0=0,
y1=1,
yref="paper",
line=dict(color="orange", width=2),
)
fig.update_layout(
showlegend=True,
legend=dict(
x=1,
y=1,
bgcolor="rgba(255, 255, 255, 0.5)",
bordercolor="rgba(255, 255, 255, 0.5)",
),
)
return fig
def create_copula_chart(copula):
copula_sample = copula.sample(500).T
fig = go.Figure()
fig.add_trace(go.Scatter(x=copula_sample[0], y=copula_sample[1], mode='markers', name='Copula'))
fig.update_layout(title='Copula Scatter Plot', xaxis_title='X', yaxis_title='Y')
return fig
Frontend stuff
In [19]:
# Define a CSS class with black text color
dropdown_style1 = {
'color': 'black',
'width': '40%',
'border-radius': '50px',
'margin-left': '5px',
'margin-bottom': '5px',
'margin-top': '-75px'
}
button_style1 = {
'backgroundColor': 'transparent',
'color': 'white',
'border': '2px solid white',
'border-radius': '50px',
'margin-right': '545px'
}
button_style2 = {
'backgroundColor': 'transparent',
'color': 'white',
'border': '2px solid white',
'border-radius': '50px',
'margin-right': '0px',
'margin-top': '-90px'
}
case_style = {
'width': '20%',
'backgroundColor': 'white',
'color': 'black',
'border': '2px solid white',
'border-radius': '50px',
'margin-right': '10px',
'margin-top': '-90px',
'text-align': 'center', # Add this line to center the placeholder text
'justify-content': 'center' # Add this line to center the input content
}
Put a dropdown menu allowing the user to select stocks from S&P500
Make an ADD button allowing the user to add them to his portfolio
Put a date dropdown menu to let the user choose the timeframe for his portfolio
Show portfolio returns over time on a graph
In [ ]:
# Initialize the app with the chosen theme
app = JupyterDash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.QUARTZ])
dcc.Dropdown(
id='stock-dropdown',
options=[{'label': ticker, 'value': ticker} for ticker in sp500_symbols],
style=dropdown_style1,
value=None,
),
dcc.DatePickerRange(
id='date-picker-range',
min_date_allowed=(datetime.today() - timedelta(days=365 * 10)).date(),
max_date_allowed=datetime.today().date(),
start_date=datetime.today().date() - timedelta(days=365),
end_date=datetime.today().date(),
display_format='YYYY-MM-DD',
persistence=True,
persisted_props=['start_date', 'end_date'],
style={'margin-right': '10px', 'margin-left': '5px', 'border-radius': '50px', 'margin-bottom': '5px', 'font-family': 'Castellar'}
),
html.Button('Add to Portfolio', id='add-button', n_clicks=0, style=button_style1),
dcc.Input(
id='investment-input',
type='number',
placeholder='Enter investment amount',
style=case_style
),
html.Button('Confirm Investment', id='confirm-investment-button', n_clicks=0,
style=button_style2),
dcc.Store(id='confirmed-investment-store', data=None),
html.Div(id='investment-output'),
dcc.Store(id='portfolio-store', data=[]),
html.Div(id='portfolio', children=[]),
dcc.Dropdown(
id='weighting-method-dropdown',
options=[
{'label': 'Equally Weighted', 'value': 'equal'},
{'label': 'Global Minimum Variance', 'value': 'min_variance'},
{'label': 'Maximum Sharpe Ratio', 'value': 'max_sharpe'}
],
style=dropdown_style2,
value='equal'),
dash_table.DataTable(
id='weights-table',
columns=[
{"name": "Stock", "id": "Stock"},
{"name": "Weight", "id": "Weight"},
],
style_header={
'backgroundColor': 'white',
'color': 'black', 'text-align': 'center'
},
style_data={
'color': 'black', 'text-align': 'center'},
),
dcc.Graph(id='portfolio-returns-chart'),
dcc.Graph(id='rolling-correlation-chart'),
dcc.Dropdown(
id='copula-dropdown',
options=[
{'label': 'Frank Copula', 'value': 'frank'},
{'label': 'Gumbel Copula', 'value': 'gumbel'},
{'label': 'Clayton Copula', 'value': 'clayton'}
],
style=dropdown_style2,
value='gumbel'),
dcc.Graph(id='copula-chart'),
dcc.Graph(id='portfolio-density-plot'),
dcc.Graph(id='benchmark-density-plot'),
])
@app.callback(
[
Output("portfolio", "children"),
Output("portfolio-returns-chart", "figure"),
Output("portfolio-density-plot", "figure"),
Output("benchmark-density-plot", "figure"),
Output("investment-output", "children"),
Output("rolling-correlation-chart", "figure"),
Output("weights-table", "data"),
Output('copula-chart', 'figure'),
],
[
Input("portfolio-store", "data"),
Input("date-picker-range", "start_date"),
Input("date-picker-range", "end_date"),
Input("weighting-method-dropdown", "value"),
Input("copula-dropdown", "value"),
Input('confirm-investment-button', 'n_clicks') # Add the new button as input
],
[
State("investment-input", "value"),
State('confirmed-investment-store', 'data'), # Add the confirmed investment state
],
prevent_initial_call=True
)
start_date = pd.Timestamp(start_date)
end_date = pd.Timestamp(end_date)
risk_free_rate = get_risk_free_rate() # Fetch the risk-free rate
if weighting_method == 'equal':
portfolio_weights = equal_weights(len(portfolio))
elif weighting_method == 'min_variance':
portfolio_weights = global_minimum_variance_weights(stock_cov_matrix)
elif weighting_method == 'max_sharpe':
portfolio_weights = maximum_sharpe_ratio_weights(stock_log_returns, stock_cov_matrix)
copula_chart = create_copula_chart(copula)
return (
portfolio_div,
returns_fig,
density_fig,
benchmark_density_fig,
investment_output,
rolling_corr_fig,
weights_table.to_dict("records"),
copula_chart,
)
else:
return [], {}, {}, {}, 'Please add stocks to the portfolio.', {}, []
In [ ]:
JupyterDash.infer_jupyter_proxy_config()
app.run_server(port=2225)
In [ ]:
In [ ]: