Tonic commited on
Commit
c9bad9c
·
1 Parent(s): f2e16b4

attempt more advanced predictions using model ensemble

Browse files
Files changed (1) hide show
  1. app.py +116 -71
app.py CHANGED
@@ -1128,81 +1128,126 @@ def calculate_advanced_risk_metrics(df: pd.DataFrame, market_returns: pd.Series
1128
  Returns:
1129
  Dict: Advanced risk metrics
1130
  """
1131
- returns = df['Returns'].dropna()
1132
-
1133
- if len(returns) < 30:
1134
- return {"error": "Insufficient data for risk calculation"}
1135
-
1136
- # Basic metrics
1137
- annual_return = returns.mean() * 252
1138
- annual_vol = returns.std() * np.sqrt(252)
1139
-
1140
- # Market-adjusted metrics
1141
- if market_returns is not None and len(market_returns) > 0:
1142
- # Align dates
1143
- aligned_returns = returns.reindex(market_returns.index).dropna()
1144
- aligned_market = market_returns.reindex(aligned_returns.index).dropna()
1145
-
1146
- if len(aligned_returns) > 10:
1147
- beta = np.cov(aligned_returns, aligned_market)[0,1] / np.var(aligned_market)
1148
- alpha = aligned_returns.mean() - beta * aligned_market.mean()
1149
- correlation = np.corrcoef(aligned_returns, aligned_market)[0,1]
1150
- else:
1151
- beta = 1.0
1152
- alpha = 0.0
1153
- correlation = 0.0
1154
- else:
1155
  beta = 1.0
1156
  alpha = 0.0
1157
  correlation = 0.0
1158
-
1159
- # Tail risk metrics
1160
- var_95 = np.percentile(returns, 5)
1161
- var_99 = np.percentile(returns, 1)
1162
- cvar_95 = returns[returns <= var_95].mean()
1163
- cvar_99 = returns[returns <= var_99].mean()
1164
-
1165
- # Maximum drawdown
1166
- cumulative_returns = (1 + returns).cumprod()
1167
- rolling_max = cumulative_returns.expanding().max()
1168
- drawdown = (cumulative_returns - rolling_max) / rolling_max
1169
- max_drawdown = drawdown.min()
1170
-
1171
- # Skewness and kurtosis
1172
- skewness = stats.skew(returns)
1173
- kurtosis = stats.kurtosis(returns)
1174
-
1175
- # Risk-adjusted returns
1176
- sharpe_ratio = (annual_return - risk_free_rate) / annual_vol if annual_vol > 0 else 0
1177
- sortino_ratio = (annual_return - risk_free_rate) / (returns[returns < 0].std() * np.sqrt(252)) if returns[returns < 0].std() > 0 else 0
1178
- calmar_ratio = annual_return / abs(max_drawdown) if max_drawdown != 0 else 0
1179
-
1180
- # Information ratio (if market data available)
1181
- if market_returns is not None and len(market_returns) > 0:
1182
- excess_returns = aligned_returns - aligned_market
1183
- information_ratio = excess_returns.mean() / excess_returns.std() if excess_returns.std() > 0 else 0
1184
- else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1185
  information_ratio = 0
1186
-
1187
- return {
1188
- "Annual_Return": annual_return,
1189
- "Annual_Volatility": annual_vol,
1190
- "Sharpe_Ratio": sharpe_ratio,
1191
- "Sortino_Ratio": sortino_ratio,
1192
- "Calmar_Ratio": calmar_ratio,
1193
- "Information_Ratio": information_ratio,
1194
- "Beta": beta,
1195
- "Alpha": alpha * 252,
1196
- "Correlation_with_Market": correlation,
1197
- "VaR_95": var_95,
1198
- "VaR_99": var_99,
1199
- "CVaR_95": cvar_95,
1200
- "CVaR_99": cvar_99,
1201
- "Max_Drawdown": max_drawdown,
1202
- "Skewness": skewness,
1203
- "Kurtosis": kurtosis,
1204
- "Risk_Free_Rate": risk_free_rate
1205
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1206
 
1207
  def create_ensemble_prediction(df: pd.DataFrame, prediction_days: int,
1208
  ensemble_weights: Dict = None) -> Tuple[np.ndarray, np.ndarray]:
 
1128
  Returns:
1129
  Dict: Advanced risk metrics
1130
  """
1131
+ try:
1132
+ returns = df['Returns'].dropna()
1133
+
1134
+ if len(returns) < 30:
1135
+ return {"error": "Insufficient data for risk calculation"}
1136
+
1137
+ # Basic metrics
1138
+ annual_return = returns.mean() * 252
1139
+ annual_vol = returns.std() * np.sqrt(252)
1140
+
1141
+ # Market-adjusted metrics
 
 
 
 
 
 
 
 
 
 
 
 
 
1142
  beta = 1.0
1143
  alpha = 0.0
1144
  correlation = 0.0
1145
+ aligned_returns = None
1146
+ aligned_market = None
1147
+
1148
+ if market_returns is not None and len(market_returns) > 0:
1149
+ try:
1150
+ # Align dates
1151
+ aligned_returns = returns.reindex(market_returns.index).dropna()
1152
+ aligned_market = market_returns.reindex(aligned_returns.index).dropna()
1153
+
1154
+ # Ensure both arrays have the same length
1155
+ if len(aligned_returns) > 10 and len(aligned_market) > 10:
1156
+ # Find the common length
1157
+ min_length = min(len(aligned_returns), len(aligned_market))
1158
+ aligned_returns = aligned_returns.iloc[-min_length:]
1159
+ aligned_market = aligned_market.iloc[-min_length:]
1160
+
1161
+ # Ensure they have the same length
1162
+ if len(aligned_returns) == len(aligned_market) and len(aligned_returns) > 10:
1163
+ try:
1164
+ beta = np.cov(aligned_returns, aligned_market)[0,1] / np.var(aligned_market)
1165
+ alpha = aligned_returns.mean() - beta * aligned_market.mean()
1166
+ correlation = np.corrcoef(aligned_returns, aligned_market)[0,1]
1167
+ except Exception as e:
1168
+ print(f"Market correlation calculation error: {str(e)}")
1169
+ beta = 1.0
1170
+ alpha = 0.0
1171
+ correlation = 0.0
1172
+ else:
1173
+ beta = 1.0
1174
+ alpha = 0.0
1175
+ correlation = 0.0
1176
+ else:
1177
+ beta = 1.0
1178
+ alpha = 0.0
1179
+ correlation = 0.0
1180
+ except Exception as e:
1181
+ print(f"Market data alignment error: {str(e)}")
1182
+ beta = 1.0
1183
+ alpha = 0.0
1184
+ correlation = 0.0
1185
+ aligned_returns = None
1186
+ aligned_market = None
1187
+
1188
+ # Tail risk metrics
1189
+ var_95 = np.percentile(returns, 5)
1190
+ var_99 = np.percentile(returns, 1)
1191
+ cvar_95 = returns[returns <= var_95].mean()
1192
+ cvar_99 = returns[returns <= var_99].mean()
1193
+
1194
+ # Maximum drawdown
1195
+ cumulative_returns = (1 + returns).cumprod()
1196
+ rolling_max = cumulative_returns.expanding().max()
1197
+ drawdown = (cumulative_returns - rolling_max) / rolling_max
1198
+ max_drawdown = drawdown.min()
1199
+
1200
+ # Skewness and kurtosis
1201
+ skewness = stats.skew(returns)
1202
+ kurtosis = stats.kurtosis(returns)
1203
+
1204
+ # Risk-adjusted returns
1205
+ sharpe_ratio = (annual_return - risk_free_rate) / annual_vol if annual_vol > 0 else 0
1206
+ sortino_ratio = (annual_return - risk_free_rate) / (returns[returns < 0].std() * np.sqrt(252)) if returns[returns < 0].std() > 0 else 0
1207
+ calmar_ratio = annual_return / abs(max_drawdown) if max_drawdown != 0 else 0
1208
+
1209
+ # Information ratio (if market data available)
1210
  information_ratio = 0
1211
+ if aligned_returns is not None and aligned_market is not None:
1212
+ try:
1213
+ if len(aligned_returns) > 10 and len(aligned_market) > 10:
1214
+ min_length = min(len(aligned_returns), len(aligned_market))
1215
+ aligned_returns_for_ir = aligned_returns.iloc[-min_length:]
1216
+ aligned_market_for_ir = aligned_market.iloc[-min_length:]
1217
+
1218
+ if len(aligned_returns_for_ir) == len(aligned_market_for_ir):
1219
+ excess_returns = aligned_returns_for_ir - aligned_market_for_ir
1220
+ information_ratio = excess_returns.mean() / excess_returns.std() if excess_returns.std() > 0 else 0
1221
+ else:
1222
+ information_ratio = 0
1223
+ else:
1224
+ information_ratio = 0
1225
+ except Exception as e:
1226
+ print(f"Information ratio calculation error: {str(e)}")
1227
+ information_ratio = 0
1228
+
1229
+ return {
1230
+ "Annual_Return": annual_return,
1231
+ "Annual_Volatility": annual_vol,
1232
+ "Sharpe_Ratio": sharpe_ratio,
1233
+ "Sortino_Ratio": sortino_ratio,
1234
+ "Calmar_Ratio": calmar_ratio,
1235
+ "Information_Ratio": information_ratio,
1236
+ "Beta": beta,
1237
+ "Alpha": alpha * 252,
1238
+ "Correlation_with_Market": correlation,
1239
+ "VaR_95": var_95,
1240
+ "VaR_99": var_99,
1241
+ "CVaR_95": cvar_95,
1242
+ "CVaR_99": cvar_99,
1243
+ "Max_Drawdown": max_drawdown,
1244
+ "Skewness": skewness,
1245
+ "Kurtosis": kurtosis,
1246
+ "Risk_Free_Rate": risk_free_rate
1247
+ }
1248
+ except Exception as e:
1249
+ print(f"Advanced risk metrics calculation error: {str(e)}")
1250
+ return {"error": f"Risk calculation failed: {str(e)}"}
1251
 
1252
  def create_ensemble_prediction(df: pd.DataFrame, prediction_days: int,
1253
  ensemble_weights: Dict = None) -> Tuple[np.ndarray, np.ndarray]: