"""SEA03 — Weekend Effect
HYPOTHESIS: Crypto prices behave differently on weekend bars vs weekday bars.
We test long/flat (and long/short) positions on weekend bars only,
with the direction chosen by expanding in-sample sign of weekend vs weekday returns.

VARIANTS tested (<=4 param sets, <=6 total backtests with 2 TFs):
  V1: Fixed long on weekends (Sat/Sun bars), flat on weekdays
  V2: Expanding-sign direction on weekends (long or short), flat on weekdays
  V3: V2 + vol-targeting
  Best config selected by min_asset_holdout_sharpe.

We use 1d bars (weekend = day_of_week in {5,6}: Saturday, Sunday).
On hourly bars there may not be a clean weekend partition, so we use 1d only.
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np
import pandas as pd


def _is_weekend(df: pd.DataFrame) -> np.ndarray:
    """Return boolean array: True if this bar is a weekend bar (Sat or Sun)."""
    dt = pd.to_datetime(df["datetime"], utc=True)
    return (dt.dt.dayofweek >= 5).values  # 5=Sat, 6=Sun


def _expanding_weekend_sign(df: pd.DataFrame) -> np.ndarray:
    """For each bar, compute expanding-mean return on weekend bars vs weekday bars.
    Return +1 if weekend historically outperforms weekday, else -1.
    This is causal: at bar i we use only returns from bars 0..i-1.
    Returns array of +1/-1 (same sign for all bars on the same day as rolling expands).
    """
    c = df["close"].values.astype(float)
    r = al.simple_returns(c)
    is_wk = _is_weekend(df)

    # Expanding cumulative mean of weekend returns and weekday returns up to bar i-1
    # We look at sign(mean_wkend - mean_wkday) to decide direction for bar i
    sign_arr = np.ones(len(r))  # default +1 (long)

    cum_wkend_sum = 0.0
    cum_wkend_n = 0
    cum_wkday_sum = 0.0
    cum_wkday_n = 0

    for i in range(1, len(r)):
        # Use return of bar i-1
        if is_wk[i - 1]:
            cum_wkend_sum += r[i - 1]
            cum_wkend_n += 1
        else:
            cum_wkday_sum += r[i - 1]
            cum_wkday_n += 1

        if cum_wkend_n >= 5 and cum_wkday_n >= 5:
            mean_wk = cum_wkend_sum / cum_wkend_n
            mean_wd = cum_wkday_sum / cum_wkday_n
            sign_arr[i] = 1.0 if mean_wk >= mean_wd else -1.0
        # else: not enough history, default +1

    return sign_arr


# ---- Variant 1: Fixed long on weekends, flat on weekdays ----
def v1_fixed_long(df: pd.DataFrame) -> np.ndarray:
    is_wk = _is_weekend(df)
    # position: +1 on weekend bars, 0 on weekday bars
    return is_wk.astype(float)


# ---- Variant 2: Expanding-sign direction on weekends, flat on weekdays ----
def v2_expanding_sign(df: pd.DataFrame) -> np.ndarray:
    is_wk = _is_weekend(df)
    sign = _expanding_weekend_sign(df)
    # Long or short on weekend depending on expanding sign, flat on weekdays
    return np.where(is_wk, sign, 0.0)


# ---- Variant 3: V2 + vol targeting ----
def v3_voltarget(df: pd.DataFrame) -> np.ndarray:
    direction = v2_expanding_sign(df)
    return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)


# ---- Variant 4: Long weekdays (inverse hypothesis) ----
def v4_fixed_long_weekday(df: pd.DataFrame) -> np.ndarray:
    is_wk = _is_weekend(df)
    return (~is_wk).astype(float)


if __name__ == "__main__":
    variants = [
        ("SEA03-V1-weekend-long", v1_fixed_long),
        ("SEA03-V2-expanding-sign", v2_expanding_sign),
        ("SEA03-V3-voltarget", v3_voltarget),
        ("SEA03-V4-weekday-long", v4_fixed_long_weekday),
    ]

    results = []
    for name, fn in variants:
        print(f"\nRunning {name}...")
        rep = al.study_weights(name, fn, tfs=("1d",))
        print(al.fmt(rep))
        results.append(rep)

    # Pick best config by min_asset_holdout_sharpe across all cells
    best_rep = max(results, key=lambda r: r["verdict"].get("best_holdout_sharpe", -99))
    print("\n\n=== BEST CONFIG ===")
    print(al.fmt(best_rep))
    print("JSON:", al.as_json(best_rep))
