14522262e6
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera libreria "validata OOS" era artefatto di feed contaminato (print fantasma del feed Cerbero TESTNET + storico Binance/USDT). - Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE 50-82% barre flat; XRP/BNB non certificabili). - Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST con segnale residuo, da ri-validare in isolamento. - Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio, runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/ portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/ (preservati, non cancellati). Diario consolidato in un unico documento. - Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal + src/backtest/engine + load_data; tool dati certificati (rebuild_history, certify_feed, audit_feed, multi_source_check). - Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
3.3 KiB
Python
71 lines
3.3 KiB
Python
"""Gate feed CONGELATO (2026-06-15): salta entry+exit degli sleeve concentrati
|
|
(single/ml/pairs) il cui feed di DECISIONE 1h e' fermo (guasto, es. ETH-PERPETUAL
|
|
a 1661.95 per 36h+). Distingue il GUASTO (close mai cambiata per decine di barre)
|
|
dall'ILLIQUIDITA' (SOL/LTC/ADA: molte barre flat ma il prezzo si muove -> run corte).
|
|
Auto-guarente: la barra di ripresa e' non-flat -> il gate si rilascia da solo."""
|
|
import pandas as pd
|
|
from src.portfolio.runner import _frozen_assets, _feed_gated_sids
|
|
|
|
|
|
def _df(completed, forming):
|
|
"""Serie 1h: barre complete (flat = O=H=L=C; non-flat quando il prezzo cambia)
|
|
+ una candela in formazione (ultima riga, esclusa dal detector)."""
|
|
end_ms = int(pd.Timestamp.now(tz="UTC").floor("h").timestamp() * 1000)
|
|
vals = list(completed) + [forming]
|
|
n = len(vals)
|
|
rows = []
|
|
for j, v in enumerate(vals):
|
|
ts = end_ms - (n - 1 - j) * 3_600_000
|
|
rows.append({"timestamp": ts, "open": v, "high": v, "low": v, "close": v, "volume": 0.0})
|
|
for j in range(1, n): # bar NON-flat quando il prezzo si muove
|
|
if rows[j]["close"] != rows[j - 1]["close"]:
|
|
rows[j]["high"] = rows[j]["close"] * 1.001
|
|
return pd.DataFrame(rows)
|
|
|
|
|
|
def test_frozen_feed_detected():
|
|
raw = {"ETH": _df([1661.95] * 40, 1661.95)} # prezzo MAI cambiato (guasto)
|
|
assert _frozen_assets(raw, 12) == {"ETH"}
|
|
|
|
|
|
def test_live_feed_not_frozen():
|
|
raw = {"BTC": _df([65000 + i * 5 for i in range(40)], 65200.0)} # sempre in movimento
|
|
assert _frozen_assets(raw, 12) == set()
|
|
|
|
|
|
def test_illiquid_but_alive_not_frozen():
|
|
# ultima barra completa FLAT ma il prezzo si e' mosso da poche barre (run < soglia):
|
|
# alt illiquido (SOL/LTC/ADA), NON un guasto -> non gateato.
|
|
raw = {"LTC": _df([44.0] * 30 + [45.0] * 5, 45.0)}
|
|
assert _frozen_assets(raw, 12) == set()
|
|
|
|
|
|
def test_resume_releases_gate():
|
|
# rilascio solo su una barra COMPLETATA non-flat (la forming non basta -> coerente
|
|
# con la valutazione su barre settled, EXIT-16). NON e' l'entry-guard post-flat: la
|
|
# barra di ripresa NON viene saltata, il tick riprende su di essa.
|
|
raw = {"ETH": _df([1661.95] * 40 + [1700.0], 1700.0)}
|
|
assert _frozen_assets(raw, 12) == set()
|
|
# finche' la ripresa e' solo nella candela in formazione, resta congelato
|
|
assert _frozen_assets({"ETH": _df([1661.95] * 40, 1700.0)}, 12) == {"ETH"}
|
|
|
|
|
|
def test_threshold_zero_disables():
|
|
raw = {"ETH": _df([1661.95] * 40, 1661.95)}
|
|
assert _frozen_assets(raw, 0) == set()
|
|
|
|
|
|
def test_gated_scope_matches_eth_legs():
|
|
"""Sui veri sleeve PORT06: con ETH congelato si gatano TUTTE e sole le gambe ETH
|
|
(3 fade ETH + SH_ETH + 5 pairs con gamba ETH). BTC-only, BTC/LTC e i multi-asset
|
|
(anche ROT02 che ha ETH nell'universo) restano attivi."""
|
|
from scripts.portfolios._defs import FADE, PAIRS, SHAPE, HONEST
|
|
specs = FADE + PAIRS + SHAPE + HONEST
|
|
g = _feed_gated_sids(specs, {"ETH"})
|
|
assert {"MR01_ETH", "MR02_ETH", "MR07_ETH", "SH_ETH",
|
|
"PR_ETHBTC", "PR_ETHBTC_15M", "PR_LTCETH", "PR_ADAETH", "PR_ETHSOL"} <= g
|
|
assert g.isdisjoint({"MR01_BTC", "MR02_BTC", "MR07_BTC", "SH_BTC",
|
|
"DIP01_BTC", "PR_BTCLTC"})
|
|
assert g.isdisjoint({"TR01_basket", "ROT02_rot"}) # multi-asset mai gateati
|
|
assert _feed_gated_sids(specs, set()) == set() # nessun congelato -> nessun gate
|