QuantumLearner commited on
Commit
07f488d
·
verified ·
1 Parent(s): dab3afb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +164 -163
app.py CHANGED
@@ -13,10 +13,10 @@ def fetch_stock_data(ticker: str, start_date: str, end_date: str) -> pd.DataFram
13
  return yf.download(ticker, start=start_date, end=end_date)
14
 
15
  # Helper function to plot rolling volatility and volatility of volatility
16
- def plot_rolling_volatility(data: pd.DataFrame) -> go.Figure:
17
  data['Return'] = data['Close'].pct_change()
18
- data['Rolling_Volatility'] = data['Return'].rolling(window=21).std() * np.sqrt(252)
19
- data['Vol_of_Vol'] = data['Rolling_Volatility'].rolling(window=21).std()
20
 
21
  fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.1,
22
  subplot_titles=('Close Price', 'Rolling Volatility', 'Volatility of Volatility'))
@@ -29,9 +29,9 @@ def plot_rolling_volatility(data: pd.DataFrame) -> go.Figure:
29
  return fig
30
 
31
  # Helper function to plot rolling Sharpe ratio
32
- def plot_rolling_sharpe(data: pd.DataFrame) -> go.Figure:
33
  data['Return'] = data['Close'].pct_change()
34
- rolling_sharpe = np.sqrt(252) * data['Return'].rolling(252).mean() / data['Return'].rolling(252).std()
35
 
36
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
37
  subplot_titles=('Close Price', 'Rolling Sharpe Ratio'))
@@ -40,23 +40,21 @@ def plot_rolling_sharpe(data: pd.DataFrame) -> go.Figure:
40
  fig.add_trace(go.Scatter(x=data.index, y=rolling_sharpe, mode='lines', name='Rolling Sharpe Ratio', line=dict(color='green')), row=2, col=1)
41
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
42
 
43
- fig.update_layout(title='Rolling 1-Year Sharpe Ratio with Stock Price', xaxis_title='Date')
44
  return fig
45
 
46
  # Helper function to plot rolling Treynor ratio
47
- # Helper function to calculate and plot rolling Treynor Ratio
48
- def plot_rolling_treynor(data: pd.DataFrame, market_data: pd.DataFrame, window_size: int = 252) -> go.Figure:
49
  data['Return'] = data['Close'].pct_change()
50
  market_data['Return'] = market_data['Close'].pct_change()
51
 
52
  # Align indices
53
  market_data = market_data.reindex(data.index, method='ffill')
54
 
55
- covariance = data['Return'].rolling(window=window_size).cov(market_data['Return'])
56
- variance = market_data['Return'].rolling(window=window_size).var()
57
  rolling_beta = covariance / variance
58
- avg_rolling_returns = data['Return'].rolling(window=window_size).mean()
59
- risk_free_rate = 0
60
  data['Rolling_Treynor_Ratio'] = (avg_rolling_returns - risk_free_rate) / rolling_beta
61
 
62
  fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.1,
@@ -66,11 +64,11 @@ def plot_rolling_treynor(data: pd.DataFrame, market_data: pd.DataFrame, window_s
66
  fig.add_trace(go.Scatter(x=market_data.index, y=market_data['Close'], mode='lines', name='Benchmark Price', line=dict(color='blue')), row=2, col=1)
67
  fig.add_trace(go.Scatter(x=data.index, y=data['Rolling_Treynor_Ratio'], mode='lines', name='Rolling Treynor Ratio', line=dict(color='red')), row=3, col=1)
68
 
69
- fig.update_layout(title='Rolling 1-Year Treynor Ratio with Stock Price and Benchmark', xaxis_title='Date')
70
  return fig
71
-
72
  # Helper function to calculate and plot rolling beta
73
- def plot_rolling_beta(data: pd.DataFrame, market_data: pd.DataFrame, window: int = 60) -> go.Figure:
74
  data['Return'] = data['Close'].pct_change().dropna()
75
  market_data['Market_Return'] = market_data['Close'].pct_change().dropna()
76
 
@@ -106,26 +104,25 @@ def plot_rolling_beta(data: pd.DataFrame, market_data: pd.DataFrame, window: int
106
  fig.add_trace(go.Scatter(x=rolling_beta_ransac.index, y=rolling_beta_ransac, mode='lines', name='Rolling Beta (RANSAC)', line=dict(color='red')), row=3, col=1)
107
  fig.add_trace(go.Scatter(x=rolling_beta_ols.index, y=rolling_beta_ols, mode='lines', name='Rolling Beta (OLS)', line=dict(color='green')), row=3, col=1)
108
 
109
- fig.update_layout(title='Rolling 1-Year Beta with Stock Price and Benchmark', xaxis_title='Date')
110
  return fig
111
 
112
  # Helper function to plot rolling Jensen's alpha
113
- def plot_rolling_alpha(data: pd.DataFrame, market_data: pd.DataFrame) -> go.Figure:
114
  data['Return'] = data['Close'].pct_change()
115
  market_data['Return'] = market_data['Close'].pct_change()
116
 
117
- window_size = 252
118
  rolling_alpha = []
119
 
120
- for i in range(len(data) - window_size):
121
- window = data['Return'].iloc[i:i + window_size]
122
- market_window = market_data['Return'].iloc[i:i + window_size]
123
- beta = window.cov(market_window) / market_window.var()
124
- expected_return = beta * market_window.mean()
125
- alpha = window.mean() - expected_return
126
  rolling_alpha.append(alpha)
127
 
128
- rolling_alpha = pd.Series(rolling_alpha, index=data.index[window_size:])
129
 
130
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
131
  subplot_titles=('Close Price', 'Rolling Jensen\'s Alpha'))
@@ -133,15 +130,15 @@ def plot_rolling_alpha(data: pd.DataFrame, market_data: pd.DataFrame) -> go.Figu
133
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
134
  fig.add_trace(go.Scatter(x=rolling_alpha.index, y=rolling_alpha, mode='lines', name='Rolling Jensen\'s Alpha', line=dict(color='green')), row=2, col=1)
135
 
136
- fig.update_layout(title='Rolling 1-Year Jensen\'s Alpha with Stock Price', xaxis_title='Date')
137
  return fig
138
 
139
  # Helper function to plot rolling Value at Risk (VaR)
140
- def plot_rolling_var(data: pd.DataFrame) -> go.Figure:
141
  data['Return'] = data['Close'].pct_change()
142
- rolling_var_90 = data['Return'].rolling(252).quantile(0.10).dropna()
143
- rolling_var_95 = data['Return'].rolling(252).quantile(0.05).dropna()
144
- rolling_var_97 = data['Return'].rolling(252).quantile(0.03).dropna()
145
 
146
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
147
  subplot_titles=('Close Price', 'Rolling VaR'))
@@ -151,20 +148,20 @@ def plot_rolling_var(data: pd.DataFrame) -> go.Figure:
151
  fig.add_trace(go.Scatter(x=rolling_var_95.index, y=rolling_var_95, mode='lines', name='Rolling VaR 95%', line=dict(color='blue')), row=2, col=1)
152
  fig.add_trace(go.Scatter(x=rolling_var_97.index, y=rolling_var_97, mode='lines', name='Rolling VaR 97%', line=dict(color='purple')), row=2, col=1)
153
 
154
- fig.update_layout(title='Rolling 1-Year VaR with Stock Price', xaxis_title='Date')
155
  return fig
156
 
157
  # Helper function to plot rolling Conditional VaR (CVaR)
158
- def plot_rolling_cvar(data: pd.DataFrame) -> go.Figure:
159
  data['Return'] = data['Close'].pct_change()
160
 
161
  def conditional_var(x, alpha=0.05):
162
  var = np.percentile(x, alpha * 100)
163
  return np.mean(x[x < var])
164
 
165
- rolling_cvar_95 = data['Return'].rolling(252).apply(conditional_var, raw=True).dropna()
166
- rolling_cvar_90 = data['Return'].rolling(252).apply(lambda x: conditional_var(x, alpha=0.1), raw=True).dropna()
167
- rolling_cvar_97 = data['Return'].rolling(252).apply(lambda x: conditional_var(x, alpha=0.03), raw=True).dropna()
168
 
169
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
170
  subplot_titles=('Close Price', 'Rolling CVaR'))
@@ -174,13 +171,13 @@ def plot_rolling_cvar(data: pd.DataFrame) -> go.Figure:
174
  fig.add_trace(go.Scatter(x=rolling_cvar_90.index, y=rolling_cvar_90, mode='lines', name='Rolling CVaR 90%', line=dict(color='green')), row=2, col=1)
175
  fig.add_trace(go.Scatter(x=rolling_cvar_97.index, y=rolling_cvar_97, mode='lines', name='Rolling CVaR 97%', line=dict(color='orange')), row=2, col=1)
176
 
177
- fig.update_layout(title='Rolling 1-Year CVaR with Stock Price', xaxis_title='Date')
178
  return fig
179
 
180
  # Helper function to plot rolling Tail Ratio
181
- def plot_rolling_tail_ratio(data: pd.DataFrame) -> go.Figure:
182
  data['Return'] = data['Close'].pct_change()
183
- tail_ratio = data['Return'].rolling(252).apply(lambda x: np.abs(np.percentile(x, 95)) / np.abs(np.percentile(x, 5))).dropna()
184
 
185
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
186
  subplot_titles=('Close Price', 'Rolling Tail Ratio'))
@@ -189,14 +186,14 @@ def plot_rolling_tail_ratio(data: pd.DataFrame) -> go.Figure:
189
  fig.add_trace(go.Scatter(x=tail_ratio.index, y=tail_ratio, mode='lines', name='Tail Ratio', line=dict(color='purple')), row=2, col=1)
190
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
191
 
192
- fig.update_layout(title='Rolling 1-Year Tail Ratio with Stock Price', xaxis_title='Date')
193
  return fig
194
 
195
  # Helper function to plot rolling Omega Ratio
