research(alt): sweep 104 strategie alternative su Deribit (153 agenti) + marginal scorer

Ondata di ricerca onesta a largo spettro su BTC/ETH+DVOL certificati: 104 ipotesi
distinte (11 famiglie), un agente-finder per ipotesi, verifica avversariale a 3
scettici sui promettenti, sintesi (153 agenti totali). Esito: NIENTE di nuovo regge
-> conferma del soffitto strutturale ~1.3 BTC/ETH-direzionale; lo stack
TP01+XS01+VRP01 resta imbattuto.

- altlib.py: harness condiviso vettoriale leak-free (eval_weights/study_weights,
  fee-sweep, both-asset + hold-out 2025+). Riproduce i numeri canonici di TP01.
- MARGINAL SCORER (study_marginal/marginal_vs_tp01): Sharpe INCREMENTALE vs baseline
  TP01 (corr, blend uplift OOS, alpha residua) + jackknife OOS (clean-year +
  drop-best-month). earns_slot = abs!=FAIL & ADDS & robust_oos. Smaschera gli overlay
  su TSMOM con PASS assoluti fasulli (CMB04, VOL11, ...) e il falso positivo KAMA
  (ADDS ma muore al jackknife).
- runs/*.py (104) script riproducibili per ipotesi; wf_altstrat.js workflow.
- Verdetto: 0 candidati deployabili; 2 LEAD fragili (VOL08, STA05_LS) da forward-monitor.
- test_marginal_scorer.py blocca baseline + invarianti. Suite: 32 verde.

Diario: docs/diary/2026-06-20-alt-strategies-100agent-sweep.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-20 19:50:39 +00:00
parent bf84bc91e2
commit 5ac4e16af8
111 changed files with 16924 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
"""XAS04 — Lead-lag BTC->ETH
HYPOTHESIS: BTC returns lead ETH returns. ETH position = sign of BTC lagged return.
We evaluate on ETH series with BTC-derived signals. BTC and ETH data must be at the SAME
timeframe so that timestamp alignment is exact (no cross-TF look-ahead).
CAUSAL GUARANTEE:
- BTC and ETH are loaded at the SAME timeframe (1d or 12h).
- We align BTC to ETH by merging on common timestamps (inner/exact match).
- target[i] uses BTC close[i] (same bar as ETH close[i]) -> held during bar i+1.
- The altlib eval_weights shift handles the i->i+1 transition.
- No cross-TF artifacts.
CRITICAL BUG AVOIDED: loading BTC at 1d and aligning to ETH at 12h creates look-ahead
because the 1d bar timestamp (midnight) has the day's FINAL close, so the midnight 12h bar
gets the full day's close which is the FUTURE relative to the midnight price.
FIX: always use the same TF for both BTC and ETH.
CONFIGS TESTED:
1. Sign of BTC 1-bar return (pure lag-1 momentum applied to ETH)
2. BTC EMA5/20 cross -> ETH direction (BTC trend applied to ETH)
3. BTC TSMOM multi-horizon (30/90/180d) -> ETH direction
4. Blend: require BTC lag-1 AND BTC EMA trend to agree before entering ETH
"""
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 _align_same_tf(eth_df: pd.DataFrame, btc_df: pd.DataFrame) -> np.ndarray:
"""Align BTC close to ETH timestamps using exact same-TF merge.
Both DataFrames have the SAME timeframe, so merge on timestamp directly.
Returns BTC close values aligned to ETH bar indices, NaN where missing."""
eth_ts = eth_df["timestamp"].astype("int64")
btc_df2 = btc_df[["timestamp", "close"]].copy()
btc_df2["timestamp"] = btc_df2["timestamp"].astype("int64")
btc_df2 = btc_df2.rename(columns={"close": "btc_close"})
merged = eth_ts.to_frame().merge(btc_df2, on="timestamp", how="left")
return merged["btc_close"].values.astype(float)
def make_target_lag1(tf: str):
"""Config 1: Sign of BTC 1-bar return -> ETH vol-targeted position."""
btc_df = al.get("BTC", tf)
def target_fn(df):
# Align BTC close to ETH at same TF
btc_c = _align_same_tf(df, btc_df)
n = len(df)
# BTC 1-bar lagged return: r[i] = BTC_close[i] / BTC_close[i-1] - 1
btc_ret = np.zeros(n)
btc_ret[1:] = btc_c[1:] / btc_c[:-1] - 1.0
# Direction = sign of BTC return
direction = np.sign(btc_ret)
direction[~np.isfinite(direction)] = 0.0
direction[:5] = 0.0 # warmup
# Vol-target position on ETH
return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target_fn
def make_target_ema(tf: str, ema_fast: int = 5, ema_slow: int = 20):
"""Config 2: BTC EMA cross -> ETH direction (long-flat)."""
btc_df = al.get("BTC", tf)
def target_fn(df):
btc_c = _align_same_tf(df, btc_df)
n = len(df)
fast = al.ema(btc_c, ema_fast)
slow = al.ema(btc_c, ema_slow)
direction = np.where(fast > slow, 1.0, 0.0)
direction[~np.isfinite(direction)] = 0.0
direction[:ema_slow + 5] = 0.0 # warmup
return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target_fn
def make_target_tsmom(tf: str):
"""Config 3: BTC TSMOM multi-horizon (30/90/180 day) -> ETH direction (long-flat)."""
btc_df = al.get("BTC", tf)
def target_fn(df):
btc_c = _align_same_tf(df, btc_df)
n = len(df)
bpd = al.bars_per_day(df)
signal = np.zeros(n)
for days in (30, 90, 180):
h = int(days * bpd)
if h < n:
s = np.full(n, np.nan)
valid = ~np.isnan(btc_c) & (np.roll(btc_c, h) != 0)
s[h:] = np.sign(btc_c[h:] / btc_c[:-h] - 1.0)
signal = signal + np.nan_to_num(s)
direction = np.clip(np.sign(signal), 0, None) # long-flat
direction[:int(180 * bpd) + 5] = 0.0
return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target_fn
def make_target_blend(tf: str, lag: int = 1, ema_span: int = 10):
"""Config 4: Blend BTC lag-1 sign + BTC EMA trend; enter ETH only when both agree."""
btc_df = al.get("BTC", tf)
def target_fn(df):
btc_c = _align_same_tf(df, btc_df)
n = len(df)
# Signal 1: BTC 1-bar lag sign
btc_ret = np.zeros(n)
btc_ret[lag:] = btc_c[lag:] / btc_c[:-lag] - 1.0
sig1 = np.sign(btc_ret)
sig1[:lag + 3] = 0.0
# Signal 2: BTC EMA momentum
fast = al.ema(btc_c, ema_span)
slow = al.ema(btc_c, ema_span * 4)
sig2 = np.where(fast > slow, 1.0, 0.0)
sig2[:ema_span * 4 + 5] = 0.0
# Both must agree (long ETH only when BTC shows positive momentum AND positive lag)
direction = np.where((sig1 > 0) & (sig2 > 0), 1.0, 0.0)
direction[~np.isfinite(direction)] = 0.0
return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target_fn
if __name__ == "__main__":
print("XAS04 — Lead-lag BTC->ETH (same-TF, causal alignment)")
print("=" * 70)
# We test on both 1d and 12h but use SAME TF for BTC signal source.
# This avoids the cross-TF look-ahead artifact.
# The study_weights will apply the function to BOTH BTC and ETH at each TF.
# For BTC asset: BTC signal applied to BTC (degenerate = BTC follows BTC lag)
# For ETH asset: BTC signal applied to ETH (the actual lead-lag hypothesis)
# Config 1: pure lag-1 BTC signal -> run on 1d and 12h
print("\n--- C1: Lag-1 BTC return sign -> ETH (1d) ---")
rep_c1_1d = al.study_weights(
"XAS04-C1-lag1-1d",
make_target_lag1("1d"),
tfs=("1d",)
)
print(al.fmt(rep_c1_1d))
print("\n--- C1: Lag-1 BTC return sign -> ETH (12h) ---")
rep_c1_12h = al.study_weights(
"XAS04-C1-lag1-12h",
make_target_lag1("12h"),
tfs=("12h",)
)
print(al.fmt(rep_c1_12h))
print("\n--- C2: BTC EMA5/20 cross -> ETH (1d) ---")
rep_c2 = al.study_weights(
"XAS04-C2-ema5x20-1d",
make_target_ema("1d", 5, 20),
tfs=("1d",)
)
print(al.fmt(rep_c2))
print("\n--- C3: BTC TSMOM -> ETH (1d) ---")
rep_c3 = al.study_weights(
"XAS04-C3-tsmom-1d",
make_target_tsmom("1d"),
tfs=("1d",)
)
print(al.fmt(rep_c3))
print("\n--- C4: BTC blend lag+ema -> ETH (1d) ---")
rep_c4 = al.study_weights(
"XAS04-C4-blend-1d",
make_target_blend("1d", lag=1, ema_span=10),
tfs=("1d",)
)
print(al.fmt(rep_c4))
# Identify best config
all_reps = [rep_c1_1d, rep_c1_12h, rep_c2, rep_c3, rep_c4]
best_rep = max(all_reps, key=lambda r: r["verdict"].get("best_holdout_sharpe") or -999)
print("\n" + "=" * 70)
print(f"BEST CONFIG: {best_rep['name']} -> {best_rep['verdict']['grade']}")
print(al.fmt(best_rep))
print("\nJSON:", al.as_json(best_rep))