Tonic commited on
Commit
542229d
·
verified ·
1 Parent(s): ef5069d

improve regime detection

Browse files
Files changed (1) hide show
  1. app.py +50 -4
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": 1, "probabilities": [1.0], "volatility": returns.std()}
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": int(current_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": 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: