Spaces:
Paused
Paused
Tonic commited on
Commit ·
c9bad9c
1
Parent(s): f2e16b4
attempt more advanced predictions using model ensemble
Browse files
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 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
-
|
| 1141 |
-
|
| 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 |
-
|
| 1160 |
-
|
| 1161 |
-
|
| 1162 |
-
|
| 1163 |
-
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
|
| 1170 |
-
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
-
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
|
| 1177 |
-
|
| 1178 |
-
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1185 |
information_ratio = 0
|
| 1186 |
-
|
| 1187 |
-
|
| 1188 |
-
|
| 1189 |
-
|
| 1190 |
-
|
| 1191 |
-
|
| 1192 |
-
|
| 1193 |
-
|
| 1194 |
-
|
| 1195 |
-
|
| 1196 |
-
|
| 1197 |
-
|
| 1198 |
-
|
| 1199 |
-
|
| 1200 |
-
|
| 1201 |
-
|
| 1202 |
-
|
| 1203 |
-
|
| 1204 |
-
|
| 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]:
|