196
- def plot_rolling_omega(data: pd.DataFrame) -> go.Figure:
197
  data['Return'] = data['Close'].pct_change()
198
  MAR = 0 # Minimum Acceptable Return
199
- omega_ratio = data['Return'].rolling(252).apply(lambda x: np.sum(x[x > MAR] - MAR) / np.sum(MAR - x[x < MAR])).dropna()
200
 
201
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
202
  subplot_titles=('Close Price', 'Rolling Omega Ratio'))
@@ -205,14 +202,13 @@ def plot_rolling_omega(data: pd.DataFrame) -> go.Figure:
205
  fig.add_trace(go.Scatter(x=omega_ratio.index, y=omega_ratio, mode='lines', name='Omega Ratio', line=dict(color='green')), row=2, col=1)
206
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
207
 
208
- fig.update_layout(title='Rolling 1-Year Omega Ratio with Stock Price', xaxis_title='Date')
209
  return fig
210
 
211
  # Helper function to plot rolling Sortino Ratio
212
- def plot_rolling_sortino(data: pd.DataFrame) -> go.Figure:
213
  data['Return'] = data['Close'].pct_change()
214
- MAR = 0 # Minimum Acceptable Return
215
- sortino_ratio = data['Return'].rolling(252).apply(lambda x: np.mean(x - MAR) / np.sqrt(np.mean(np.minimum(0, x - MAR) ** 2))).dropna()
216
 
217
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
218
  subplot_titles=('Close Price', 'Rolling Sortino Ratio'))
@@ -220,13 +216,13 @@ def plot_rolling_sortino(data: pd.DataFrame) -> go.Figure:
220
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
221
  fig.add_trace(go.Scatter(x=sortino_ratio.index, y=sortino_ratio, mode='lines', name='Sortino Ratio', line=dict(color='green')), row=2, col=1)
222
 
223
- fig.update_layout(title='Rolling 1-Year Sortino Ratio with Stock Price', xaxis_title='Date')
224
  return fig
225
 
226
  # Helper function to plot rolling Calmar Ratio
227
- def plot_rolling_calmar(data: pd.DataFrame) -> go.Figure:
228
  data['Return'] = data['Close'].pct_change()
229
- calmar_ratio = data['Return'].rolling(252).apply(lambda x: (1 + x).cumprod()[-1] ** (252.0 / len(x)) / np.abs(np.min((1 + x).cumprod() / (1 + x).cumprod().cummax()) - 1)).dropna()
230
 
231
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
232
  subplot_titles=('Close Price', 'Rolling Calmar Ratio'))
@@ -234,13 +230,13 @@ def plot_rolling_calmar(data: pd.DataFrame) -> go.Figure:
234
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
235
  fig.add_trace(go.Scatter(x=calmar_ratio.index, y=calmar_ratio, mode='lines', name='Calmar Ratio', line=dict(color='green')), row=2, col=1)
236
 
237
- fig.update_layout(title='Rolling 1-Year Calmar Ratio with Stock Price', xaxis_title='Date')
238
  return fig
239
 
240
  # Helper function to plot rolling stability
241
- def plot_rolling_stability(data: pd.DataFrame) -> go.Figure:
242
  data['Return'] = data['Close'].pct_change()
243
- stability = data['Return'].rolling(252).apply(lambda x: np.std(np.log1p(x).cumsum() - linregress(np.arange(len(x)), np.log1p(x).cumsum()).intercept - linregress(np.arange(len(x)), np.log1p(x).cumsum()).slope * np.arange(len(x)))).dropna()
244
 
245
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
246
  subplot_titles=('Close Price', 'Rolling Stability'))
@@ -248,14 +244,14 @@ def plot_rolling_stability(data: pd.DataFrame) -> go.Figure:
248
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
249
  fig.add_trace(go.Scatter(x=stability.index, y=stability, mode='lines', name='Stability', line=dict(color='purple')), row=2, col=1)
250
 
251
- fig.update_layout(title='Rolling 1-Year Stability of Returns with Stock Price', xaxis_title='Date')
252
  return fig
253
 
254
  # Helper function to plot rolling maximum drawdown
255
- def plot_rolling_drawdown(data: pd.DataFrame) -> go.Figure:
256
  data['Return'] = data['Close'].pct_change()
257
  rolling_cumulative = (1 + data['Return']).cumprod()
258
- rolling_max = rolling_cumulative.rolling(252, min_periods=1).max()
259
  rolling_drawdown = (rolling_cumulative - rolling_max) / rolling_max
260
 
261
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
@@ -264,11 +260,11 @@ def plot_rolling_drawdown(data: pd.DataFrame) -> go.Figure:
264
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
265
  fig.add_trace(go.Scatter(x=rolling_drawdown.index, y=rolling_drawdown, mode='lines', name='Maximum Drawdown', line=dict(color='red')), row=2, col=1)
266
 
267
- fig.update_layout(title='Rolling 1-Year Maximum Drawdown with Stock Price', xaxis_title='Date')
268
  return fig
269
 
270
  # Helper function to calculate and plot rolling capture ratios
271
- def plot_rolling_capture(data: pd.DataFrame, market_data: pd.DataFrame, window_size: int = 252) -> go.Figure:
272
  data['Return'] = data['Close'].pct_change()
273
  market_data['Return'] = market_data['Close'].pct_change()
274
 
@@ -310,7 +306,7 @@ def plot_rolling_capture(data: pd.DataFrame, market_data: pd.DataFrame, window_s
310
  return upside_captures, downside_captures
311
 
312
  data['rolling_upside_capture'], data['rolling_downside_capture'] = compute_rolling_captures(
313
- data['Return'], market_data['Return'], window_size
314
  )
315
 
316
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
@@ -320,17 +316,16 @@ def plot_rolling_capture(data: pd.DataFrame, market_data: pd.DataFrame, window_s
320
  fig.add_trace(go.Scatter(x=data.index, y=data['rolling_upside_capture'], mode='lines', name='Rolling Upside Capture', line=dict(color='green')), row=2, col=1)
321
  fig.add_trace(go.Scatter(x=data.index, y=data['rolling_downside_capture'], mode='lines', name='Rolling Downside Capture', line=dict(color='red')), row=2, col=1)
322
 
323
- fig.update_layout(title='Rolling 1-Year Capture Ratios with Stock Price', xaxis_title='Date')
324
  return fig
325
 
326
-
327
  # Helper function to plot rolling Pain Index
328
- def plot_rolling_pain_index(data: pd.DataFrame) -> go.Figure:
329
  data['Return'] = data['Close'].pct_change()
330
  cumulative_return = (1 + data['Return']).cumprod()
331
  running_max = cumulative_return.cummax()
332
  drawdown = (cumulative_return - running_max) / running_max
333
- pain_index = drawdown.rolling(252).apply(lambda x: np.mean(x[x < 0])).dropna()
334
 
335
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
336
  subplot_titles=('Close Price', 'Rolling Pain Index'))
@@ -338,7 +333,7 @@ def plot_rolling_pain_index(data: pd.DataFrame) -> go.Figure:
338
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
339
  fig.add_trace(go.Scatter(x=pain_index.index, y=pain_index, mode='lines', name='Pain Index', line=dict(color='red')), row=2, col=1)
340
 
341
- fig.update_layout(title='Rolling 1-Year Pain Index with Stock Price', xaxis_title='Date')
342
  return fig
343
 
344
  # Streamlit app
@@ -356,6 +351,7 @@ st.sidebar.header("Input Parameters")
356
  ticker = st.sidebar.text_input('Enter Stock Ticker', 'VOW.DE')
357
  start_date = st.sidebar.date_input('Start Date', pd.to_datetime('2010-01-01'))
358
  end_date = st.sidebar.date_input('End Date', pd.to_datetime('2024-12-31'))
 
359
 
360
  # Fetch data
361
  if 'data' not in st.session_state or st.sidebar.button('Fetch Data'):
@@ -363,14 +359,19 @@ if 'data' not in st.session_state or st.sidebar.button('Fetch Data'):
363
 
364
  data = st.session_state.data
365
 
366
- # Additional input for Rolling Treynor Ratio, Rolling Beta, Rolling Jensen's Alpha, Rolling Capture Ratios
367
  if selected in ["Rolling Treynor Ratio", "Rolling Beta", "Rolling Jensen's Alpha", "Rolling Capture Ratios"]:
368
  benchmark_ticker = st.sidebar.text_input('Enter Benchmark Ticker', '^GSPC')
369
  if 'market_data' not in st.session_state or st.sidebar.button('Fetch Market Data'):
370
  st.session_state.market_data = fetch_stock_data(benchmark_ticker, start_date, end_date)
371
-
372
  market_data = st.session_state.market_data
373
 
 
 
 
 
 
 
374
  # Display results based on the selected method
375
  if selected == "Rolling Volatility":
376
  st.markdown("""
@@ -390,16 +391,16 @@ if selected == "Rolling Volatility":
390
  where \( P_t \) is the closing price at time \( t \).
391
 
392
  2. **Calculate Rolling Volatility:**
393
- - Compute the rolling standard deviation of the returns over a specified window (e.g., 21 days) and annualize it:
394
  """)
395
  st.latex(r'''
396
  \text{Rolling Volatility}_t = \sqrt{252} \times \text{std}(\text{Return}_{t-n:t})
397
  ''')
398
  st.markdown("""
399
- where \( n \) is the window size (e.g., 21 days).
400
 
401
  3. **Calculate Volatility of Volatility:**
402
- - Compute the rolling standard deviation of the rolling volatility over a specified window (e.g., 21 days):
403
  """)
404
  st.latex(r'''
405
  \text{Volatility of Volatility}_t = \text{std}(\text{Rolling Volatility}_{t-n:t})
@@ -408,18 +409,19 @@ if selected == "Rolling Volatility":
408
  st.markdown("""
409
  **How to use:**
410
  1. Enter the stock ticker, start date, and end date.
411
- 2. Click 'Fetch Data' to load the stock data.
412
- 3. The chart will display the rolling volatility and the volatility of volatility.
 
413
  """)
414
 
415
- fig = plot_rolling_volatility(data)
416
  st.plotly_chart(fig)
417
 
418
  elif selected == "Rolling Sharpe Ratio":
419
  st.markdown("""
420
  ### Rolling Sharpe Ratio
421
 
422
- This method calculates the rolling 1-year Sharpe Ratio.
423
 
424
  **Methodology:**
425
 
@@ -433,44 +435,44 @@ elif selected == "Rolling Sharpe Ratio":
433
  where \( P_t \) is the closing price at time \( t \).
434
 
435
  2. **Calculate Rolling Average Return:**
436
- - Compute the rolling mean of the returns over a 1-year period (252 trading days):
437
  """)
438
  st.latex(r'''
439
- \text{Rolling Average Return}_t = \text{mean}(\text{Return}_{t-252:t})
440
  ''')
441
  st.markdown("""
442
 
443
  3. **Calculate Rolling Standard Deviation:**
444
- - Compute the rolling standard deviation of the returns over a 1-year period:
445
  """)
446
  st.latex(r'''
447
- \text{Rolling Std Dev}_t = \text{std}(\text{Return}_{t-252:t})
448
  ''')
449
  st.markdown("""
450
 
451
  4. **Calculate Rolling Sharpe Ratio:**
452
- - Annualize the Sharpe Ratio by multiplying by the square root of 252:
453
  """)
454
  st.latex(r'''
455
- \text{Rolling Sharpe Ratio}_t = \frac{\text{Rolling Average Return}_t}{\text{Rolling Std Dev}_t} \times \sqrt{252}
456
  ''')
457
  st.markdown("""
458
 
459
  **How to use:**
460
  1. Enter the stock ticker, start date, and end date.
461
- 2. Click 'Fetch Data' to load the stock data.
462
- 3. The chart will display the rolling Sharpe Ratio.
 
463
  """)
464
 
465
- fig = plot_rolling_sharpe(data)
466
  st.plotly_chart(fig)
467
 
468
-
469
  elif selected == "Rolling Treynor Ratio":
470
  st.markdown("""
471
  ### Rolling Treynor Ratio
472
 
473
- This method calculates the rolling 1-year Treynor Ratio.
474
 
475
  **Methodology:**
476
 
@@ -490,7 +492,7 @@ elif selected == "Rolling Treynor Ratio":
490
  \beta_t = \frac{\text{Cov}(\text{Return}_{\text{stock}, t}, \text{Return}_{\text{benchmark}, t})}{\text{Var}(\text{Return}_{\text{benchmark}, t})}
491
  ''')
492
  st.markdown("""
493
- where the rolling window size is typically 252 days for 1-year calculations.
494
 
495
  3. **Calculate Average Rolling Returns:**
496
  - Compute the rolling mean of the stock returns over the same window:
@@ -499,10 +501,10 @@ elif selected == "Rolling Treynor Ratio":
499
  \text{Average Rolling Return}_t = \frac{1}{n} \sum_{i=t-n+1}^{t} \text{Return}_{\text{stock}, i}
500
  ''')
501
  st.markdown("""
502
- where \( n \) is the window size (e.g., 252 days).
503
 
504
  4. **Calculate Treynor Ratio:**
505
- - Compute the Treynor Ratio using the risk-free rate \( R_f \) (assumed to be 0 here for simplicity):
506
  """)
507
  st.latex(r'''
508
  \text{Treynor Ratio}_t = \frac{\text{Average Rolling Return}_t - R_f}{\beta_t}
@@ -512,12 +514,12 @@ elif selected == "Rolling Treynor Ratio":
512
 
513
  **How to use:**
514
  1. Enter the stock ticker, start date, and end date.
515
- 2. Enter the benchmark ticker.
516
  3. Click 'Fetch Data' to load the stock and benchmark data.
517
  4. The chart will display the rolling Treynor Ratio.
518
  """)
519
 
520
- fig = plot_rolling_treynor(data, market_data)
521
  st.plotly_chart(fig)
522
 
523
  elif selected == "Rolling Beta":
@@ -538,13 +540,13 @@ elif selected == "Rolling Beta":
538
  where \( P_t \) is the closing price at time \( t \).
539
 
540
  2. **Calculate Rolling Beta using OLS:**
541
- - Perform a linear regression of the stock returns against the benchmark returns over a specified window (e.g., 60 days):
542
  """)
543
  st.latex(r'''
544
  \beta_{OLS} = \frac{\text{Cov}(\text{Return}_{\text{stock}}, \text{Return}_{\text{benchmark}})}{\text{Var}(\text{Return}_{\text{benchmark}})}
545
  ''')
546
  st.markdown("""
547
- where the rolling window size is typically 60 days.
548
 
549
  3. **Calculate Rolling Beta using RANSAC:**
550
  - Use the RANSAC algorithm to robustly estimate the beta, reducing the influence of outliers:
@@ -557,19 +559,19 @@ elif selected == "Rolling Beta":
557
 
558
  **How to use:**
559
  1. Enter the stock ticker, start date, and end date.
560
- 2. Enter the benchmark ticker.
561
  3. Click 'Fetch Data' to load the stock and benchmark data.
562
  4. The chart will display the rolling beta calculated using both OLS and RANSAC methods.
563
  """)
564
 
565
- fig = plot_rolling_beta(data, market_data)
566
  st.plotly_chart(fig)
567
 
568
  elif selected == "Rolling Jensen's Alpha":
569
  st.markdown("""
570
  ### Rolling Jensen's Alpha
571
 
572
- This method calculates the rolling 1-year Jensen's Alpha.
573
 
574
  **Methodology:**
575
 
@@ -583,13 +585,13 @@ elif selected == "Rolling Jensen's Alpha":
583
  where \( P_t \) is the closing price at time \( t \).
584
 
585
  2. **Calculate Beta:**
586
- - Compute the rolling beta of the stock returns against the benchmark returns over a specified window (e.g., 252 days):
587
  """)
588
  st.latex(r'''
589
  \beta_t = \frac{\text{Cov}(\text{Return}_{\text{stock}, t}, \text{Return}_{\text{benchmark}, t})}{\text{Var}(\text{Return}_{\text{benchmark}, t})}
590
  ''')
591
  st.markdown("""
592
- where the rolling window size is typically 252 days for 1-year calculations.
593
 
594
  3. **Calculate Expected Return:**
595
  - Compute the expected return of the stock based on the CAPM model:
@@ -598,7 +600,7 @@ elif selected == "Rolling Jensen's Alpha":
598
  \text{Expected Return}_t = R_f + \beta_t (\text{Return}_{\text{benchmark}} - R_f)
599
  ''')
600
  st.markdown("""
601
- where \( R_f \) is the risk-free rate (assumed to be 0 here for simplicity).
602
 
603
  4. **Calculate Jensen's Alpha:**
604
  - Compute the Jensen's Alpha as the difference between the actual return and the expected return:
@@ -611,19 +613,19 @@ elif selected == "Rolling Jensen's Alpha":
611
 
612
  **How to use:**
613
  1. Enter the stock ticker, start date, and end date.
614
- 2. Enter the benchmark ticker.
615
  3. Click 'Fetch Data' to load the stock and benchmark data.
616
  4. The chart will display the rolling Jensen's Alpha.
617
  """)
618
 
619
- fig = plot_rolling_alpha(data, market_data)
620
  st.plotly_chart(fig)
621
 
622
  elif selected == "Rolling Value at Risk":
623
  st.markdown("""
624
  ### Rolling Value at Risk (VaR)
625
 
626
- This method calculates the rolling 1-year Value at Risk (VaR) at different confidence levels.
627
 
628
  **Methodology:**
629
 
@@ -637,31 +639,32 @@ elif selected == "Rolling Value at Risk":
637
  where \( P_t \) is the closing price at time \( t \).
638
 
639
  2. **Calculate Rolling VaR:**
640
- - Compute the rolling quantile of the returns over a specified window (e.g., 252 days) for different confidence levels:
641
  """)
642
  st.latex(r'''
643
  \text{VaR}_{\alpha, t} = \text{Quantile}_{\alpha}(\text{Return}_{t-n:t})
644
  ''')
645
  st.markdown("""
646
- where \( \alpha \) is the confidence level (e.g., 0.05 for 95% VaR) and \( n \) is the window size (e.g., 252 days).
647
 
648
  **How to use:**
649
  1. Enter the stock ticker, start date, and end date.
650
- 2. Click 'Fetch Data' to load the stock data.
651
- 3. The chart will display the rolling VaR at different confidence levels (e.g., 90%, 95%, 97%).
 
652
 
653
  **Results:**
654
  The chart shows the close prices along with the rolling VaR at different confidence levels over time.
655
  """)
656
 
657
- fig = plot_rolling_var(data)
658
  st.plotly_chart(fig)
659
 
660
  elif selected == "Rolling Conditional VaR":
661
  st.markdown("""
662
  ### Rolling Conditional Value at Risk (CVaR)
663
 
664
- This method calculates the rolling 1-year Conditional Value at Risk (CVaR) at different confidence levels.
665
 
666
  **Methodology:**
667
 
@@ -674,41 +677,33 @@ elif selected == "Rolling Conditional VaR":
674
  st.markdown("""
675
  where \( P_t \) is the closing price at time \( t \).
676
 
677
- 2. **Calculate Rolling VaR:**
678
- - Compute the rolling quantile of the returns over a specified window (e.g., 252 days) for different confidence levels:
679
- """)
680
- st.latex(r'''
681
- \text{VaR}_{\alpha, t} = \text{Quantile}_{\alpha}(\text{Return}_{t-n:t})
682
- ''')
683
- st.markdown("""
684
- where \( \alpha \) is the confidence level (e.g., 0.05 for 95% VaR) and \( n \) is the window size (e.g., 252 days).
685
-
686
- 3. **Calculate Rolling CVaR:**
687
- - Compute the average of the returns that are below the VaR threshold:
688
  """)
689
  st.latex(r'''
690
  \text{CVaR}_{\alpha, t} = \frac{1}{n} \sum_{i=1}^{n} \text{Return}_{i} \text{ where } \text{Return}_{i} < \text{VaR}_{\alpha, t}
691
  ''')
692
  st.markdown("""
693
- where \( n \) is the number of returns below the VaR threshold.
694
 
695
  **How to use:**
696
  1. Enter the stock ticker, start date, and end date.
697
- 2. Click 'Fetch Data' to load the stock data.
698
- 3. The chart will display the rolling CVaR at different confidence levels (e.g., 90%, 95%, 97%).
 
699
 
700
  **Results:**
701
  The chart shows the close prices along with the rolling CVaR at different confidence levels over time.
702
  """)
703
 
704
- fig = plot_rolling_cvar(data)
705
  st.plotly_chart(fig)
706
 
707
  elif selected == "Rolling Tail Ratio":
708
  st.markdown("""
709
  ### Rolling Tail Ratio
710
 
711
- This method calculates the rolling 1-year Tail Ratio.
712
 
713
  **Methodology:**
714
 
@@ -722,31 +717,32 @@ elif selected == "Rolling Tail Ratio":
722
  where \( P_t \) is the closing price at time \( t \).
723
 
724
  2. **Calculate Tail Ratio:**
725
- - Compute the rolling Tail Ratio over a specified window (e.g., 252 days):
726
  """)
727
  st.latex(r'''
728
  \text{Tail Ratio}_t = \frac{|\text{Quantile}_{95}(\text{Return}_{t-n:t})|}{|\text{Quantile}_{5}(\text{Return}_{t-n:t})|}
729
  ''')
730
  st.markdown("""
731
- where \( n \) is the window size (e.g., 252 days).
732
 
733
  **How to use:**
734
  1. Enter the stock ticker, start date, and end date.
735
- 2. Click 'Fetch Data' to load the stock data.
736
- 3. The chart will display the rolling Tail Ratio.
 
737
 
738
  **Results:**
739
  The chart shows the close prices along with the rolling Tail Ratio over time, indicating the balance between extreme positive and negative returns.
740
  """)
741
 
742
- fig = plot_rolling_tail_ratio(data)
743
  st.plotly_chart(fig)
744
 
745
  elif selected == "Rolling Omega Ratio":
746
  st.markdown("""
747
  ### Rolling Omega Ratio
748
 
749
- This method calculates the rolling 1-year Omega Ratio.
750
 
751
  **Methodology:**
752
 
@@ -760,31 +756,32 @@ elif selected == "Rolling Omega Ratio":
760
  where \( P_t \) is the closing price at time \( t \).
761
 
762
  2. **Calculate Omega Ratio:**
763
- - Compute the rolling Omega Ratio over a specified window (e.g., 252 days):
764
  """)
765
  st.latex(r'''
766
  \text{Omega Ratio}_t = \frac{\sum (\text{Return}_{i} > MAR) (\text{Return}_{i} - MAR)}{\sum (\text{Return}_{i} < MAR) (MAR - \text{Return}_{i})}
767
  ''')
768
  st.markdown("""
769
- where \( MAR \) is the Minimum Acceptable Return (assumed to be 0 here for simplicity) and \( n \) is the window size (e.g., 252 days).
770
 
771
  **How to use:**
772
  1. Enter the stock ticker, start date, and end date.
773
- 2. Click 'Fetch Data' to load the stock data.
774
- 3. The chart will display the rolling Omega Ratio.
 
775
 
776
  **Results:**
777
  The chart shows the close prices along with the rolling Omega Ratio over time, indicating the risk-return trade-off.
778
  """)
779
 
780
- fig = plot_rolling_omega(data)
781
  st.plotly_chart(fig)
782
 
783
  elif selected == "Rolling Sortino Ratio":
784
  st.markdown("""
785
  ### Rolling Sortino Ratio
786
 
787
- This method calculates the rolling 1-year Sortino Ratio.
788
 
789
  **Methodology:**
790
 
@@ -798,31 +795,32 @@ elif selected == "Rolling Sortino Ratio":
798
  where \( P_t \) is the closing price at time \( t \).
799
 
800
  2. **Calculate Rolling Sortino Ratio:**
801
- - Compute the rolling Sortino Ratio over a specified window (e.g., 252 days):
802
  """)
803
  st.latex(r'''
804
  \text{Sortino Ratio}_t = \frac{\sqrt{252} \cdot \text{Mean}(\text{Return}_{t-n:t} - MAR)}{\sqrt{\text{Mean}(\min(0, \text{Return}_{t-n:t} - MAR)^2)}}
805
  ''')
806
  st.markdown("""
807
- where \( MAR \) is the Minimum Acceptable Return (assumed to be 0 here for simplicity) and \( n \) is the window size (e.g., 252 days).
808
 
809
  **How to use:**
810
  1. Enter the stock ticker, start date, and end date.
811
- 2. Click 'Fetch Data' to load the stock data.
812
- 3. The chart will display the rolling Sortino Ratio.
 
813
 
814
  **Results:**
815
  The chart shows the close prices along with the rolling Sortino Ratio over time, indicating the risk-adjusted return considering downside risk.
816
  """)
817
 
818
- fig = plot_rolling_sortino(data)
819
  st.plotly_chart(fig)
820
 
821
  elif selected == "Rolling Calmar Ratio":
822
  st.markdown("""
823
  ### Rolling Calmar Ratio
824
 
825
- This method calculates the rolling 1-year Calmar Ratio.
826
 
827
  **Methodology:**
828
 
@@ -836,32 +834,32 @@ elif selected == "Rolling Calmar Ratio":
836
  where \( P_t \) is the closing price at time \( t \).
837
 
838
  2. **Calculate Rolling Calmar Ratio:**
839
- - Compute the rolling Calmar Ratio over a specified window (e.g., 252 days):
840
  """)
841
  st.latex(r'''
842
  \text{Calmar Ratio}_t = \frac{\text{CAGR}_{t-n:t}}{\text{Max Drawdown}_{t-n:t}}
843
  ''')
844
  st.markdown("""
845
- where \( \text{CAGR} \) is the Compound Annual Growth Rate and \( \text{Max Drawdown} \) is the maximum drawdown over the window \( n \) (e.g., 252 days).
846
 
847
  **How to use:**
848
  1. Enter the stock ticker, start date, and end date.
849
- 2. Click 'Fetch Data' to load the stock data.
850
- 3. The chart will display the rolling Calmar Ratio.
 
851
 
852
  **Results:**
853
  The chart shows the close prices along with the rolling Calmar Ratio over time, indicating the performance of the stock relative to its maximum drawdown.
854
  """)
855
 
856
- fig = plot_rolling_calmar(data)
857
  st.plotly_chart(fig)
858
 
859
-
860
  elif selected == "Rolling Stability":
861
  st.markdown("""
862
  ### Rolling Stability
863
 
864
- This method calculates the rolling 1-year stability of returns.
865
 
866
  **Methodology:**
867
 
@@ -875,31 +873,32 @@ elif selected == "Rolling Stability":
875
  where \( P_t \) is the closing price at time \( t \).
876
 
877
  2. **Calculate Rolling Stability:**
878
- - Compute the rolling stability over a specified window (e.g., 252 days):
879
  """)
880
  st.latex(r'''
881
  \text{Stability}_t = \sqrt{\frac{1}{n-1} \sum_{i=1}^{n} (\log(1 + \text{Return}_{t-i}) - \overline{\log(1 + \text{Return})})^2}
882
  ''')
883
  st.markdown("""
884
- where \( n \) is the window size (e.g., 252 days) and \( \overline{\log(1 + \text{Return})} \) is the mean of the log returns over the window.
885
 
886
  **How to use:**
887
  1. Enter the stock ticker, start date, and end date.
888
- 2. Click 'Fetch Data' to load the stock data.
889
- 3. The chart will display the rolling stability.
 
890
 
891
  **Results:**
892
  The chart shows the close prices along with the rolling stability over time, indicating the consistency of returns.
893
  """)
894
 
895
- fig = plot_rolling_stability(data)
896
  st.plotly_chart(fig)
897
 
898
  elif selected == "Rolling Maximum Drawdown":
899
  st.markdown("""
900
  ### Rolling Maximum Drawdown
901
 
902
- This method calculates the rolling 1-year maximum drawdown.
903
 
904
  **Methodology:**
905
 
@@ -913,7 +912,7 @@ elif selected == "Rolling Maximum Drawdown":
913
  where \( P_t \) is the closing price at time \( t \).
914
 
915
  2. **Calculate Rolling Maximum Drawdown:**
916
- - Compute the cumulative returns and the maximum drawdown over a specified window (e.g., 252 days):
917
  """)
918
  st.latex(r'''
919
  \text{Cumulative Return}_t = \prod_{i=1}^{t} (1 + \text{Return}_i)
@@ -926,21 +925,22 @@ elif selected == "Rolling Maximum Drawdown":
926
 
927
  **How to use:**
928
  1. Enter the stock ticker, start date, and end date.
929
- 2. Click 'Fetch Data' to load the stock data.
930
- 3. The chart will display the rolling maximum drawdown.
 
931
 
932
  **Results:**
933
  The chart shows the close prices along with the rolling maximum drawdown over time, indicating the peak-to-trough decline during a specified period.
934
  """)
935
 
936
- fig = plot_rolling_drawdown(data)
937
  st.plotly_chart(fig)
938
 
939
  elif selected == "Rolling Capture Ratios":
940
  st.markdown("""
941
  ### Rolling Capture Ratios
942
 
943
- This method calculates the rolling 1-year upside and downside capture ratios.
944
 
945
  **Methodology:**
946
 
@@ -969,7 +969,7 @@ elif selected == "Rolling Capture Ratios":
969
  st.markdown("""
970
  **How to use:**
971
  1. Enter the stock ticker, start date, and end date.
972
- 2. Enter the benchmark ticker.
973
  3. Click 'Fetch Data' to load the stock and benchmark data.
974
  4. The chart will display the rolling capture ratios.
975
 
@@ -977,14 +977,14 @@ elif selected == "Rolling Capture Ratios":
977
  The chart shows the close prices along with the rolling upside and downside capture ratios over time, indicating the stock's performance relative to the benchmark during up and down market conditions.
978
  """)
979
 
980
- fig = plot_rolling_capture(data, market_data)
981
  st.plotly_chart(fig)
982
 
983
  elif selected == "Rolling Pain Index":
984
  st.markdown("""
985
  ### Rolling Pain Index
986
 
987
- This method calculates the rolling 1-year pain index.
988
 
989
  **Methodology:**
990
 
@@ -1012,7 +1012,7 @@ elif selected == "Rolling Pain Index":
1012
  ''')
1013
  st.markdown("""
1014
  4. **Calculate Rolling Pain Index:**
1015
- - Compute the average drawdown over a specified window (e.g., 252 days) where the drawdown is negative:
1016
  """)
1017
  st.latex(r'''
1018
  \text{Pain Index} = \frac{1}{n} \sum_{i=1}^{n} \text{Drawdown}_i \quad \text{for } \text{Drawdown}_i < 0
@@ -1020,14 +1020,15 @@ elif selected == "Rolling Pain Index":
1020
  st.markdown("""
1021
  **How to use:**
1022
  1. Enter the stock ticker, start date, and end date.
1023
- 2. Click 'Fetch Data' to load the stock data.
1024
- 3. The chart will display the rolling pain index.
 
1025
 
1026
  **Results:**
1027
  The chart shows the close prices along with the rolling pain index over time, indicating the average drawdown experienced over a specified period.
1028
  """)
1029
 
1030
- fig = plot_rolling_pain_index(data)
1031
  st.plotly_chart(fig)
1032
 
1033
  hide_streamlit_style = """
 
13
  return yf.download(ticker, start=start_date, end=end_date)
14
 
15
  # Helper function to plot rolling volatility and volatility of volatility
16
+ def plot_rolling_volatility(data: pd.DataFrame, window: int) -> go.Figure:
17
  data['Return'] = data['Close'].pct_change()
18
+ data['Rolling_Volatility'] = data['Return'].rolling(window=window).std() * np.sqrt(252)
19
+ data['Vol_of_Vol'] = data['Rolling_Volatility'].rolling(window=window).std()
20
 
21
  fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.1,
22
  subplot_titles=('Close Price', 'Rolling Volatility', 'Volatility of Volatility'))
 
29
  return fig
30
 
31
  # Helper function to plot rolling Sharpe ratio
32
+ def plot_rolling_sharpe(data: pd.DataFrame, window: int, risk_free_rate: float) -> go.Figure:
33
  data['Return'] = data['Close'].pct_change()
34
+ rolling_sharpe = np.sqrt(252) * (data['Return'].rolling(window).mean() - risk_free_rate) / data['Return'].rolling(window).std()
35
 
36
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
37
  subplot_titles=('Close Price', 'Rolling Sharpe Ratio'))
 
