de72e3ce1f
Second agent wave (skyhook-improve-v2, 14 DD-reduction families, each adversarially verified by 2 skeptics) beats the prior winner on the only unmet goal (DD<30%). Winner = ASYM_LS -> promoted to engine as SKH01_V2_DD: same signal (ptn_n=45, vola[35,95], vol_lo=0, exit-bars 24/16) but exits switched from ATR to FIXED-PCT ASYMMETRIC — long sl4%/tp10%, short sl2%(tighter)/tp8%. The tight short %-SL caps the per-trade loss that forms the maxDD in vol spikes. Verified (sk.study, independent re-run): standalone maxDD BTC 21.4% / ETH 27.4% (<30%), minFull +0.99, minHold +1.26, causality 0/400 both assets, fee-surviving to 0.40%RT, marginal vs TP01 ADDS (corr 0.09, in-sample edge, robust_oos, multicut, clean-year +0.57), blend 0.75*TP01+0.25*SKH uplift_hold +0.87; blend 50/50 full 1.84/hold 1.59/DD 10.7%. Plateau (not knife-edge); both skeptics holds_up=high, killer=null. Engine: per-direction short exit overrides (exit_mode_short/sl_*_short/tp_*_short), backward-compatible (None -> symmetric, V1/intermediate-winner unchanged). +3 tests (8/8 pass). Lessons: DD is cut by changing the exit MECHANISM (%-SL, L/S asymmetry, ensembles), NOT by entry-only kill-switch / vol-target / cadence. PATTERN_CONF killed as overfit (knife-edge). PCTL_DD unverified (rate-limit) and ENS_PARAM/TPSL_DD recency/hedge-loaded -> forward-monitor. NOT yet wired to live sleeves: re-verify blend@0.25 + causality on execution code before deploy. Includes both waves' research scripts (runs/SKH_* wave 1, runs/SKH2_* wave 2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
73 lines
2.9 KiB
Python
73 lines
2.9 KiB
Python
"""SKH_R_EXPAND_study — final study() on the two best volatility-expansion configs.
|
|
|
|
We use the project's HONEST study() harness. Because the expansion regime is a STRUCTURAL
|
|
change (not expressible via SkyhookParams bands), we monkeypatch htf_features INSIDE
|
|
skyhooklib's namespace to our expansion-features for the duration of each study, so study()
|
|
runs the exact same leak-free FULL+HOLDOUT+fee-sweep+per-year machinery on our entries.
|
|
|
|
This is safe: we only swap the feature builder (regime def); pattern/composer/entry/exit and
|
|
all the eval code are unchanged. We restore the original after each study.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/skyhook")
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
import skyhooklib as sk
|
|
from src.strategies import skyhook as S
|
|
from src.strategies.skyhook import SkyhookParams
|
|
|
|
# import our feature builder
|
|
from SKH_R_EXPAND import expand_htf_features
|
|
|
|
ORIG_FEAT = S.htf_features
|
|
|
|
|
|
def make_patched_features(cfg):
|
|
def _feat(htf, p):
|
|
return expand_htf_features(htf, p, **cfg)
|
|
return _feat
|
|
|
|
|
|
def study_expand(name, p, cfg):
|
|
"""Run sk.study with htf_features patched to the expansion regime defined by cfg."""
|
|
patched = make_patched_features(cfg)
|
|
# skyhook_entries calls skyhook.htf_features via the module-level name S.htf_features.
|
|
S.htf_features = patched
|
|
try:
|
|
rep = sk.study(name, p)
|
|
caus = sk.causality(p, "BTC")
|
|
caus_eth = sk.causality(p, "ETH")
|
|
marg = sk.marginal(p)
|
|
finally:
|
|
S.htf_features = ORIG_FEAT
|
|
return rep, (caus, caus_eth), marg
|
|
|
|
|
|
if __name__ == "__main__":
|
|
p = SkyhookParams(ptn_n=55, sl_atr=2.5, tp_atr=6.0)
|
|
|
|
configs = {
|
|
# best DD-cut + above-V1 full, balanced volume gate (maxDD 34%)
|
|
"EXP_atr20vol20": dict(w_atr=20, k_atr=1.0, w_vol=20, k_vol=1.0),
|
|
# best hold-out / no volume gate (minFull 0.81, DD 40%)
|
|
"EXP_atr20volOFF": dict(w_atr=20, k_atr=1.0, w_vol=20, k_vol=0.0),
|
|
}
|
|
|
|
for name, cfg in configs.items():
|
|
print(f"\n########## {name} cfg={cfg} ##########")
|
|
rep, (caus, caus_eth), marg = study_expand(name, p, cfg)
|
|
print(sk.fmt(rep))
|
|
print(f"causality BTC={caus} ETH={caus_eth}")
|
|
print(f"marginal: verdict={marg.get('marginal_verdict')} corr_full={marg.get('corr_full')}"
|
|
f" blend_w25_uplift_hold={marg.get('blends',{}).get('w25',{}).get('uplift_hold')}")
|
|
print(f" has_insample_edge={marg.get('has_insample_edge')} is_hedge={marg.get('is_hedge')}"
|
|
f" robust_oos={marg.get('robust_oos')} clean_year_uplift={marg.get('clean_year_uplift')}"
|
|
f" multicut_persistent={marg.get('multicut_persistent')}")
|
|
v = rep["verdict"]
|
|
print(f"VERDICT[{name}]: grade={v['grade']} minFull={v['min_asset_full_sharpe']}"
|
|
f" minHold={v['min_asset_holdout_sharpe']} minTrades={v['min_trades']} feeOK={v['fee_survives']}")
|