"""Monthly seasonality — long if the current month is historically positive, short if negative.

Rationale: commodity storage/weather/harvest cycles are economically grounded and structurally
under-arbitraged. The signal is strictly causal (prior years only) and is validated against a
negative control on financials, which have no seasonal economics.

It is NOT shifted (unlike the close-derived kinds): seasonal_signal[t] depends only on the calendar
and prior years, so it is already known at t-1's close and aligned to day t. Shifting it would add a
spurious 1-day lag and misalign positions at month boundaries.
"""
from __future__ import annotations

import numpy as np

from fxhnt.domain.models import PriceSeries
from fxhnt.domain.seasonality import seasonal_signal
from fxhnt.domain.strategies.base import register


class Seasonality:
    kind = "seasonality"
    rationale = "commodity storage/weather/harvest cycles — economically grounded, structurally under-arbitraged; negative-control on financials guards against data-mining"

    def positions(self, prices: PriceSeries, params: dict[str, float]) -> np.ndarray:
        min_prior_years = int(params.get("min_prior_years", 3))
        _, sig = seasonal_signal(prices, min_prior_years=min_prior_years)
        pos: np.ndarray = np.zeros(len(sig))
        pos[sig > 0] = 1.0
        pos[sig < 0] = -1.0
        return pos   # long if month historically positive, short if negative; 0 during warmup / flat months


register(Seasonality())