40
  fig.add_trace(go.Scatter(x=data.index, y=rolling_sharpe, mode='lines', name='Rolling Sharpe Ratio', line=dict(color='green')), row=2, col=1)
41
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
42
 
43
+ fig.update_layout(title='Rolling Sharpe Ratio with Stock Price', xaxis_title='Date')
44
  return fig
45
 
46
  # Helper function to plot rolling Treynor ratio
47
+ def plot_rolling_treynor(data: pd.DataFrame, market_data: pd.DataFrame, window: int, risk_free_rate: float) -> go.Figure:
 
48
  data['Return'] = data['Close'].pct_change()
49
  market_data['Return'] = market_data['Close'].pct_change()
50
 
51
  # Align indices
52
  market_data = market_data.reindex(data.index, method='ffill')
53
 
54
+ covariance = data['Return'].rolling(window=window).cov(market_data['Return'])
55
+ variance = market_data['Return'].rolling(window=window).var()
56
  rolling_beta = covariance / variance
57
+ avg_rolling_returns = data['Return'].rolling(window=window).mean()
 
58
  data['Rolling_Treynor_Ratio'] = (avg_rolling_returns - risk_free_rate) / rolling_beta
59
 
60
  fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.1,
 
64
  fig.add_trace(go.Scatter(x=market_data.index, y=market_data['Close'], mode='lines', name='Benchmark Price', line=dict(color='blue')), row=2, col=1)
