Spaces:
Running
on
Zero
Running
on
Zero
improve regime detection
Browse files
app.py
CHANGED
@@ -1395,8 +1395,46 @@ def detect_market_regime(returns: pd.Series, n_regimes: int = 3) -> Dict:
|
|
1395 |
Returns:
|
1396 |
Dict: Regime information including probabilities and characteristics
|
1397 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1398 |
if len(returns) < 50:
|
1399 |
-
return {"regime":
|
1400 |
|
1401 |
try:
|
1402 |
if HMM_AVAILABLE:
|
@@ -1424,8 +1462,12 @@ def detect_market_regime(returns: pd.Series, n_regimes: int = 3) -> Dict:
|
|
1424 |
regime_means = model.means_.flatten()
|
1425 |
regime_vols = np.sqrt(model.covars_.diagonal(axis1=1, axis2=2)) if model.covariance_type == "full" else np.sqrt(model.covars_)
|
1426 |
|
|
|
|
|
|
|
1427 |
return {
|
1428 |
-
"regime":
|
|
|
1429 |
"probabilities": regime_probs[-1].tolist(),
|
1430 |
"means": regime_means.tolist(),
|
1431 |
"volatilities": regime_vols.tolist(),
|
@@ -1442,21 +1484,25 @@ def detect_market_regime(returns: pd.Series, n_regimes: int = 3) -> Dict:
|
|
1442 |
vol_percentile = volatility.iloc[-1] / volatility.quantile(0.8)
|
1443 |
|
1444 |
if vol_percentile > 1.2:
|
|
|
1445 |
regime = 2 # High volatility regime
|
1446 |
elif vol_percentile < 0.8:
|
|
|
1447 |
regime = 0 # Low volatility regime
|
1448 |
else:
|
|
|
1449 |
regime = 1 # Normal regime
|
1450 |
|
1451 |
return {
|
1452 |
-
"regime":
|
|
|
1453 |
"probabilities": [0.1, 0.8, 0.1] if regime == 1 else [0.8, 0.1, 0.1] if regime == 0 else [0.1, 0.1, 0.8],
|
1454 |
"volatility": volatility.iloc[-1],
|
1455 |
"method": "Volatility-based"
|
1456 |
}
|
1457 |
except Exception as e:
|
1458 |
print(f"Warning: Regime detection failed: {str(e)}")
|
1459 |
-
return {"regime": 1, "probabilities": [1.0], "volatility": returns.std(), "method": "Fallback"}
|
1460 |
|
1461 |
def calculate_advanced_risk_metrics(df: pd.DataFrame, market_returns: pd.Series = None,
|
1462 |
risk_free_rate: float = 0.02) -> Dict:
|
|
|
1395 |
Returns:
|
1396 |
Dict: Regime information including probabilities and characteristics
|
1397 |
"""
|
1398 |
+
def get_regime_name(regime_idx: int, means: List[float], volatilities: List[float]) -> str:
|
1399 |
+
"""
|
1400 |
+
Convert regime index to descriptive name based on characteristics.
|
1401 |
+
|
1402 |
+
Args:
|
1403 |
+
regime_idx (int): Regime index (0, 1, 2)
|
1404 |
+
means (List[float]): List of regime means
|
1405 |
+
volatilities (List[float]): List of regime volatilities
|
1406 |
+
|
1407 |
+
Returns:
|
1408 |
+
str: Descriptive regime name
|
1409 |
+
"""
|
1410 |
+
if len(means) != 3 or len(volatilities) != 3:
|
1411 |
+
return f"Regime {regime_idx}"
|
1412 |
+
|
1413 |
+
# Sort regimes by volatility (low to high)
|
1414 |
+
vol_sorted = sorted(range(len(volatilities)), key=lambda i: volatilities[i])
|
1415 |
+
|
1416 |
+
# Sort regimes by mean return (low to high)
|
1417 |
+
mean_sorted = sorted(range(len(means)), key=lambda i: means[i])
|
1418 |
+
|
1419 |
+
# Determine regime characteristics
|
1420 |
+
if regime_idx == vol_sorted[0]: # Lowest volatility
|
1421 |
+
if means[regime_idx] > 0:
|
1422 |
+
return "Low Volatility Bull"
|
1423 |
+
else:
|
1424 |
+
return "Low Volatility Bear"
|
1425 |
+
elif regime_idx == vol_sorted[2]: # Highest volatility
|
1426 |
+
if means[regime_idx] > 0:
|
1427 |
+
return "High Volatility Bull"
|
1428 |
+
else:
|
1429 |
+
return "High Volatility Bear"
|
1430 |
+
else: # Medium volatility
|
1431 |
+
if means[regime_idx] > 0:
|
1432 |
+
return "Moderate Bull"
|
1433 |
+
else:
|
1434 |
+
return "Moderate Bear"
|
1435 |
+
|
1436 |
if len(returns) < 50:
|
1437 |
+
return {"regime": "Normal Market", "probabilities": [1.0], "volatility": returns.std()}
|
1438 |
|
1439 |
try:
|
1440 |
if HMM_AVAILABLE:
|
|
|
1462 |
regime_means = model.means_.flatten()
|
1463 |
regime_vols = np.sqrt(model.covars_.diagonal(axis1=1, axis2=2)) if model.covariance_type == "full" else np.sqrt(model.covars_)
|
1464 |
|
1465 |
+
# Convert regime index to descriptive name
|
1466 |
+
regime_name = get_regime_name(int(current_regime), regime_means.tolist(), regime_vols.tolist())
|
1467 |
+
|
1468 |
return {
|
1469 |
+
"regime": regime_name,
|
1470 |
+
"regime_index": int(current_regime),
|
1471 |
"probabilities": regime_probs[-1].tolist(),
|
1472 |
"means": regime_means.tolist(),
|
1473 |
"volatilities": regime_vols.tolist(),
|
|
|
1484 |
vol_percentile = volatility.iloc[-1] / volatility.quantile(0.8)
|
1485 |
|
1486 |
if vol_percentile > 1.2:
|
1487 |
+
regime_name = "High Volatility Market"
|
1488 |
regime = 2 # High volatility regime
|
1489 |
elif vol_percentile < 0.8:
|
1490 |
+
regime_name = "Low Volatility Market"
|
1491 |
regime = 0 # Low volatility regime
|
1492 |
else:
|
1493 |
+
regime_name = "Normal Market"
|
1494 |
regime = 1 # Normal regime
|
1495 |
|
1496 |
return {
|
1497 |
+
"regime": regime_name,
|
1498 |
+
"regime_index": regime,
|
1499 |
"probabilities": [0.1, 0.8, 0.1] if regime == 1 else [0.8, 0.1, 0.1] if regime == 0 else [0.1, 0.1, 0.8],
|
1500 |
"volatility": volatility.iloc[-1],
|
1501 |
"method": "Volatility-based"
|
1502 |
}
|
1503 |
except Exception as e:
|
1504 |
print(f"Warning: Regime detection failed: {str(e)}")
|
1505 |
+
return {"regime": "Normal Market", "regime_index": 1, "probabilities": [1.0], "volatility": returns.std(), "method": "Fallback"}
|
1506 |
|
1507 |
def calculate_advanced_risk_metrics(df: pd.DataFrame, market_returns: pd.Series = None,
|
1508 |
risk_free_rate: float = 0.02) -> Dict:
|