Allinea la spec all'implementazione: dataclass ChainAuditReport senza
depth_zero_pct, tabella checks senza la riga book_depth_top3=0, output
example senza la riga depth_top3. Aggiunta nota che spiega perché il
check è stato rimosso (colonna popolata solo dal path entry_cycle).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Riflette la struttura effettiva del CLI: il group 'audit' contiene già
'verify' per la hash chain; il data-quality audit è entrato come
sibling 'data'. Documentata la deviazione in linea.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Usa il group 'audit' esistente (sibling di 'audit verify' per la hash
chain). Opzioni: --db, --since DAYS, --asset ETH|BTC, --json.
Output stdout Rich di default, dump JSON con --json. Esce con codice 2
su sqlite3.OperationalError (DB malformato/schema mancante).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implementa la funzione dichiarata in __all__ ma mancante. Helper _pct
usa statistics.quantiles(method="inclusive") con fallback per len<=1.
Niente check su book_depth_top3: per design è NULL sugli snapshot
(popolato solo da entry_cycle per gli strike candidati al picker).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
book_depth_top3 è popolato solo dal path entry_cycle (per gli strike
candidati al picker), mai dal collector option_chain_snapshot — il
controllo depth_zero su questi snapshot sarebbe strutturalmente 100%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Il piano originale aveva `floor(span/15) + 1` che over-conta a span allineati
(span=60min → 5 invece di 4). Il primo fix dell'implementer (`floor(span/15)`)
under-conta a span non-allineati (span=16min → 1 invece di 2). Solo
`ceil(span/15)` è corretto in entrambi i casi. Aggiunti 2 test che
coprono gli scenari non-allineato e boundary-esatto per impedire
regressioni. Plan doc allineato.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Piano dettagliato task-by-task per `cerbero-bite audit`:
analysis/data_audit.py (helper puri + dataclass), CLI subcommand,
test unit + smoke test, end-to-end su DB produzione. Ogni task ha
i suoi step TDD con codice completo, comandi e commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migration 0006 promuove dvol_history da PK=(timestamp) mono-ETH a
PK=(timestamp, asset), rinomina eth_spot -> spot, e backfilla con
asset='ETH' le righe storiche. market_snapshot_cycle ora scrive sia
per ETH che per BTC; monitor_cycle resta ETH-only via WHERE asset='ETH'
nella lookup di return_4h.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Directory creata localmente dall'infrastruttura OMC per stato sessione
(project-memory.json, research/, sessions/, state/). Non è artefatto
del progetto cerbero-bite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pannello "P/L atteso — Conservativa vs Aggressiva":
* Sostituiti slider Capitale/Spot con slider parametrici Cap/trade
(EUR) + posizioni concorrenti. Il capitale richiesto viene calcolato
in automatico via Kelly-binding aggregato:
capital = cap_pertrade_usd × concorrenza / max(kelly, 1e-3).
* Profili Conservativa/Aggressiva ora ereditano dai yaml SOLO le leve
qualitative (width_pct, credit_ratio, kelly_fraction, feature
attive); le leve di sizing (cap, concorrenza) sono comandate dagli
slider per confronti omogenei.
* Tre metriche header: capitale richiesto, cap aggregato notional,
cap per trade USD.
Fix in `_compute_pl`:
* Max loss per contratto era `width` (errato per credit spread).
Corretto a `width − credit` allineato a core/sizing_engine.py.
Effetto: n_kelly aumenta proporzionalmente al credit incassato →
P/L stimato più realistico per spread con credit_to_width_ratio
alto (es. 0.30+ in profilo Aggressiva).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sostituisce `option_chain_asset: str = "ETH"` con
`option_chain_assets: tuple[str, ...] = ("ETH", "BTC")` e itera nel
job schedulato. Coerente con `market_snapshot_assets` già multi-asset
e con i 64 strikes BTC + 51 strikes ETH già visibili in
option_chain_snapshots.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sblocca il warmup hard del gate IV-RV adattivo (~21 giorni residui)
permettendo di mischiare cadenze diverse (tick live 15min + backfill
giornaliero) senza assumere il fattore costante 96 tick/giorno.
API change (no backwards-compat shims):
* compute_adaptive_threshold(history, *, n_days, percentile,
absolute_floor): rimossi `min_days`/`target_days`. La selezione
finestra (target_days/min_days/intera storia) si sposta al caller.
Warmup hard quando `n_days == 0`.
* repository: rimosso `iv_rv_history`; aggiunti
`count_iv_rv_distinct_days` (COUNT DISTINCT substr(ts,1,10)) e
`iv_rv_values_for_window`.
* EntryContext aggiunge `iv_rv_n_days: int = 0`. entry_cycle calcola
n_days, sceglie window_days e popola il context. Audit
`iv_rv_n_days` reale (non più len/96).
* GUI Calibrazione: counter giorni distinti tramite set di date.
* Spec aggiornata con errata 2026-05-10 e nuova warmup table.
Backfill (scripts/backfill_iv_rv.py, stdlib-only):
* Fetch DVOL daily + ETH/BTC-PERPETUAL closes da Deribit public REST.
* Calcolo RV30d annualizzato (stdev log-return × √365 × 100).
* INSERT OR REPLACE in market_snapshots con timestamp 12:00 UTC e
fetch_errors_json='{"backfill":true}' per distinzione audit.
* Compute layer testato (9 test): RV su prezzi costanti/monotoni/
alternati, build_records con cutoff e missing data.
Verifica live post-deploy (10 mag 2026 08:50 UTC):
* ETH: n_days=46, P25=2.21 vol pt, IV-RV=10.05 → gate PASS
* BTC: n_days=46, P25=5.69 vol pt, IV-RV=8.60 → gate PASS
509 test passati (500 esistenti + 9 backfill), ruff pulito.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Risponde al final review (spec §6.4): il decisions log ora
contiene iv_rv_threshold_used (la soglia P_q effettivamente
applicata) e iv_rv_window_used_days (giorni di history nella
finestra). Permette ricostruire ex-post perché un trade è stato
saltato e con quali numeri.
Helper privi di I/O — la soglia viene ricomputata in base alla
history già caricata, costo trascurabile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
L'hash dichiarato non rispecchiava più il contenuto del file dopo
l'attivazione del gate adattivo (commit 080acf8). Senza questo fix
il loader sollevava ConfigHashError e l'orchestrator rifiutava il
profilo Aggressiva al boot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Sequence importato da collections.abc invece di typing (PYI001).
- compute_adaptive_threshold spostato a top-level (PLC0415):
niente circular dep risk perché adaptive_threshold non importa
da entry_validator.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mostra status (warmup/attivo), soglia P25 rolling corrente, IV-RV
ultimo tick, floor assoluto, decisione hypothetical e sezione
Vol-of-Vol guard. Read-only: i percentili statici esistenti
restano per analisi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P25 rolling 60g, warmup a finestra disponibile, VoV guard 5pt.
Conservativa e golden invariati (default disabled).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verifica integrazione tra Repository.iv_rv_history,
compute_adaptive_threshold e dvol_lookback su un DB reale
seedato con 30 giorni di market_snapshots bimodale.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Quando i flag adaptive_enabled / vol_of_vol_guard_enabled sono
attivi, entry_cycle carica history e lookback dal repository
prima di costruire EntryContext. Il decisions log riceve i meta
n_history e dvol_24h_ago per audit ex-post.
Quando i flag sono off, niente query DB extra (zero overhead).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Risponde alla code review di 395191e:
- iv_rv_history accetta as_of (default now UTC) invece di
affidarsi al clock SQLite, rendendo i test time-stable.
- Valida max_days > 0 e raise se as_of/reference sono naive.
- Aggiunge 3 test sulle nuove guard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Due nuovi metodi che leggono market_snapshots filtrando NULL e
fetch_ok=0. iv_rv_history limita a max_days; dvol_lookback trova
il tick più vicino a un istante con tolerance configurabile.
Tests: ordered ASC, asset filter, NULL skip, fetch_ok=0 skip,
lookback closest, gap returns None.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blocca entry se |DVOL_now - DVOL_24h_ago| >= threshold (default
5 pt). Fail-open quando dvol_24h_ago è None (gap dati). Independente
dal gate IV-RV: i due gate sono additivi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Quando iv_minus_rv_adaptive_enabled=True, la soglia diventa
max(P_q rolling, iv_minus_rv_min). Path legacy (statico) e
None-bypass restano invariati.
Aggiunge anche due model_validator a StrategyConfig per
fail-fast su config invalida (window_min_days < target_days,
percentile in (0,1)) — risponde alla code review T1.
Tests: pass/skip su rolling, warmup hard, floor binding,
backwards compat statico, None bypass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Campi opzionali con default vuoto/None per non rompere i caller
esistenti. Saranno popolati da entry_cycle quando i flag
adaptive_enabled / vol_of_vol_guard_enabled sono True.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Risponde alla code review di 7dc2fda:
- Valida percentile in [0,1] e 0 < min_days < target_days, raise
ValueError quando out-of-range. Fail-fast invece di IndexError o
silent wrong result.
- Aggiunge test boundary esattamente a min_days*96 e target_days*96
(spec §9.1 item 9 era mancante).
- Aggiunge 4 test sulle nuove guards.
- Fix typo docstring (Determinismic → Deterministic).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implementa il calcolo del percentile rolling con warmup,
transizione min_days → target_days e floor assoluto. Pure
function senza I/O: il caller passa la sequenza pre-filtrata
(NULL e fetch_ok=0 esclusi).
Tests: warmup, transizione finestra, floor, percentili.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aggiunge i flag e i parametri per il gate IV-RV adattivo (P25
rolling) e per il Vol-of-Vol guard. Default disabilitati per
non cambiare comportamento dei profili attuali.
Vedi docs/superpowers/specs/2026-05-08-iv-rv-adaptive-gate-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Piano TDD bite-sized in 11 task con steps dettagliati, codice
completo, comandi e expected output. Coverage completa dello
spec 2026-05-08-iv-rv-adaptive-gate-design.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spec del gate IV-RV adattivo (P25 rolling 60g + Vol-of-Vol guard 5pt
24h) — riprende roadmap §4-quater di 13-strategia-spiegata.md punti
1 e 2 e li promuove a design pronto per implementazione.
Decisioni emerse dal brainstorming:
- Hybrid (percentile rolling + VoV guard), non regime detection
- Window target 60g, min 30g, sotto usa storia disponibile (warmup)
- Floor assoluto via vecchio iv_minus_rv_min (backwards compat)
- Inline nel validator, stateless, no DB cache
- GUI Calibrazione: pannello informativo, slider esistenti invariati
- Fail-open su tutti i casi di dato mancante
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Il commento dichiarava cron settimanale (55 13 * * MON) ma lo
scheduler reale (orchestrator._CRON_OPTION_CHAIN_SNAPSHOT) è */15
24/7, allineato a market_snapshot. Aggiornato per evitare confusione
nei lettori futuri. Anche fixato l'header file (0004 → 0005).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Alle 00:00 UTC Deribit non ha ancora costruito il candle 1D di oggi:
con start_date=oggi la response è vuota e il client tirava
McpDataAnomalyError ('neither latest nor candles'). Includendo ieri
nello start_date, candles[-1] resta valido come fallback.
Verificato sui dati raccolti: 3 fail consecutivi 2026-05-02/03/04 a
00:00 UTC su ETH, zero fail dal 2026-05-05 in poi (container
rebuildato in mezzo al periodo).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Popola dvol_history dentro la stessa transazione di market_snapshots,
così lo storico è disponibile anche in modalità data-only (STRATEGY=false).
Evita il warm-up vuoto di return_4h quando si abilita la strategia: il
monitor_cycle trova subito i campioni locali invece di dipendere dal
fallback Deribit get_historical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
I valori percentili (es. -0.0298, 0.05323) renderizzati come
``st.metric`` su 7 colonne venivano tagliati su viewport stretti:
ogni metric ha label sopra, font fisso, nessun shrink. Sostituito
con render markdown inline a font 0.85rem, single-line, scrollabile
orizzontalmente se serve. Tutti e 7 i percentili visibili senza
troncamento e senza wrap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Espone direttamente da CLI le due operazioni più utili sui dati di
``option_chain_snapshots`` raccolti dal cron settimanale:
- ``cerbero-bite option-chain trigger`` — esegue UNA volta il
collector della catena. Riusa la stessa pipeline schedulata (cron
``55 13 * * MON``) ma on-demand. Utile per popolare il DB senza
aspettare lunedì.
- ``cerbero-bite option-chain analyze [--bias bull_put|bear_call]`` —
legge l'ultimo snapshot, simula il selector di strike
(``select_strikes``) con la strategy passata e stampa una tabella
con: short/long strike, delta, width, credito reale, ratio
credit/width, e PASS/FAIL del gate ``credit_to_width_ratio_min``.
Il comando ``analyze`` rende immediatamente actionable la catena
appena raccolta: invece di stime ex-ante via Black-Scholes (modulo
``core/backtest.py``), legge i mid REALI di Deribit e dice "il rule
engine aprirebbe questo trade qui? credit/width ratio passa o no?".
Esempio di output sui primi snapshot raccolti (regime ETH ~2200,
DTE ~14g):
Snapshot del 2026-05-01T20:53:49 — 21 quote totali
Il rule engine NON aprirebbe trade con questa catena
(no strike compatibile coi gate delta/distance/width/credit-ratio).
Conferma empirica del messaggio del documento ``13-strategia-spiegata``:
con delta target 0.12 + width 4% + credit/width ≥ 30%, il regime
attuale di ETH options non è abbastanza ricco per produrre trade —
serve calibrare soglie o aspettare un regime IV più alto.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
La migrazione `0004_option_chain_snapshots.sql` collide con quella
parallela `0004_auto_pause.sql` del PR `feat/strategy-improvements-fdac`:
entrambe puntano allo stesso slot e bumpano user_version a 4.
Rinominata a 0005 (con `PRAGMA user_version = 5`) così le due
migrazioni possono coesistere senza conflitti, indipendentemente
dall'ordine di merge dei due PR. Quando i due PR landeranno in main,
basterà conservare la sequenza 0004 (auto_pause) → 0005 (option_chain).
Verificato in locale: deploy con DB già a v4 (post-FDAC) ora applica
correttamente la migrazione e crea la tabella `option_chain_snapshots`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aggiunge la persistence della option chain Deribit con cron settimanale
``55 13 * * MON`` (5 minuti prima del trigger entry alle 14:00 UTC),
sbloccando il backtest non-stilizzato e la calibrazione empirica
dello skew premium.
**Schema (migrazione 0004)**
Nuova tabella ``option_chain_snapshots`` con primary key composta
``(timestamp, instrument_name)`` — tutti i quote prelevati nello
stesso tick condividono il timestamp, così le query "lo snapshot del
2026-05-04 alle 13:55" diventano una singola WHERE timestamp = X.
Indici su (asset, timestamp DESC) e (asset, expiry) per supportare
sia listing recenti sia query per scadenza specifica.
Campi: instrument_name, strike, expiry, option_type (C/P), bid, ask,
mid, iv, delta, gamma, theta, vega, open_interest, volume_24h,
book_depth_top3. Tutti i numerici sono nullable: il collector è
best-effort, un ticker mancante produce comunque una riga (utile
per sapere che lo strumento esisteva ma non era quotato).
**Modello + repository**
- ``OptionChainQuoteRecord`` (Pydantic, in ``state/models.py``).
- ``Repository.record_option_chain_snapshot`` (bulk insert
idempotente).
- ``Repository.list_option_chain_snapshots`` (filtri su asset,
timestamp window, expiry window, limit default 50000).
- ``Repository.latest_option_chain_timestamp`` (freshness check
per dashboard GUI).
**Collector**
Nuovo ``runtime/option_chain_snapshot_cycle.py`` che:
1. Calcola la finestra scadenze ``[now+dte_min, now+dte_max]`` da
``cfg.structure``: niente richieste su scadenze che il rule
engine non userebbe mai.
2. Chiama ``deribit.options_chain()`` con
``min_open_interest=cfg.liquidity.open_interest_min``.
3. Batch ``deribit.get_tickers()`` (max 20 per call, limite Deribit)
con error-isolation per batch — un batch fallito non blocca
gli altri.
4. NON chiama l'order book per ogni strike (rate-limit guard);
``book_depth_top3`` resta NULL e il liquidity gate live lo
chiede on-the-fly per gli strike candidati al picker.
Best-effort end-to-end: chain assente, get_tickers giù, persist
fallito → ritorna 0 senza alzare eccezioni, logga sempre.
**Schedulazione**
Wired in ``Orchestrator.install_scheduler`` come job parallelo a
``market_snapshot``, attivo solo quando
``ENABLE_DATA_ANALYSIS=true``. Cron parametrizzabile via il nuovo
kwarg ``option_chain_cron`` (default ``55 13 * * MON``).
**Test**
- 4 unit test del collector (happy path, ticker mancante, chain
vuota, fetch fail best-effort) con mock di RuntimeContext.
- Aggiornato ``test_install_scheduler_registers_canonical_jobs``
per includere il nuovo job nel set canonico.
**Cosa sblocca**
- Backtest non-stilizzato: il PR ``feat/backtest-engine`` può
dropparsi il modello BS+skew_premium e leggere prezzi reali
``mid`` dalla chain registrata.
- Calibrazione empirica dello skew premium (hardcoded a 1.5 nel
backtest stilizzato): plot del rapporto fra quote reali Deribit
e BS per delta/expiry, regressione → valore data-driven.
- Validazione ex-post: "il delta-0.12 era davvero a 25% OTM in
quella settimana?" diventa una query SELECT.
- Dimensione attesa: ~50 strike × 3 scadenze × 1 snapshot/settimana
× 17 colonne ≈ 12 KB/settimana, ~600 KB/anno. Trascurabile.
Suite: 409 passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aggiunge `core/backtest.py`, motore di backtesting stilizzato che gira
sui dati raccolti in `market_snapshots`. Risponde alla domanda:
"se questa config fosse stata attiva nelle ultime N settimane, quanti
lunedì avrebbero superato i filtri e quale sarebbe stato il P/L stimato?"
**Architettura a due strati**:
1. **Filtri di entry — RIGOROSO**: per ogni Monday-14:00-UTC nei
snapshot ricostruisce `EntryContext` e chiama lo stesso
`validate_entry()` del live. Output esatto di "cosa avrebbe deciso
il bot" per ogni settimana, con conteggio dei motivi di skip.
2. **P/L per trade accettato — STILIZZATO**: senza catena opzioni
storica, stima credito/exit via Black-Scholes con skew premium
(default 1.5×) per approssimare la vol smile dell'ETH. Re-prezza
il combo ad ogni tick futuro per simulare i trigger §7
(profit_take, stop_loss, vol_stop, time_stop, expiry).
**Aggregati nel `BacktestReport`**:
- n_picks / n_accepted / n_skipped_data / n_completed / n_winners
- win_rate, P/L cumulato (USD + % su capitale)
- max drawdown (USD + % di peak)
- Sharpe annualizzato (52 settimane)
- skip_reasons: dict{motivo → settimane bloccate}
**CLI**: nuovo `cerbero-bite backtest --strategy F --from D --to D
--capital N --asset ETH`. Stampa Rich-formatted summary + tabella
motivi di skip. Esempio:
cerbero-bite backtest \
--strategy strategy.aggressiva.yaml \
--from 2026-04-01 --to 2026-05-01 \
--capital 10000
**Limiti dichiarati**:
- BS + skew_premium ≠ catena reale: i numeri P/L sono **stime ex-post
per ranking config**, non promesse operative. Buono per dire
"config A batte config B sui dati reali", non per dimensionare
capitale.
- skew_premium 1.5× è stato calibrato sui dati Deribit storici
(smile slope ETH options); va rifinito quando avremo abbastanza
chain history da farlo empiricamente.
**Tests**: 15 unit test (BS math, monday picks, filter sim,
position outcome simulation, full pipeline su sintetico).
Suite totale: 420 passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>