65
  fig.add_trace(go.Scatter(x=data.index, y=data['Rolling_Treynor_Ratio'], mode='lines', name='Rolling Treynor Ratio', line=dict(color='red')), row=3, col=1)
66
 
67
+ fig.update_layout(title='Rolling Treynor Ratio with Stock Price and Benchmark', xaxis_title='Date')
68
  return fig
69
+
70
  # Helper function to calculate and plot rolling beta
71
+ def plot_rolling_beta(data: pd.DataFrame, market_data: pd.DataFrame, window: int) -> go.Figure:
72
  data['Return'] = data['Close'].pct_change().dropna()
73
  market_data['Market_Return'] = market_data['Close'].pct_change().dropna()
74
 
 
104
  fig.add_trace(go.Scatter(x=rolling_beta_ransac.index, y=rolling_beta_ransac, mode='lines', name='Rolling Beta (RANSAC)', line=dict(color='red')), row=3, col=1)
105
  fig.add_trace(go.Scatter(x=rolling_beta_ols.index, y=rolling_beta_ols, mode='lines', name='Rolling Beta (OLS)', line=dict(color='green')), row=3, col=1)
106
 
107
+ fig.update_layout(title='Rolling Beta with Stock Price and Benchmark', xaxis_title='Date')
108
  return fig
109
 
110
  # Helper function to plot rolling Jensen's alpha
111
+ def plot_rolling_alpha(data: pd.DataFrame, market_data: pd.DataFrame, window: int, risk_free_rate: float) -> go.Figure:
112
  data['Return'] = data['Close'].pct_change()
113
  market_data['Return'] = market_data['Close'].pct_change()
114
 
 
115
  rolling_alpha = []
116
 
117
+ for i in range(len(data) - window):
118
+ window_stock = data['Return'].iloc[i:i + window]
119
+ window_market = market_data['Return'].iloc[i:i + window]
120
+ beta = window_stock.cov(window_market) / window_market.var()
121
+ expected_return = risk_free_rate + beta * (window_market.mean() - risk_free_rate)
122
+ alpha = window_stock.mean() - expected_return
123
  rolling_alpha.append(alpha)
124
 
125
+ rolling_alpha = pd.Series(rolling_alpha, index=data.index[window:])
126
 
127
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
128
  subplot_titles=('Close Price', 'Rolling Jensen\'s Alpha'))
 
130
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
131
  fig.add_trace(go.Scatter(x=rolling_alpha.index, y=rolling_alpha, mode='lines', name='Rolling Jensen\'s Alpha', line=dict(color='green')), row=2, col=1)
132
 
133
+ fig.update_layout(title='Rolling Jensen\'s Alpha with Stock Price', xaxis_title='Date')
134
  return fig
135
 
136
  # Helper function to plot rolling Value at Risk (VaR)
137
+ def plot_rolling_var(data: pd.DataFrame, window: int) -> go.Figure:
138
  data['Return'] = data['Close'].pct_change()
139
+ rolling_var_90 = data['Return'].rolling(window).quantile(0.10).dropna()
140
+ rolling_var_95 = data['Return'].rolling(window).quantile(0.05).dropna()
141
+ rolling_var_97 = data['Return'].rolling(window).quantile(0.03).dropna()
142
 
143
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
144
  subplot_titles=('Close Price', 'Rolling VaR'))
 
148
  fig.add_trace(go.Scatter(x=rolling_var_95.index, y=rolling_var_95, mode='lines', name='Rolling VaR 95%', line=dict(color='blue')), row=2, col=1)
149
  fig.add_trace(go.Scatter(x=rolling_var_97.index, y=rolling_var_97, mode='lines', name='Rolling VaR 97%', line=dict(color='purple')), row=2, col=1)
150
 
151
+ fig.update_layout(title='Rolling VaR with Stock Price', xaxis_title='Date')
152
  return fig
153
 
154
  # Helper function to plot rolling Conditional VaR (CVaR)
155
+ def plot_rolling_cvar(data: pd.DataFrame, window: int) -> go.Figure:
156
  data['Return'] = data['Close'].pct_change()
157
 
158
  def conditional_var(x, alpha=0.05):
159
  var = np.percentile(x, alpha * 100)
160
  return np.mean(x[x < var])
161
 
162
+ rolling_cvar_95 = data['Return'].rolling(window).apply(conditional_var, raw=True).dropna()
163
+ rolling_cvar_90 = data['Return'].rolling(window).apply(lambda x: conditional_var(x, alpha=0.1), raw=True).dropna()
164
+ rolling_cvar_97 = data['Return'].rolling(window).apply(lambda x: conditional_var(x, alpha=0.03), raw=True).dropna()
165
 
166
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
167
  subplot_titles=('Close Price', 'Rolling CVaR'))
 
171
  fig.add_trace(go.Scatter(x=rolling_cvar_90.index, y=rolling_cvar_90, mode='lines', name='Rolling CVaR 90%', line=dict(color='green')), row=2, col=1)
172
  fig.add_trace(go.Scatter(x=rolling_cvar_97.index, y=rolling_cvar_97, mode='lines', name='Rolling CVaR 97%', line=dict(color='orange')), row=2, col=1)
173
 
174
+ fig.update_layout(title='Rolling CVaR with Stock Price', xaxis_title='Date')
175
  return fig
176
 
177
  # Helper function to plot rolling Tail Ratio
