feat(portfolio): build_worker_for (worker esecutori con capitale da alloc pool)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
"""PortfolioRunner: faccia live del portafoglio (capitale pool, sizing, ribilancio, ledger).
|
||||||
|
Riusa i worker esistenti come esecutori e il data layer Cerbero v2."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from src.portfolio.base import SleeveSpec, Portfolio
|
||||||
|
from src.portfolio.ledger import PortfolioLedger
|
||||||
|
from src.live.strategy_worker import StrategyWorker
|
||||||
|
from src.live.pairs_worker import PairsWorker
|
||||||
|
from src.live.multi_runner import MLWorkerWrapper
|
||||||
|
from src.live.strategy_loader import load_strategy
|
||||||
|
|
||||||
|
# Codice-breve sleeve -> nome modulo Strategy in scripts/strategies/
|
||||||
|
_STRAT_MODULE = {
|
||||||
|
"MR01": "MR01_bollinger_fade", "MR02": "MR02_donchian_fade",
|
||||||
|
"MR07": "MR07_return_reversal", "SH01": "SH01_shape_ml",
|
||||||
|
# DIP01/TR01/ROT02 sono honest a sé: vedi nota nel design (worker dedicati in fase 2)
|
||||||
|
}
|
||||||
|
DATA_DIR = Path("data/paper_trades")
|
||||||
|
|
||||||
|
|
||||||
|
def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float,
|
||||||
|
data_dir: Path = DATA_DIR, position_size: float = 0.15):
|
||||||
|
"""Costruisce il worker esecutore per uno sleeve con capitale = quota allocata."""
|
||||||
|
if spec.kind == "pairs":
|
||||||
|
return PairsWorker(
|
||||||
|
asset_a=spec.a, asset_b=spec.b, tf=spec.tf, params=spec.params,
|
||||||
|
capital=alloc_capital, position_size=position_size, leverage=leverage,
|
||||||
|
fee_rt=0.001, name="PR01_pairs_reversion", data_dir=data_dir,
|
||||||
|
)
|
||||||
|
module = _STRAT_MODULE.get(spec.name)
|
||||||
|
if module is None:
|
||||||
|
raise ValueError(f"sleeve live non ancora supportato: {spec.name} "
|
||||||
|
f"(honest DIP01/TR01/ROT02 richiedono worker dedicati, fase 2)")
|
||||||
|
strategy = load_strategy(module)
|
||||||
|
worker = StrategyWorker(
|
||||||
|
strategy=strategy, asset=spec.asset, tf=spec.tf, capital=alloc_capital,
|
||||||
|
position_size=position_size, leverage=leverage, params=spec.params, data_dir=data_dir,
|
||||||
|
)
|
||||||
|
if spec.kind == "ml": # SH01: retraining periodico
|
||||||
|
return MLWorkerWrapper(worker, {"retrain_hours": 24})
|
||||||
|
return worker
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from src.portfolio.runner import build_worker_for
|
||||||
|
from src.portfolio.base import SleeveSpec
|
||||||
|
from src.live.strategy_worker import StrategyWorker
|
||||||
|
from src.live.pairs_worker import PairsWorker
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_single_worker_capital_from_alloc(tmp_path):
|
||||||
|
spec = SleeveSpec(kind="single", name="MR01", sid="MR01_BTC", asset="BTC",
|
||||||
|
params={"bb_window": 50, "k": 2.5, "sl_atr": 2.0, "max_bars": 24})
|
||||||
|
w = build_worker_for(spec, alloc_capital=300.0, leverage=2.0, data_dir=tmp_path)
|
||||||
|
assert isinstance(w, StrategyWorker)
|
||||||
|
assert w.capital == 300.0 and w.leverage == 2.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_pairs_worker(tmp_path):
|
||||||
|
spec = SleeveSpec(kind="pairs", name="PR01", sid="PR_ETHBTC", a="ETH", b="BTC",
|
||||||
|
params={"n": 50, "z_in": 2.0, "z_exit": 0.75, "max_bars": 72})
|
||||||
|
w = build_worker_for(spec, alloc_capital=200.0, leverage=2.0, data_dir=tmp_path)
|
||||||
|
assert isinstance(w, PairsWorker)
|
||||||
|
assert w.capital == 200.0
|
||||||
Reference in New Issue
Block a user