"""Return Autocorrelation — exploits microstructure return patterns (IC=+0.025).

Combines two time-tested quantitative signals:
1. Negative 1m autocorrelation: short-term bounce/mean-revert effect
2. Positive 5m autocorrelation: medium-term momentum/continuation

Weights: 60% mean-revert (1m) + 40% momentum (5m).
Only signals when combined strength > 0.15 (avoids noise).
"""
from collections import deque
from vanta.tracker import TrackerBase
from vanta.indicators import ATR, SMA


class _SignalScaler:
    def __init__(self, atr_period=14, scale_period=60, target_risk=0.003):
        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 ReturnAutocorrTracker(TrackerBase):
    """Dual-horizon return autocorrelation strategy.

    Walk-forward results:
        BTC IS: IC=+0.032  |  BTC OOS: IC=+0.016
        ETH IS: IC=+0.054  |  ETH OOS: IC= 0.000
    """

    def __init__(self):
        super().__init__()
        self.scaler = _SignalScaler()
        self.returns_1m = deque(maxlen=20)
        self.returns_5m = deque(maxlen=12)
        self._prev_1m = None
        self._prev_5m = None

    def tick(self, data):
        super().tick(data)
        for c in data.get("candles_1m", []):
            p = float(c["close"])
            self.scaler.update(float(c["high"]), float(c["low"]), p)
            if self._prev_1m is not None and self._prev_1m > 0:
                self.returns_1m.append((p - self._prev_1m) / self._prev_1m)
            self._prev_1m = p
        for c in data.get("candles_5m", []):
            p = float(c["close"])
            if self._prev_5m is not None and self._prev_5m > 0:
                self.returns_5m.append((p - self._prev_5m) / self._prev_5m)
            self._prev_5m = p

    def predict(self, symbol, horizon_seconds, step_seconds):
        if len(self.returns_1m) < 10 or len(self.returns_5m) < 6 or not self.scaler.ready:
            return {"expected_return": 0.0}

        recent_1m = sum(list(self.returns_1m)[-3:]) / 3
        recent_5m = sum(list(self.returns_5m)[-3:]) / 3

        raw = 0.6 * (-recent_1m * 100) + 0.4 * (recent_5m * 50)
        raw = max(-1.0, min(1.0, raw))

        if abs(raw) < 0.15:
            return {"expected_return": 0.0}

        return {"expected_return": self.scaler.scale(raw)}