178
+ def plot_rolling_tail_ratio(data: pd.DataFrame, window: int) -> go.Figure:
179
  data['Return'] = data['Close'].pct_change()
180
+ tail_ratio = data['Return'].rolling(window).apply(lambda x: np.abs(np.percentile(x, 95)) / np.abs(np.percentile(x, 5))).dropna()
181
 
182
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
183
  subplot_titles=('Close Price', 'Rolling Tail Ratio'))
 
186
  fig.add_trace(go.Scatter(x=tail_ratio.index, y=tail_ratio, mode='lines', name='Tail Ratio', line=dict(color='purple')), row=2, col=1)
187
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
188
 
189
+ fig.update_layout(title='Rolling Tail Ratio with Stock Price', xaxis_title='Date')
190
  return fig
191
 
192
  # Helper function to plot rolling Omega Ratio
193
+ def plot_rolling_omega(data: pd.DataFrame, window: int) -> go.Figure:
194
  data['Return'] = data['Close'].pct_change()
195
  MAR = 0 # Minimum Acceptable Return
196
+ omega_ratio = data['Return'].rolling(window).apply(lambda x: np.sum(x[x > MAR] - MAR) / np.sum(MAR - x[x < MAR])).dropna()
197
 
198
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
199
  subplot_titles=('Close Price', 'Rolling Omega Ratio'))
 
202
  fig.add_trace(go.Scatter(x=omega_ratio.index, y=omega_ratio, mode='lines', name='Omega Ratio', line=dict(color='green')), row=2, col=1)
203
  fig.add_hline(y=1, line=dict(color='red', dash='dash'), row=2, col=1)
204
 
205
+ fig.update_layout(title='Rolling Omega Ratio with Stock Price', xaxis_title='Date')
206
  return fig
207
 
208
  # Helper function to plot rolling Sortino Ratio
209
+ def plot_rolling_sortino(data: pd.DataFrame, window: int, MAR: float) -> go.Figure:
210
  data['Return'] = data['Close'].pct_change()
211
+ sortino_ratio = data['Return'].rolling(window).apply(lambda x: np.mean(x - MAR) / np.sqrt(np.mean(np.minimum(0, x - MAR) ** 2))).dropna()
 
212
 
213
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
214
  subplot_titles=('Close Price', 'Rolling Sortino Ratio'))
 
216
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
217
  fig.add_trace(go.Scatter(x=sortino_ratio.index, y=sortino_ratio, mode='lines', name='Sortino Ratio', line=dict(color='green')), row=2, col=1)
218
 
219
+ fig.update_layout(title='Rolling Sortino Ratio with Stock Price', xaxis_title='Date')
220
  return fig
221
 
222
  # Helper function to plot rolling Calmar Ratio
223
+ def plot_rolling_calmar(data: pd.DataFrame, window: int) -> go.Figure:
224
  data['Return'] = data['Close'].pct_change()
225
+ calmar_ratio = data['Return'].rolling(window).apply(lambda x: (1 + x).cumprod()[-1] ** (252.0 / len(x)) / np.abs(np.min((1 + x).cumprod() / (1 + x).cumprod().cummax()) - 1)).dropna()
226
 
227
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
228
  subplot_titles=('Close Price', 'Rolling Calmar Ratio'))
 
230
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
231
  fig.add_trace(go.Scatter(x=calmar_ratio.index, y=calmar_ratio, mode='lines', name='Calmar Ratio', line=dict(color='green')), row=2, col=1)
232
 
233
+ fig.update_layout(title='Rolling Calmar Ratio with Stock Price', xaxis_title='Date')
234
  return fig
235
 
236
  # Helper function to plot rolling stability
237
+ def plot_rolling_stability(data: pd.DataFrame, window: int) -> go.Figure:
238
  data['Return'] = data['Close'].pct_change()
239
+ stability = data['Return'].rolling(window).apply(lambda x: np.std(np.log1p(x).cumsum() - linregress(np.arange(len(x)), np.log1p(x).cumsum()).intercept - linregress(np.arange(len(x)), np.log1p(x).cumsum()).slope * np.arange(len(x)))).dropna()
240
 
241
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
242
  subplot_titles=('Close Price', 'Rolling Stability'))
 
244
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
245
  fig.add_trace(go.Scatter(x=stability.index, y=stability, mode='lines', name='Stability', line=dict(color='purple')), row=2, col=1)
246
 
247
+ fig.update_layout(title='Rolling Stability of Returns with Stock Price', xaxis_title='Date')
248
  return fig
249
 
250
  # Helper function to plot rolling maximum drawdown
251
+ def plot_rolling_drawdown(data: pd.DataFrame, window: int) -> go.Figure:
252
  data['Return'] = data['Close'].pct_change()
253
  rolling_cumulative = (1 + data['Return']).cumprod()
254
+ rolling_max = rolling_cumulative.rolling(window, min_periods=1).max()
255
  rolling_drawdown = (rolling_cumulative - rolling_max) / rolling_max
256
 
257
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
 
260
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
261
  fig.add_trace(go.Scatter(x=rolling_drawdown.index, y=rolling_drawdown, mode='lines', name='Maximum Drawdown', line=dict(color='red')), row=2, col=1)
262
 
263
+ fig.update_layout(title='Rolling Maximum Drawdown with Stock Price', xaxis_title='Date')
264
  return fig
265
 
266
  # Helper function to calculate and plot rolling capture ratios
267
+ def plot_rolling_capture(data: pd.DataFrame, market_data: pd.DataFrame, window: int) -> go.Figure:
268
  data['Return'] = data['Close'].pct_change()
269
  market_data['Return'] = market_data['Close'].pct_change()
270
 
 
306
  return upside_captures, downside_captures
307
 
308
  data['rolling_upside_capture'], data['rolling_downside_capture'] = compute_rolling_captures(
309
+ data['Return'], market_data['Return'], window
310
  )
311
 
312
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
 
316
  fig.add_trace(go.Scatter(x=data.index, y=data['rolling_upside_capture'], mode='lines', name='Rolling Upside Capture', line=dict(color='green')), row=2, col=1)
317
  fig.add_trace(go.Scatter(x=data.index, y=data['rolling_downside_capture'], mode='lines', name='Rolling Downside Capture', line=dict(color='red')), row=2, col=1)
318
 
319
+ fig.update_layout(title='Rolling Capture Ratios with Stock Price', xaxis_title='Date')
320
  return fig
321
 
 
322
  # Helper function to plot rolling Pain Index
323
+ def plot_rolling_pain_index(data: pd.DataFrame, window: int) -> go.Figure:
324
  data['Return'] = data['Close'].pct_change()
325
  cumulative_return = (1 + data['Return']).cumprod()
326
  running_max = cumulative_return.cummax()
327
  drawdown = (cumulative_return - running_max) / running_max
328
+ pain_index = drawdown.rolling(window).apply(lambda x: np.mean(x[x < 0])).dropna()
329
 
330
  fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
331
  subplot_titles=('Close Price', 'Rolling Pain Index'))
 
333
  fig.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price', line=dict(color='grey')), row=1, col=1)
334
  fig.add_trace(go.Scatter(x=pain_index.index, y=pain_index, mode='lines', name='Pain Index', line=dict(color='red')), row=2, col=1)
335
 
336
+ fig.update_layout(title='Rolling Pain Index with Stock Price', xaxis_title='Date')
337
  return fig
338
 
339
  # Streamlit app
 
351
  ticker = st.sidebar.text_input('Enter Stock Ticker', 'VOW.DE')
352
  start_date = st.sidebar.date_input('Start Date', pd.to_datetime('2010-01-01'))
353
  end_date = st.sidebar.date_input('End Date', pd.to_datetime('2024-12-31'))
354
+ window_size = st.sidebar.number_input('Rolling Window Size (Days)', min_value=1, value=252)
355
 
356
  # Fetch data
357
  if 'data' not in st.session_state or st.sidebar.button('Fetch Data'):
 
359
 
360
  data = st.session_state.data
361
 
362
+ # Additional input for methods requiring benchmark or risk-free rate
363
  if selected in ["Rolling Treynor Ratio", "Rolling Beta", "Rolling Jensen's Alpha", "Rolling Capture Ratios"]:
364
  benchmark_ticker = st.sidebar.text_input('Enter Benchmark Ticker', '^GSPC')
365
  if 'market_data' not in st.session_state or st.sidebar.button('Fetch Market Data'):
366
  st.session_state.market_data = fetch_stock_data(benchmark_ticker, start_date, end_date)
 
367
  market_data = st.session_state.market_data
368
 
369
+ if selected in ["Rolling Sharpe Ratio", "Rolling Treynor Ratio", "Rolling Jensen's Alpha", "Rolling Sortino Ratio"]:
370
+ risk_free_rate = st.sidebar.number_input('Risk-Free Rate (as a decimal)', min_value=0.0, value=0.0)
371
+
372
+ if selected == "Rolling Sortino Ratio":
373
+ MAR = st.sidebar.number_input('Minimum Acceptable Return (MAR, as a decimal)', min_value=0.0, value=0.0)
374
+
375
  # Display results based on the selected method
376
  if selected == "Rolling Volatility":
377
  st.markdown("""
 
391
  where \( P_t \) is the closing price at time \( t \).
392
 
393
  2. **Calculate Rolling Volatility:**
394
+ - Compute the rolling standard deviation of the returns over a specified window and annualize it:
395
  """)
396
  st.latex(r'''
397
  \text{Rolling Volatility}_t = \sqrt{252} \times \text{std}(\text{Return}_{t-n:t})
398
  ''')
399
  st.markdown("""
400
+ where \( n \) is the window size.
401
 
402
  3. **Calculate Volatility of Volatility:**
403
+ - Compute the rolling standard deviation of the rolling volatility over the specified window:
404
  """)
