Files
PythagorasGoal/src/live/bars.py
T
Adriano Dal Pastro f5173fba06 fix(live): 4 hardening da code-review — REAL_DIVERGENCE, outage su feed vuoto, bars.py condiviso, DSL cancel retry
Review multi-agente 7-angoli su 8c4e1cd..HEAD + check trades live:

1. Alert Telegram REAL_DIVERGENCE quando |slippage sim/reale| >= 100bps a
   open/close. Causa scatenante: spike print testnet 10:37 (candela 10:00
   H=65618, O/C ~62400) -> 3 fade BTC short su close fantasma 65266.5, reale
   fillato a 62395 (-440bps), sim +2.26 mai esistiti — passato in silenzio.
2. FEED_OUTAGE anche su feed degradato SENZA eccezione (HTTP 200 + candles
   vuote: i worker saltavano il tick in silenzio, streak a 0). Helper unico
   _outage_tick; chiavi payload uniformate (minuti su start e RIPRESO).
3. src/live/bars.py: detection forming-bar unificata (bar_ms_of /
   last_bar_is_forming / last_settled_idx) — era copiata in 4 punti
   (strategy_worker, basket, pairs, _check_stale_feed hardcoded 1h).
   E' l'invariante di sicurezza EXIT-16: ora una sola implementazione testata.
4. DSL cancel hardening in _real_close: retry su errore transitorio + alert
   REAL_DSL_CANCEL_FAIL se lo stop resta forse orfano sul book (prima l'id
   veniva dimenticato in silenzio); order_not_found = probabile trigger in
   outage -> solo log (il close a valle esce gia' verified=False).

Refutato il finding top dei finder ("stop_market senza trigger"): cerbero-mcp
traduce price->trigger_price+mark, e in produzione 2 DSL armati + 1 ciclo
completo pulito (MR07_BTC).

Test: 83/83 (9 nuovi: bars helper + DSL/divergence con executor finto).
Smoke testnet 4 scenari verdi, conto flat, zero falsi allarmi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:59:58 +00:00

45 lines
1.6 KiB
Python

"""Helper condivisi sulle barre OHLCV live (lezione EXIT-16, 2026-06-05).
La riga -1 di un df di candele e' la candela IN FORMAZIONE finche' non e'
trascorsa la sua durata: valutare segnali/exit-confirm su quella riga
reintroduce la wick-sensitivity che EXIT-16 elimina (audit live: 2 stop su 3
del crash ETH erano wick-stop sulla barra in corso). Questa e' l'UNICA
implementazione della detection — prima era copiata in 4 punti
(strategy_worker, basket_trend_worker, pairs_worker, runner._check_stale_feed)
con una variante hardcoded a 1h: una correzione applicata a una copia e
dimenticata nelle altre reintrodurrebbe il bug in silenzio.
"""
from __future__ import annotations
import time
import numpy as np
def bar_ms_of(ts_ms, window: int = 50) -> int:
"""Durata stimata della barra: mediana dei diff degli ultimi `window`
timestamp (ms). 0 se la serie e' troppo corta per stimarla."""
ts = np.asarray(ts_ms, dtype="int64")
if len(ts) < 2:
return 0
return int(np.median(np.diff(ts[-window:])))
def last_bar_is_forming(ts_ms, now_ms: int | None = None) -> bool:
"""True se la riga -1 e' la candela IN CORSO (now < ts[-1] + durata barra)."""
ts = np.asarray(ts_ms, dtype="int64")
if len(ts) == 0:
return False
bar = bar_ms_of(ts)
if not bar:
return False
if now_ms is None:
now_ms = int(time.time() * 1000)
return now_ms < int(ts[-1]) + bar
def last_settled_idx(ts_ms, now_ms: int | None = None) -> int:
"""Indice dell'ultima barra COMPLETATA: -1 se la riga -1 e' chiusa,
-2 se e' in formazione."""
return -2 if last_bar_is_forming(ts_ms, now_ms) else -1