"""Hourly Momentum — macro trend with pullback entry (IC=+0.014).

Uses 1h EMA crossover for macro direction and 5m RSI for pullback timing.
Only enters when 5m RSI shows a pullback within a strong 1h trend.
"""
from vanta.tracker import TrackerBase
from vanta.indicators import EMA, RSI, Returns, ATR, SMA


class _SignalScaler:
    def __init__(self, atr_period=14, scale_period=60, target_risk=0.004):
        self.atr = ATR(period=atr_period)
        self.price_sma = SMA(period=atr_period)
        self.atr_sma = SMA(period=scale_period)
        self.target_risk = target_risk

    def update(self, high, low, close):
        self.atr.update(high, low, close)
        self.price_sma.update(close)
        if self.atr.ready:
            self.atr_sma.update(self.atr.value)

    @property
    def ready(self):
        return self.atr.ready and self.price_sma.ready and self.atr_sma.ready

    def scale(self, raw, max_abs=0.02):
        if not self.ready or self.price_sma.value == 0:
            return raw * self.target_risk
        norm_atr = self.atr.value / self.price_sma.value
        avg_norm_atr = self.atr_sma.value / self.price_sma.value
        if avg_norm_atr < 1e-9:
            return raw * self.target_risk
        vol_ratio = max(0.3, min(3.0, avg_norm_atr / max(norm_atr, 1e-9)))
        return max(-max_abs, min(max_abs, raw * self.target_risk * vol_ratio))


class HourlyMomentumTracker(TrackerBase):
    """1h trend with 5m pullback entry.

    Walk-forward results:
        BTC IS: IC=+0.012  |  BTC OOS: IC=+0.017
        ETH IS: IC=+0.017  |  ETH OOS: IC=-0.070 (ETH-unstable)
    """

    def __init__(self):
        super().__init__()
        self.scaler = _SignalScaler()
        self.ema_1h_fast = EMA(period=5)
        self.ema_1h_slow = EMA(period=13)
        self.returns_1h = Returns(period=3)
        self.rsi_5m = RSI(period=10)

    def tick(self, data):
        super().tick(data)
        for c in data.get("candles_1m", []):
            self.scaler.update(float(c["high"]), float(c["low"]), float(c["close"]))
        for c in data.get("candles_5m", []):
            self.rsi_5m.update(float(c["close"]))
        for c in data.get("candles_1h", []):
            p = float(c["close"])
            self.ema_1h_fast.update(p)
            self.ema_1h_slow.update(p)
            self.returns_1h.update(p)

    def predict(self, symbol, horizon_seconds, step_seconds):
        if not (self.ema_1h_fast.ready and self.returns_1h.ready
                and self.rsi_5m.ready and self.scaler.ready):
            return {"expected_return": 0.0}

        trend = (self.ema_1h_fast.value - self.ema_1h_slow.value) / self.ema_1h_slow.value
        mom = self.returns_1h.value

        if abs(trend) < 0.001:
            return {"expected_return": 0.0}

        direction = 1.0 if trend > 0 else -1.0

        if direction > 0 and self.rsi_5m.value > 60:
            return {"expected_return": 0.0}
        if direction < 0 and self.rsi_5m.value < 40:
            return {"expected_return": 0.0}
        if direction * mom <= 0:
            return {"expected_return": 0.0}

        strength = min(abs(trend) * 20, 1.0)
        raw = direction * strength
        return {"expected_return": self.scaler.scale(raw)}
