""" Moving Average Strategy Configurable trend following strategy. - Long when Price > MA(period) - Short when Price < MA(period) """ from typing import Dict, Any, List, Optional from .base import BaseStrategy, StrategySignal, SignalType class MAStrategy(BaseStrategy): """ Configurable Moving Average Strategy. Config: - period: int - MA period (default: 44) """ DEFAULT_PERIOD = 44 @property def name(self) -> str: return "ma_trend" @property def required_indicators(self) -> List[str]: # Dynamic based on config period = self.config.get('period', self.DEFAULT_PERIOD) return [f"ma{period}"] @property def display_name(self) -> str: return "MA Strategy" @property def description(self) -> str: return "Configurable Moving Average strategy. Parameters: period (5-500, default: 44). Goes long when price > MA(period), short when price < MA(period). Optional multi-timeframe trend filter available." def analyze( self, candle: Dict[str, Any], indicators: Dict[str, float], current_position: Optional[Dict[str, Any]] = None ) -> StrategySignal: period = self.config.get('period', self.DEFAULT_PERIOD) ma_key = f"ma{period}" price = candle['close'] ma_value = indicators.get(ma_key) if ma_value is None: return StrategySignal(SignalType.HOLD, 0.0, f"MA{period} not available") # Current position state is_long = current_position and current_position.get('type') == 'long' is_short = current_position and current_position.get('type') == 'short' # Logic: Price > MA -> Bullish if price > ma_value: if is_long: return StrategySignal(SignalType.HOLD, 1.0, f"Price {price:.2f} > MA{period} {ma_value:.2f}. Stay Long.") elif is_short: return StrategySignal(SignalType.CLOSE_SHORT, 1.0, f"Price {price:.2f} crossed above MA{period} {ma_value:.2f}. Close Short.") else: return StrategySignal(SignalType.OPEN_LONG, 1.0, f"Price {price:.2f} > MA{period} {ma_value:.2f}. Open Long.") # Logic: Price < MA -> Bearish elif price < ma_value: if is_short: return StrategySignal(SignalType.HOLD, 1.0, f"Price {price:.2f} < MA{period} {ma_value:.2f}. Stay Short.") elif is_long: return StrategySignal(SignalType.CLOSE_LONG, 1.0, f"Price {price:.2f} crossed below MA{period} {ma_value:.2f}. Close Long.") else: return StrategySignal(SignalType.OPEN_SHORT, 1.0, f"Price {price:.2f} < MA{period} {ma_value:.2f}. Open Short.") return StrategySignal(SignalType.HOLD, 0.0, f"Price == MA{period}")