405
  st.latex(r'''
406
  \text{Volatility of Volatility}_t = \text{std}(\text{Rolling Volatility}_{t-n:t})
 
409
  st.markdown("""
410
  **How to use:**
411
  1. Enter the stock ticker, start date, and end date.
412
+ 2. Enter the rolling window size.
413
+ 3. Click 'Fetch Data' to load the stock data.
414
+ 4. The chart will display the rolling volatility and the volatility of volatility.
415
  """)
416
 
417
+ fig = plot_rolling_volatility(data, window_size)
418
  st.plotly_chart(fig)
419
 
420
  elif selected == "Rolling Sharpe Ratio":
421
  st.markdown("""
422
  ### Rolling Sharpe Ratio
423
 
424
+ This method calculates the rolling Sharpe Ratio.
425
 
426
  **Methodology:**
427
 
 
435
  where \( P_t \) is the closing price at time \( t \).
436
 
437
  2. **Calculate Rolling Average Return:**
438
+ - Compute the rolling mean of the returns over the specified window:
439
  """)
440
  st.latex(r'''
441
+ \text{Rolling Average Return}_t = \text{mean}(\text{Return}_{t-n:t})
442
  ''')
443
  st.markdown("""
444
 
445
  3. **Calculate Rolling Standard Deviation:**
446
+ - Compute the rolling standard deviation of the returns over the specified window:
447
  """)
448
  st.latex(r'''
449
+ \text{Rolling Std Dev}_t = \text{std}(\text{Return}_{t-n:t})
450
  ''')
451
  st.markdown("""
452
 
453
  4. **Calculate Rolling Sharpe Ratio:**
454
+ - Annualize the Sharpe Ratio:
455
  """)
456
  st.latex(r'''
457
+ \text{Rolling Sharpe Ratio}_t = \frac{\text{Rolling Average Return}_t - R_f}{\text{Rolling Std Dev}_t} \times \sqrt{252}
458
  ''')
459
  st.markdown("""
460
 
461
  **How to use:**
462
  1. Enter the stock ticker, start date, and end date.
463
+ 2. Enter the rolling window size and risk-free rate.
464
+ 3. Click 'Fetch Data' to load the stock data.
465
+ 4. The chart will display the rolling Sharpe Ratio.
466
  """)
467
 
468
+ fig = plot_rolling_sharpe(data, window_size, risk_free_rate)
469
  st.plotly_chart(fig)
470
 
 
471
  elif selected == "Rolling Treynor Ratio":
472
  st.markdown("""
473
  ### Rolling Treynor Ratio
474
 
475
+ This method calculates the rolling Treynor Ratio.
476
 
477
  **Methodology:**
478
 
 
492
  \beta_t = \frac{\text{Cov}(\text{Return}_{\text{stock}, t}, \text{Return}_{\text{benchmark}, t})}{\text{Var}(\text{Return}_{\text{benchmark}, t})}
493
  ''')
494
  st.markdown("""
495
+ where the rolling window size is specified.
496
 
497
  3. **Calculate Average Rolling Returns:**
498
  - Compute the rolling mean of the stock returns over the same window:
 
501
  \text{Average Rolling Return}_t = \frac{1}{n} \sum_{i=t-n+1}^{t} \text{Return}_{\text{stock}, i}
502
  ''')
503
  st.markdown("""
504
+ where \( n \) is the window size.
505
 
506
  4. **Calculate Treynor Ratio:**
507
+ - Compute the Treynor Ratio using the risk-free rate \( R_f \):
508
  """)
509
  st.latex(r'''
510
  \text{Treynor Ratio}_t = \frac{\text{Average Rolling Return}_t - R_f}{\beta_t}
 
514
 
515
  **How to use:**
516
  1. Enter the stock ticker, start date, and end date.
517
+ 2. Enter the benchmark ticker, rolling window size, and risk-free rate.
518
  3. Click 'Fetch Data' to load the stock and benchmark data.
519
  4. The chart will display the rolling Treynor Ratio.
520
  """)
521
 
522
+ fig = plot_rolling_treynor(data, market_data, window_size, risk_free_rate)
523
  st.plotly_chart(fig)
524
 
525
  elif selected == "Rolling Beta":
 
540
  where \( P_t \) is the closing price at time \( t \).
541
 
542
  2. **Calculate Rolling Beta using OLS:**
543
+ - Perform a linear regression of the stock returns against the benchmark returns over a specified window:
544
  """)
545
  st.latex(r'''
546
  \beta_{OLS} = \frac{\text{Cov}(\text{Return}_{\text{stock}}, \text{Return}_{\text{benchmark}})}{\text{Var}(\text{Return}_{\text{benchmark}})}
547
  ''')
548
  st.markdown("""
549
+ where the rolling window size is specified.
550
 
551
  3. **Calculate Rolling Beta using RANSAC:**
552
  - Use the RANSAC algorithm to robustly estimate the beta, reducing the influence of outliers:
 
559
 
560
  **How to use:**
561
  1. Enter the stock ticker, start date, and end date.
562
+ 2. Enter the benchmark ticker and rolling window size.
563
  3. Click 'Fetch Data' to load the stock and benchmark data.
564
  4. The chart will display the rolling beta calculated using both OLS and RANSAC methods.
565
  """)
566
 
567
+ fig = plot_rolling_beta(data, market_data, window_size)
568
  st.plotly_chart(fig)
569
 
570
  elif selected == "Rolling Jensen's Alpha":
571
  st.markdown("""
572
  ### Rolling Jensen's Alpha
573
 
574
+ This method calculates the rolling Jensen's Alpha.
575
 
576
  **Methodology:**
577
 
 
585
  where \( P_t \) is the closing price at time \( t \).
586
 
587
  2. **Calculate Beta:**
588
+ - Compute the rolling beta of the stock returns against the benchmark returns over a specified window:
589
  """)
590
  st.latex(r'''
591
  \beta_t = \frac{\text{Cov}(\text{Return}_{\text{stock}, t}, \text{Return}_{\text{benchmark}, t})}{\text{Var}(\text{Return}_{\text{benchmark}, t})}
592
  ''')
593
  st.markdown("""
594
+ where the rolling window size is specified.
595
 
596
  3. **Calculate Expected Return:**
597
  - Compute the expected return of the stock based on the CAPM model:
 
600
  \text{Expected Return}_t = R_f + \beta_t (\text{Return}_{\text{benchmark}} - R_f)
601
  ''')
602
  st.markdown("""
603
+ where \( R_f \) is the risk-free rate.
604
 
605
  4. **Calculate Jensen's Alpha:**
606
  - Compute the Jensen's Alpha as the difference between the actual return and the expected return:
 
613
 
614
  **How to use:**
615
  1. Enter the stock ticker, start date, and end date.
616
+ 2. Enter the benchmark ticker, rolling window size, and risk-free rate.
617
  3. Click 'Fetch Data' to load the stock and benchmark data.
618
  4. The chart will display the rolling Jensen's Alpha.
619
  """)
620
 
621
+ fig = plot_rolling_alpha(data, market_data, window_size, risk_free_rate)
622
  st.plotly_chart(fig)
623
 
624
  elif selected == "Rolling Value at Risk":
625
  st.markdown("""
626
  ### Rolling Value at Risk (VaR)
627
 
628
+ This method calculates the rolling Value at Risk (VaR) at different confidence levels.
629
 
630
  **Methodology:**
631
 
 
639
  where \( P_t \) is the closing price at time \( t \).
640
 
641
  2. **Calculate Rolling VaR:**
642
+ - Compute the rolling quantile of the returns over a specified window for different confidence levels:
643
  """)
644
  st.latex(r'''
645
  \text{VaR}_{\alpha, t} = \text{Quantile}_{\alpha}(\text{Return}_{t-n:t})
646
  ''')
647
  st.markdown("""
648
+ where \( \alpha \) is the confidence level and \( n \) is the window size.
649
 
650
  **How to use:**
651
  1. Enter the stock ticker, start date, and end date.
652
+ 2. Enter the rolling window size.
653
+ 3. Click 'Fetch Data' to load the stock data.
654
+ 4. The chart will display the rolling VaR at different confidence levels.
655
 
656
  **Results:**
657
  The chart shows the close prices along with the rolling VaR at different confidence levels over time.
658
  """)
659
 
660
+ fig = plot_rolling_var(data, window_size)
661
  st.plotly_chart(fig)
662
 
663
  elif selected == "Rolling Conditional VaR":
664
  st.markdown("""
665
  ### Rolling Conditional Value at Risk (CVaR)
666
 
667
+ This method calculates the rolling Conditional Value at Risk (CVaR) at different confidence levels.
668
 
669
  **Methodology:**
670
 
 
677
  st.markdown("""
678
  where \( P_t \) is the closing price at time \( t \).
679
 
680
+ 2. **Calculate Rolling CVaR:**
681
+ - Compute the average of the returns that are below the VaR threshold over a specified window:
 
 
 
 
 
 
 
 
 
682
  """)
683
  st.latex(r'''
684
  \text{CVaR}_{\alpha, t} = \frac{1}{n} \sum_{i=1}^{n} \text{Return}_{i} \text{ where } \text{Return}_{i} < \text{VaR}_{\alpha, t}
685
  ''')
686
  st.markdown("""
687
+ where \( n \) is the number of returns below the VaR threshold and \( \alpha \) is the confidence level.
688
 
689
  **How to use:**
690
  1. Enter the stock ticker, start date, and end date.
691
+ 2. Enter the rolling window size.
692
+ 3. Click 'Fetch Data' to load the stock data.
693
+ 4. The chart will display the rolling CVaR at different confidence levels.
694
 
695
  **Results:**
696
  The chart shows the close prices along with the rolling CVaR at different confidence levels over time.
697
  """)
698
 
699
+ fig = plot_rolling_cvar(data, window_size)
700
  st.plotly_chart(fig)
701
 
702
  elif selected == "Rolling Tail Ratio":
703
  st.markdown("""
704
  ### Rolling Tail Ratio
705
 
706
+ This method calculates the rolling Tail Ratio.
707
 
708
  **Methodology:**
709
 
 
717
  where \( P_t \) is the closing price at time \( t \).
718
 
719
  2. **Calculate Tail Ratio:**
720
+ - Compute the rolling Tail Ratio over a specified window:
721
  """)
722
  st.latex(r'''
