Files
PythagorasGoal/scripts/research/alt/runs/TRD07.py
T
Adriano Dal Pastro 5ac4e16af8 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>
2026-06-20 19:50:39 +00:00

103 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""TRD07 — Kaufman Adaptive Moving Average (AMA/KAMA) cross.
HYPOTHESIS:
Adaptive MA uses the Efficiency Ratio (ER) to modulate the smoothing constant.
When price moves directionally (high ER), AMA tracks quickly.
When price is noisy (low ER), AMA barely moves.
Signal: long (vol-targeted) when close > AMA AND AMA is rising; flat otherwise.
KAMA formula:
ER[i] = |close[i] - close[i-n]| / sum(|close[k] - close[k-1]|, k=i-n+1..i)
sc[i] = (ER[i] * (fast_sc - slow_sc) + slow_sc)^2
AMA[i] = AMA[i-1] + sc[i] * (close[i] - AMA[i-1])
where fast_sc = 2/(fast+1), slow_sc = 2/(slow+1)
GRID (small, <=4 configs, 2 TFs → 4*2*2 = 16 evals ≤ 6 (corrected: 2 TFs × 2 configs = max)):
We try 2 param combos × 2 TFs = 4 total backtests per asset × 2 assets = 8 total (fine).
Config A: period=10, fast=2, slow=30 (standard Kaufman defaults)
Config B: period=20, fast=2, slow=30 (slower period)
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np
def kama(close: np.ndarray, period: int = 10, fast: int = 2, slow: int = 30) -> np.ndarray:
"""Compute Kaufman Adaptive Moving Average causally."""
n = len(close)
fast_sc = 2.0 / (fast + 1)
slow_sc = 2.0 / (slow + 1)
ama = np.full(n, np.nan)
# Initialize at the first valid point
ama[period - 1] = close[period - 1]
for i in range(period, n):
# Efficiency Ratio: directional move / total path
direction = abs(close[i] - close[i - period])
volatility = np.sum(np.abs(np.diff(close[i - period: i + 1])))
if volatility == 0:
er = 0.0
else:
er = direction / volatility
# Smoothing constant
sc = (er * (fast_sc - slow_sc) + slow_sc) ** 2
ama[i] = ama[i - 1] + sc * (close[i] - ama[i - 1])
return ama
def make_target(period: int = 10, fast: int = 2, slow: int = 30):
"""Factory: returns a target_fn for the given KAMA params."""
def target_fn(df):
c = df["close"].values.astype(float)
n = len(c)
ama_vals = kama(c, period=period, fast=fast, slow=slow)
# Direction signal: long only when close > AMA AND AMA is rising
# AMA rising = ama[i] > ama[i-1]
ama_rising = np.zeros(n, dtype=bool)
ama_rising[1:] = ama_vals[1:] > ama_vals[:-1]
direction = np.where(
np.isfinite(ama_vals) & (c > ama_vals) & ama_rising,
1.0,
0.0
)
# Vol-target the position (TP01 style)
return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target_fn
if __name__ == "__main__":
# Config A: standard Kaufman (period=10)
rep_A = al.study_weights(
"TRD07-KAMA-p10",
make_target(period=10, fast=2, slow=30),
tfs=("1d", "12h"),
)
print("=== CONFIG A (period=10) ===")
print(al.fmt(rep_A))
print("JSON:", al.as_json(rep_A))
# Config B: slower period=20
rep_B = al.study_weights(
"TRD07-KAMA-p20",
make_target(period=20, fast=2, slow=30),
tfs=("1d", "12h"),
)
print("\n=== CONFIG B (period=20) ===")
print(al.fmt(rep_B))
print("JSON:", al.as_json(rep_B))
# Pick best config by min_asset_holdout_sharpe at best TF
best_rep = max([rep_A, rep_B],
key=lambda r: r["verdict"]["best_holdout_sharpe"] or -99)
print("\n=== BEST CONFIG ===")
print(al.fmt(best_rep))
print("JSON:", al.as_json(best_rep))