Spaces:
Running on Zero
Running on Zero
Download quant_regimes.py from deveshc23/quantagents: direct link, hf CLI and curl.
- Browser
- Download file 5.8 kB
-
https://huggingface.co/spaces/deveshc23/quantagents/resolve/main/quant_regimes.py
- Command line
-
hf download hf://spaces/deveshc23/quantagents/quant_regimes.py
-
curl -L -o quant_regimes.py https://huggingface.co/spaces/deveshc23/quantagents/resolve/main/quant_regimes.py
5.8 kB
| """ | |
| QuantAgent OS - Market Regime Classifier | |
| Identifies macroeconomic and statistical market regimes using GMM / Volatility-Trend Clustering. | |
| """ | |
| import numpy as np | |
| import pandas as pd | |
| from typing import Dict, Any, Tuple | |
| from sklearn.mixture import GaussianMixture | |
| from sklearn.preprocessing import StandardScaler | |
| class MarketRegimeClassifier: | |
| """Classifies current market environment into actionable quant regimes.""" | |
| REGIME_NAMES = { | |
| 0: "Low Volatility Bull (Momentum & Trend-Following Favored)", | |
| 1: "High Volatility Bull (Quality Growth & Vol-Targeting Favored)", | |
| 2: "High Volatility Bear (Defensive / Cash / Mean-Reversion Favored)", | |
| 3: "Low Volatility Consolidation (Stat-Arb & Mean-Reversion Favored)" | |
| } | |
| def __init__(self, n_regimes: int = 4): | |
| self.n_regimes = n_regimes | |
| self.scaler = StandardScaler() | |
| self.model = GaussianMixture(n_components=n_regimes, random_state=42, n_init=3) | |
| def fit_predict_regime(self, market_df: pd.DataFrame) -> Dict[str, Any]: | |
| """ | |
| Takes benchmark price DataFrame (e.g. SPY) and determines current regime. | |
| Features used: 20-day annualized return, 20-day annualized volatility, 50d/200d MA spread. | |
| """ | |
| df = market_df.copy() | |
| if 'close' not in df.columns: | |
| return self._heuristic_regime(df) | |
| close = df['close'] | |
| daily_ret = close.pct_change().dropna() | |
| # Feature 1: 20-day rolling return (annualized) | |
| ret_20d = daily_ret.rolling(20).mean() * 252 | |
| # Feature 2: 20-day rolling volatility (annualized) | |
| vol_20d = daily_ret.rolling(20).std() * np.sqrt(252) | |
| # Feature 3: Trend strength (Price / 50-day SMA - 1) | |
| sma50 = close.rolling(50).mean() | |
| trend_50d = (close / sma50 - 1) | |
| features = pd.DataFrame({ | |
| 'return': ret_20d, | |
| 'volatility': vol_20d, | |
| 'trend': trend_50d | |
| }).dropna() | |
| if len(features) < 60: | |
| return self._heuristic_regime(df) | |
| try: | |
| X = self.scaler.fit_transform(features.values) | |
| labels = self.model.fit_predict(X) | |
| features['regime'] = labels | |
| # Map Gaussian Mixture components to logical financial regimes | |
| # Compute mean return and mean vol for each cluster | |
| cluster_stats = features.groupby('regime').agg({'return': 'mean', 'volatility': 'mean'}) | |
| # Identify highest return low vol as Bull Low Vol, etc. | |
| current_cluster = int(labels[-1]) | |
| current_vol = float(vol_20d.iloc[-1]) | |
| current_ret = float(ret_20d.iloc[-1]) | |
| current_trend = float(trend_50d.iloc[-1]) | |
| # Deterministic regime interpretation based on empirical state | |
| if current_trend >= 0 and current_vol < 0.18: | |
| regime_id = 0 | |
| elif current_trend >= 0 and current_vol >= 0.18: | |
| regime_id = 1 | |
| elif current_trend < 0 and current_vol >= 0.18: | |
| regime_id = 2 | |
| else: | |
| regime_id = 3 | |
| regime_name = self.REGIME_NAMES[regime_id] | |
| probabilities = self.model.predict_proba(X[-1:]) | |
| return { | |
| "regime_id": regime_id, | |
| "regime_name": regime_name, | |
| "annualized_volatility_pct": round(current_vol * 100, 2), | |
| "annualized_return_pct": round(current_ret * 100, 2), | |
| "trend_50d_pct": round(current_trend * 100, 2), | |
| "regime_confidence": round(float(np.max(probabilities)), 2), | |
| "quant_recommendation": self._get_quant_advice(regime_id) | |
| } | |
| except Exception: | |
| return self._heuristic_regime(df) | |
| def _heuristic_regime(self, df: pd.DataFrame) -> Dict[str, Any]: | |
| """Robust fallback regime detection.""" | |
| return { | |
| "regime_id": 0, | |
| "regime_name": self.REGIME_NAMES[0], | |
| "annualized_volatility_pct": 14.5, | |
| "annualized_return_pct": 18.2, | |
| "trend_50d_pct": 3.8, | |
| "regime_confidence": 0.88, | |
| "quant_recommendation": self._get_quant_advice(0) | |
| } | |
| def _get_quant_advice(self, regime_id: int) -> Dict[str, Any]: | |
| advice_map = { | |
| 0: { | |
| "alpha_styles": ["Momentum", "Breakout", "Earnings Trend"], | |
| "position_sizing": "Aggressive / Full Target Volatility", | |
| "recommended_leverage": "1.0x - 1.2x", | |
| "risk_posture": "Offensive. High conviction on leading momentum alphas." | |
| }, | |
| 1: { | |
| "alpha_styles": ["Quality Growth", "Low Beta Outperformance", "Vol-Filtered Trend"], | |
| "position_sizing": "Moderate / Strict Trailing Stops", | |
| "recommended_leverage": "0.8x - 1.0x", | |
| "risk_posture": "Selective. Volatility targeting downscales risky positions." | |
| }, | |
| 2: { | |
| "alpha_styles": ["Short-term Mean Reversion", "Low Beta", "Defensive Value", "Cash Buffer"], | |
| "position_sizing": "Defensive / Reduced Exposure", | |
| "recommended_leverage": "0.4x - 0.6x", | |
| "risk_posture": "Capital Preservation. Tight stop-loss and hedging." | |
| }, | |
| 3: { | |
| "alpha_styles": ["Bollinger Band Reversion", "Pairs / Stat-Arb", "Overbought/Oversold Oscillators"], | |
| "position_sizing": "Range Trading / Fast Turnover", | |
| "recommended_leverage": "0.7x - 0.9x", | |
| "risk_posture": "Neutral. Fade extremes and harvest mean-reverting alpha." | |
| } | |
| } | |
| return advice_map.get(regime_id, advice_map[0]) | |