"""Short-horizon mean reversion — contrarian z-score reversal.

Rationale: a liquidity-provision / overreaction-reversal premium that is real in some markets and
horizons (and absent/negative in trending ones). Long when price is z_entry std BELOW its rolling
mean, short when z_entry ABOVE; flat in between. Decision at t-1 drives return t (no lookahead).
"""
from __future__ import annotations

import numpy as np

from fxhnt.domain.models import PriceSeries
from fxhnt.domain.strategies.base import register, rolling_mean, rolling_std


class MeanReversion:
    kind = "mean_reversion"
    rationale = "short-horizon mean reversion: liquidity-provision / overreaction-reversal premium"

    def positions(self, prices: PriceSeries, params: dict[str, float]) -> np.ndarray:
        window = int(params.get("window", 20))
        z_entry = float(params.get("z", 1.0))
        c = prices.close
        ma = rolling_mean(c, window)
        sd = rolling_std(c, window)
        z = np.divide(c - ma, sd, out=np.zeros_like(c), where=sd > 0)
        signal = np.where(z < -z_entry, 1.0, np.where(z > z_entry, -1.0, 0.0))
        signal[:window] = 0.0
        pos = np.zeros(len(c))
        pos[1:] = signal[:-1]
        return pos


register(MeanReversion())
