fix(live): parita' worker multi-asset — TR01 fee x leva, forming-bar su TR01/Pairs, WARN panel corto
Punti 2-4 dell'improvement-sweep 2026-06-06 (fix di parita', nessun cambio di strategia): - TR01 (basket_trend_worker): fee per flip = POS * LEV * fee_rt/2 come il reference honest_improve2._tr_basket_daily:150 (mancava il fattore leva -> fee sotto-caricate 2x, bias ottimistico che gonfiava total_capital al ribilancio). - TR01: crossover EMA e booking del return valutati SOLO su barre 4h COMPLETE (la riga -1 e' la candela in corso finche' non e' trascorsa la sua durata) — lezione EXIT-16; evidenza live: flip SOL 0->1->0 in 59min nella stessa finestra 4h. - PairsWorker: entry ED exit valutati sul close di barra COMPLETA, come il backtest pairs_research (close settled). Stesso pattern bar_ms di strategy_worker.tick. - TSM01/ROT02: il silent return su panel inner-join troncato sotto il lookback ora emette WARN log + Telegram PANEL_SHORT (helper _warn_panel_short condiviso), gated su "era gia' operativo" (no falsi positivi al cold-start), una notifica per episodio. Test: 72/72 verdi (7 nuovi: forming-bar TR01/pairs + controllo positivo, fee con leva, PANEL_SHORT warn/dedup/cold-start). Replay parity: validate_worker_pairs ESATTO (ETH/BTC e BTC/LTC == backtest); validate_honest_workers invariato (TR01 -44% vs ref +42% IDENTICO pre/post fix: e' la divergenza di convenzione capitale-unico vs media-equity gia' documentata, da rivisitare a parte). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ Replica live di honest_improve2._tr_basket_daily."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
@@ -52,21 +53,35 @@ class BasketTrendWorker:
|
||||
"ts": datetime.now(timezone.utc).isoformat()}, indent=2))
|
||||
|
||||
def tick(self, data: dict):
|
||||
now_ms = int(time.time() * 1000)
|
||||
rets = []
|
||||
for a in self.universe:
|
||||
df = data.get(a)
|
||||
if df is None or len(df) < 110:
|
||||
if df is None or len(df) < 111:
|
||||
continue
|
||||
# Scarta la barra 4h IN FORMAZIONE (la riga -1 e' la candela in corso
|
||||
# finche' non e' trascorsa la sua durata): crossover EMA e booking del
|
||||
# return valutati SOLO su barre COMPLETE, come il reference
|
||||
# honest_improve2._tr_basket_daily (lezione EXIT-16; evidenza live: flip
|
||||
# SOL 0->1->0 in 59min nella stessa finestra 4h, -9.3% di glitch).
|
||||
ts_arr = df["timestamp"].values.astype("int64")
|
||||
bar_ms = int(np.median(np.diff(ts_arr[-50:]))) if len(ts_arr) > 1 else 0
|
||||
c = df["close"].values
|
||||
if bar_ms and now_ms < int(ts_arr[-1]) + bar_ms:
|
||||
c, ts_arr = c[:-1], ts_arr[:-1]
|
||||
if len(c) < 110:
|
||||
continue
|
||||
ef, es = _ema(c, 20)[-1], _ema(c, 100)[-1]
|
||||
target = 1.0 if ef > es else 0.0
|
||||
bar_ts = int(df["timestamp"].iloc[-1])
|
||||
bar_ts = int(ts_arr[-1])
|
||||
prev = self.positions[a]
|
||||
if self.last_bar_ts[a] and bar_ts > self.last_bar_ts[a] and prev > 0:
|
||||
r = (c[-1] - c[-2]) / c[-2]
|
||||
rets.append(self.position_size * self.leverage * r * prev)
|
||||
if target != prev:
|
||||
self.capital -= self.capital * self.position_size * (self.fee_rt / 2) * abs(target - prev) / len(self.universe)
|
||||
# fee = FEE_RT/2 * LEV come il reference (honest_improve2.py:150):
|
||||
# il notional e' leveraged, la fee si paga sul notional
|
||||
self.capital -= self.capital * self.position_size * self.leverage * (self.fee_rt / 2) * abs(target - prev) / len(self.universe)
|
||||
self._log(a, prev, target, float(c[-1]))
|
||||
self.positions[a] = target
|
||||
self.last_bar_ts[a] = bar_ts
|
||||
|
||||
Reference in New Issue
Block a user