Download strategy/selector.py from raghava4u/Trading-Bot-M20: direct link, hf CLI and curl.
- Browser
- Download file 3.92 kB
-
https://huggingface.co/raghava4u/Trading-Bot-M20/resolve/main/strategy/selector.py
- Command line
-
hf download hf://raghava4u/Trading-Bot-M20/strategy/selector.py
-
curl -L -o selector.py https://huggingface.co/raghava4u/Trading-Bot-M20/resolve/main/strategy/selector.py
3.92 kB
| """ | |
| strategy/selector.py — Regime detector and strategy selector. | |
| Determines if market is trending or choppy, selects appropriate strategy. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import numpy as np | |
| import pandas as pd | |
| import config | |
| from contracts import TechnicalScore, PriceTarget | |
| from signals.technical import compute_atr, compute_ema | |
| from strategy.base import Strategy | |
| from strategy.momentum import MomentumStrategy | |
| from strategy.mean_reversion import MeanReversionStrategy | |
| from strategy.swing import SwingStrategy | |
| logger = logging.getLogger("trading_system.selector") | |
| _momentum = MomentumStrategy() | |
| _mean_reversion = MeanReversionStrategy() | |
| _swing = SwingStrategy() | |
| def detect_regime(df_1h: pd.DataFrame) -> str: | |
| """Detect market regime from hourly bars. | |
| Uses ADX-like directional calculation and ATR trend to determine: | |
| - "trending": strong directional movement → use momentum | |
| - "choppy": range-bound, low directional movement → use mean reversion | |
| Args: | |
| df_1h: 1-hour OHLCV bars (need at least 30 bars) | |
| Returns: "trending" or "choppy" | |
| """ | |
| if df_1h is None or len(df_1h) < 30: | |
| return "trending" # default to momentum if insufficient data | |
| close = df_1h["close"] | |
| # Method 1: EMA slope. Steep EMA(20) slope = trending | |
| ema20 = compute_ema(close, 20) | |
| ema_vals = ema20.dropna() | |
| if len(ema_vals) >= 5: | |
| recent_slope = (float(ema_vals.iloc[-1]) - float(ema_vals.iloc[-5])) / float(ema_vals.iloc[-5]) | |
| else: | |
| recent_slope = 0.0 | |
| # Method 2: ATR ratio. High ATR / price = volatile trending | |
| atr = compute_atr(df_1h, 14) | |
| if not atr.dropna().empty: | |
| atr_pct = float(atr.iloc[-1]) / float(close.iloc[-1]) | |
| else: | |
| atr_pct = 0.0 | |
| # Method 3: Price range compression. If recent range < 50% of wider range = choppy | |
| recent_range = float(close.tail(10).max() - close.tail(10).min()) | |
| wider_range = float(close.tail(30).max() - close.tail(30).min()) | |
| range_ratio = recent_range / wider_range if wider_range > 0 else 0.5 | |
| # Decision: trending if strong slope + normal ATR, or expanding range | |
| trending_score = 0 | |
| if abs(recent_slope) > 0.005: # > 0.5% slope | |
| trending_score += 1 | |
| if atr_pct > 0.008: # > 0.8% ATR/price | |
| trending_score += 1 | |
| if range_ratio > 0.6: # range expanding | |
| trending_score += 1 | |
| regime = "trending" if trending_score >= 2 else "choppy" | |
| logger.info( | |
| "Regime detection: slope=%.4f, atr_pct=%.4f, range_ratio=%.3f -> %s", | |
| recent_slope, atr_pct, range_ratio, regime, | |
| ) | |
| return regime | |
| def select_strategy(df_1h: pd.DataFrame | None = None) -> Strategy: | |
| """Select the best strategy based on config or market regime.""" | |
| # If STRATEGY_MODE is set to 'swing', always use swing | |
| strategy_mode = getattr(config, "STRATEGY_MODE", "auto") | |
| if strategy_mode == "swing": | |
| logger.info("Selected: SwingStrategy (configured via STRATEGY_MODE)") | |
| return _swing | |
| # Auto-select based on regime | |
| regime = detect_regime(df_1h) | |
| if regime == "trending": | |
| logger.info("Selected: MomentumStrategy (trending regime)") | |
| return _momentum | |
| else: | |
| logger.info("Selected: MeanReversionStrategy (choppy regime)") | |
| return _mean_reversion | |
| def generate_signal( | |
| symbol: str, | |
| df_5m: pd.DataFrame, | |
| df_1h: pd.DataFrame | None = None, | |
| df_1d: pd.DataFrame | None = None, | |
| open_positions: dict[str, str] | None = None, | |
| corr_matrix: pd.DataFrame | None = None, | |
| ) -> tuple[TechnicalScore, PriceTarget]: | |
| """Auto-select strategy based on regime and generate signal.""" | |
| strategy = select_strategy(df_1h) | |
| return strategy.generate_signal( | |
| symbol, df_5m, df_1h, df_1d, open_positions, corr_matrix | |
| ) | |