feat(xsec): XS01 reversione cross-sectional (8 asset) -> PORT06 PAPER
Famiglia NUOVA trovata in sessione (dopo aver scartato trend/breakout/seasonal/ opzioni/funding come rumore): ogni 12h long i perdenti relativi / short i vincenti su 8 asset, market-neutral. Scorrelata (~0) da pairs e fade -> diversificatore. - engine canonico scripts/strategies/XS01_cross_sectional.py (no look-ahead, plateau OOS Sharpe 2-3.9, 5/5 anni+, edge concentrato 2025, cost-sensitive ~0.35% RT). - src/live/xsec_worker.py CrossSectionalWorker: validate_xsec_worker == backtest ESATTO (4993/1427 trade). Mirror della cadenza engine (entry-to-entry = hold+1). - gate PORT06: +XS01 -> OOS Sharpe 9.66->10.07, FULL DD 3.68->3.46 (OOS DD +0.17pp, risk-contrib 2.2%). xsec_port06_gate.py. - wiring: _defs XSEC in PORT06 (19 sleeve, family XSEC), build_everything, runner kind=xsec, asset_days da supported (fix fetch alt anche per paper sleeves), paper. - 8 gambe -> niente exec reale -> gira PAPER. Regression-lock 18->19, FULL 7.20->7.34, OOS 9.66->10.07. 93 test verdi. Diario 2026-06-09-xs01-cross-sectional.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+11
-2
@@ -22,6 +22,7 @@ from src.live.pairs_worker import PairsWorker
|
||||
from src.live.basket_trend_worker import BasketTrendWorker
|
||||
from src.live.rotation_worker import RotationWorker
|
||||
from src.live.tsmom_worker import TsmomWorker
|
||||
from src.live.xsec_worker import CrossSectionalWorker
|
||||
from src.live.strategy_loader import load_strategy
|
||||
|
||||
# Codice-breve sleeve -> nome modulo Strategy in scripts/strategies/ (worker single/ml)
|
||||
@@ -30,7 +31,7 @@ _STRAT_MODULE = {
|
||||
"MR07": "MR07_return_reversal", "SH01": "SH01_shape_ml",
|
||||
"DIP01": "DIP01_dip_buy",
|
||||
}
|
||||
_MULTI_KINDS = ("basket", "rotation", "tsmom")
|
||||
_MULTI_KINDS = ("basket", "rotation", "tsmom", "xsec")
|
||||
DATA_DIR = Path("data/portfolio_paper")
|
||||
|
||||
# giorni di storia da fetchare per timeframe (TSM01 1d usa 252 barre -> ~440 giorni col buffer)
|
||||
@@ -88,6 +89,14 @@ def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float,
|
||||
thr=pr.get("thr", 1.0), gross=pr.get("gross", 0.30),
|
||||
tf=pr.get("tf", "1d"), capital=alloc_capital, data_dir=data_dir,
|
||||
)
|
||||
if spec.kind == "xsec":
|
||||
pr = spec.params
|
||||
return CrossSectionalWorker(
|
||||
universe=pr["universe"], tf=pr.get("tf", "1h"),
|
||||
params={"lb": pr.get("lb", 48), "hold": pr.get("hold", 12)},
|
||||
capital=alloc_capital, position_size=position_size, leverage=leverage,
|
||||
data_dir=data_dir,
|
||||
)
|
||||
module = _STRAT_MODULE.get(spec.name)
|
||||
if module is None:
|
||||
raise ValueError(f"sleeve live non supportato: {spec.name} (kind={spec.kind})")
|
||||
@@ -338,7 +347,7 @@ def run(config_path: str = "portfolios.yml"):
|
||||
|
||||
# lookback (giorni) richiesto per ogni asset = max sui worker che lo usano
|
||||
asset_days: dict[str, int] = {}
|
||||
for s in live_specs:
|
||||
for s in supported: # live + PAPER (anche XS01/TR01/ROT02/TSM01)
|
||||
assets, tf = _spec_assets_tf(s)
|
||||
days = _LOOKBACK_DAYS.get(tf, 90)
|
||||
if s.kind == "ml": # SH01 ha bisogno di molta storia 1h
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
_PREFIX = [("PR_", "PAIRS"), ("SH_", "SHAPE"), ("TSM", "TSM"), ("MR", "FADE")]
|
||||
_PREFIX = [("PR_", "PAIRS"), ("SH_", "SHAPE"), ("TSM", "TSM"), ("MR", "FADE"), ("XS", "XSEC")]
|
||||
|
||||
|
||||
def family_of(sleeve_id: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user