723
  \text{Tail Ratio}_t = \frac{|\text{Quantile}_{95}(\text{Return}_{t-n:t})|}{|\text{Quantile}_{5}(\text{Return}_{t-n:t})|}
724
  ''')
725
  st.markdown("""
726
+ where \( n \) is the window size.
727
 
728
  **How to use:**
729
  1. Enter the stock ticker, start date, and end date.
730
+ 2. Enter the rolling window size.
731
+ 3. Click 'Fetch Data' to load the stock data.
732
+ 4. The chart will display the rolling Tail Ratio.
733
 
734
  **Results:**
735
  The chart shows the close prices along with the rolling Tail Ratio over time, indicating the balance between extreme positive and negative returns.
736
  """)
737
 
738
+ fig = plot_rolling_tail_ratio(data, window_size)
739
  st.plotly_chart(fig)
740
 
741
  elif selected == "Rolling Omega Ratio":
742
  st.markdown("""
743
  ### Rolling Omega Ratio
744
 
745
+ This method calculates the rolling Omega Ratio.
746
 
747
  **Methodology:**
748
 
 
756
  where \( P_t \) is the closing price at time \( t \).
757
 
758
  2. **Calculate Omega Ratio:**
759
+ - Compute the rolling Omega Ratio over a specified window:
760
  """)
761
  st.latex(r'''
762
  \text{Omega Ratio}_t = \frac{\sum (\text{Return}_{i} > MAR) (\text{Return}_{i} - MAR)}{\sum (\text{Return}_{i} < MAR) (MAR - \text{Return}_{i})}
763
  ''')
764
  st.markdown("""
765
+ where \( MAR \) is the Minimum Acceptable Return and \( n \) is the window size.
766
 
767
  **How to use:**
768
  1. Enter the stock ticker, start date, and end date.
769
+ 2. Enter the rolling window size and minimum acceptable return.
770
+ 3. Click 'Fetch Data' to load the stock data.
771
+ 4. The chart will display the rolling Omega Ratio.
772
 
773
  **Results:**
774
  The chart shows the close prices along with the rolling Omega Ratio over time, indicating the risk-return trade-off.
775
  """)
776
 
777
+ fig = plot_rolling_omega(data, window_size)
778
  st.plotly_chart(fig)
779
 
780
  elif selected == "Rolling Sortino Ratio":
781
  st.markdown("""
782
  ### Rolling Sortino Ratio
783
 
784
+ This method calculates the rolling Sortino Ratio.
785
 
786
  **Methodology:**
787
 
 
795
  where \( P_t \) is the closing price at time \( t \).
796
 
797
  2. **Calculate Rolling Sortino Ratio:**
798
+ - Compute the rolling Sortino Ratio over a specified window:
799
  """)
800
  st.latex(r'''
801
  \text{Sortino Ratio}_t = \frac{\sqrt{252} \cdot \text{Mean}(\text{Return}_{t-n:t} - MAR)}{\sqrt{\text{Mean}(\min(0, \text{Return}_{t-n:t} - MAR)^2)}}
802
  ''')
803
  st.markdown("""
804
+ where \( MAR \) is the Minimum Acceptable Return and \( n \) is the window size.
805
 
806
  **How to use:**
807
  1. Enter the stock ticker, start date, and end date.
808
+ 2. Enter the rolling window size and minimum acceptable return.
809
+ 3. Click 'Fetch Data' to load the stock data.
810
+ 4. The chart will display the rolling Sortino Ratio.
811
 
812
  **Results:**
813
  The chart shows the close prices along with the rolling Sortino Ratio over time, indicating the risk-adjusted return considering downside risk.
814
  """)
815
 
816
+ fig = plot_rolling_sortino(data, window_size, MAR)
817
  st.plotly_chart(fig)
818
 
819
  elif selected == "Rolling Calmar Ratio":
820
  st.markdown("""
821
  ### Rolling Calmar Ratio
822
 
823
+ This method calculates the rolling Calmar Ratio.
824
 
825
  **Methodology:**
826
 
 
834
  where \( P_t \) is the closing price at time \( t \).
835
 
836
  2. **Calculate Rolling Calmar Ratio:**
837
+ - Compute the rolling Calmar Ratio over a specified window:
838
  """)
839
  st.latex(r'''
840
  \text{Calmar Ratio}_t = \frac{\text{CAGR}_{t-n:t}}{\text{Max Drawdown}_{t-n:t}}
841
  ''')
842
  st.markdown("""
843
+ where \( \text{CAGR} \) is the Compound Annual Growth Rate and \( \text{Max Drawdown} \) is the maximum drawdown over the window \( n \).
844
 
845
  **How to use:**
846
  1. Enter the stock ticker, start date, and end date.
847
+ 2. Enter the rolling window size.
848
+ 3. Click 'Fetch Data' to load the stock data.
849
+ 4. The chart will display the rolling Calmar Ratio.
850
 
851
  **Results:**
852
  The chart shows the close prices along with the rolling Calmar Ratio over time, indicating the performance of the stock relative to its maximum drawdown.
853
  """)
854
 
855
+ fig = plot_rolling_calmar(data, window_size)
856
  st.plotly_chart(fig)
857
 
 
858
  elif selected == "Rolling Stability":
859
  st.markdown("""
860
  ### Rolling Stability
861
 
862
+ This method calculates the rolling stability of returns.
863
 
864
  **Methodology:**
865
 
 
873
  where \( P_t \) is the closing price at time \( t \).
874
 
875
  2. **Calculate Rolling Stability:**
876
+ - Compute the rolling stability over a specified window:
877
  """)
878
  st.latex(r'''
879
  \text{Stability}_t = \sqrt{\frac{1}{n-1} \sum_{i=1}^{n} (\log(1 + \text{Return}_{t-i}) - \overline{\log(1 + \text{Return})})^2}
880
  ''')
881
  st.markdown("""
882
+ where \( n \) is the window size and \( \overline{\log(1 + \text{Return})} \) is the mean of the log returns over the window.
883
 
884
  **How to use:**
885
  1. Enter the stock ticker, start date, and end date.
886
+ 2. Enter the rolling window size.
887
+ 3. Click 'Fetch Data' to load the stock data.
888
+ 4. The chart will display the rolling stability.
889
 
890
  **Results:**
891
  The chart shows the close prices along with the rolling stability over time, indicating the consistency of returns.
892
  """)
893
 
894
+ fig = plot_rolling_stability(data, window_size)
895
  st.plotly_chart(fig)
896
 
897
  elif selected == "Rolling Maximum Drawdown":
898
  st.markdown("""
899
  ### Rolling Maximum Drawdown
900
 
901
+ This method calculates the rolling maximum drawdown.
902
 
903
  **Methodology:**
904
 
 
912
  where \( P_t \) is the closing price at time \( t \).
913
 
914
  2. **Calculate Rolling Maximum Drawdown:**
915
+ - Compute the cumulative returns and the maximum drawdown over a specified window:
916
  """)
917
  st.latex(r'''
918
  \text{Cumulative Return}_t = \prod_{i=1}^{t} (1 + \text{Return}_i)
 
925
 
926
  **How to use:**
927
  1. Enter the stock ticker, start date, and end date.
928
+ 2. Enter the rolling window size.
929
+ 3. Click 'Fetch Data' to load the stock data.
930
+ 4. The chart will display the rolling maximum drawdown.
931
 
932
  **Results:**
933
  The chart shows the close prices along with the rolling maximum drawdown over time, indicating the peak-to-trough decline during a specified period.
934
  """)
935
 
936
+ fig = plot_rolling_drawdown(data, window_size)
937
  st.plotly_chart(fig)
938
 
939
  elif selected == "Rolling Capture Ratios":
940
  st.markdown("""
941
  ### Rolling Capture Ratios
942
 
943
+ This method calculates the rolling upside and downside capture ratios.
944
 
945
  **Methodology:**
946
 
 
969
  st.markdown("""
970
  **How to use:**
971
  1. Enter the stock ticker, start date, and end date.
972
+ 2. Enter the benchmark ticker and rolling window size.
973
  3. Click 'Fetch Data' to load the stock and benchmark data.
974
  4. The chart will display the rolling capture ratios.
975
 
 
977
  The chart shows the close prices along with the rolling upside and downside capture ratios over time, indicating the stock's performance relative to the benchmark during up and down market conditions.
978
  """)
979
 
980
+ fig = plot_rolling_capture(data, market_data, window_size)
981
  st.plotly_chart(fig)
982
 
983
  elif selected == "Rolling Pain Index":
984
  st.markdown("""
985
  ### Rolling Pain Index
986
 
987
+ This method calculates the rolling pain index.
988
 
989
  **Methodology:**
990
 
 
1012
  ''')
1013
  st.markdown("""
1014
  4. **Calculate Rolling Pain Index:**
1015
+ - Compute the average drawdown over a specified window where the drawdown is negative:
1016
  """)
1017
  st.latex(r'''
1018
  \text{Pain Index} = \frac{1}{n} \sum_{i=1}^{n} \text{Drawdown}_i \quad \text{for } \text{Drawdown}_i < 0
 
1020
  st.markdown("""
1021
  **How to use:**
1022
  1. Enter the stock ticker, start date, and end date.
1023
+ 2. Enter the rolling window size.
1024
+ 3. Click 'Fetch Data' to load the stock data.
1025
+ 4. The chart will display the rolling pain index.
1026
 
1027
  **Results:**
1028
  The chart shows the close prices along with the rolling pain index over time, indicating the average drawdown experienced over a specified period.
1029
  """)
1030
 
1031
+ fig = plot_rolling_pain_index(data, window_size)
1032
  st.plotly_chart(fig)
1033
 
1034
  hide_streamlit_style = """