Files
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

102 lines
3.1 KiB
Python
Raw Permalink 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.
"""TRD08 — Hull MA slope strategy.
HYPOTHESIS: HMA(n); long when HMA rising (slope > 0), flat when falling.
Grid: n in {20, 50, 100}.
Hull Moving Average (causal):
WMA(n) = weighted moving average with linear weights
HMA(n) = WMA(sqrt(n), 2*WMA(n//2) - WMA(n))
Position sizing: vol-targeted (20% target, 2x cap), long-flat only.
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np
from numpy.lib.stride_tricks import as_strided
def wma_vectorized(x: np.ndarray, win: int) -> np.ndarray:
"""Causal weighted moving average — vectorized via cumsum trick."""
n = len(x)
# Use pandas for clean rolling WMA: sum(w_i * x_i) / sum(w_i)
# weights = 1, 2, ..., win
# We can compute via cumsum: WMA = (sum(i * x[t-i]) for i=1..win) / (win*(win+1)/2)
# Use a numerator via weighted cumsum
weights = np.arange(1, win + 1, dtype=float)
total_w = weights.sum()
result = np.full(n, np.nan)
# Efficient: build a 2D sliding window using stride tricks, then dot with weights
if n < win:
return result
# pad at start for alignment
# shape: (n - win + 1, win)
shape = (n - win + 1, win)
strides = (x.strides[0], x.strides[0])
windows = as_strided(x, shape=shape, strides=strides)
result[win - 1:] = windows @ weights / total_w
return result
def hma(x: np.ndarray, n: int) -> np.ndarray:
"""Causal Hull Moving Average."""
half_n = max(2, n // 2)
sqrt_n = max(2, int(round(np.sqrt(n))))
wma_full = wma_vectorized(x, n)
wma_half = wma_vectorized(x, half_n)
# 2 * WMA(n//2) - WMA(n)
raw = 2.0 * wma_half - wma_full
# Apply WMA(sqrt(n)) to the raw series
return wma_vectorized(raw, sqrt_n)
def make_target(n: int):
"""Return a lambda that computes vol-targeted HMA slope signal."""
def target(df):
c = df["close"].values.astype(float)
h = hma(c, n)
# slope: hma[i] > hma[i-1] => rising => long
slope = np.zeros(len(h))
slope[1:] = np.where(h[1:] > h[:-1], 1.0, 0.0)
# NaN protection: flat when HMA not yet valid or slope undefined
nan_mask = np.isnan(h) | np.isnan(np.concatenate([[np.nan], h[:-1]]))
slope[nan_mask] = 0.0
# Vol-target
return al.vol_target(slope, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
return target
# Grid: n in {20, 50, 100} across timeframes {1d, 12h}
# 3 param sets × 2 TFs = 6 total backtests (within limit)
tfs = ("1d", "12h")
grid_n = [20, 50, 100]
best_rep = None
best_score = -999.0
best_n = grid_n[0]
for n in grid_n:
name = f"TRD08-HMA{n}"
rep = al.study_weights(name, make_target(n), tfs=tfs)
print(al.fmt(rep))
print("JSON:", al.as_json(rep))
# Score by best_holdout_sharpe
score = rep["verdict"].get("best_holdout_sharpe", rep["verdict"].get("min_asset_holdout_sharpe", -999))
if score > best_score:
best_score = score
best_rep = rep
best_n = n
print("\n" + "="*60)
print(f"BEST CONFIG: n={best_n}")
print(al.fmt(best_rep))
print("JSON:", al.as_json(best_rep))