dabcc8d15b35399df5704164fb7c4c9fcdf88531
34 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dabcc8d15b |
docs: aggiornamento Phase 5 — IV-RV gate, F+D+A, backtest, option chain
- 01-strategy-rules.md:
* §2.8 (filtri quant: dealer gamma + liquidation risk)
* §2.9 (IV richness gate, opt-in, default disabled)
* §3.2 — variante delta_by_dvol step-function
* §7-bis.1 (vol-collapse harvest D)
* §7-bis.2 (graduated profit-take C — scaffolding)
* §7-bis.3 (auto-pause su drawdown F)
- 05-data-model.md:
* `system_state.auto_pause_until / _reason` (migration 0004)
* Nuova tabella `option_chain_snapshots` (migration 0005)
* Tabella migrations completa (1→5)
- 13-strategia-spiegata.md:
* §4-quinquies — catena opzioni storica (Phase 5):
cosa raccoglie, cosa sblocca, CLI `option-chain
trigger|analyze`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
7fdd8b47a5 |
fix(gui): percentili Calibrazione in riga compatta, no truncation
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> |
||
|
|
a1a9f74ed2 | Merge feat/option-chain-snapshots | ||
|
|
a9df399db4 | Merge feat/backtest-engine | ||
|
|
e06f4d5c96 |
Merge feat/strategy-improvements-fdac
# Conflicts:
# src/cerbero_bite/gui/pages/7_📚_Strategia.py
# strategy.aggressiva.yaml
# strategy.conservativa.yaml
# strategy.yaml
# tests/unit/test_config_loader.py
|
||
|
|
f24511fcad | Merge feat/iv-rv-hard-gate | ||
|
|
954baaa354 |
feat(cli): comando option-chain (trigger + analyze) per la catena opzioni
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>
|
||
|
|
3e46169278 |
fix(migrations): rinomina 0004 → 0005 per coesistenza con auto_pause
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> |
||
|
|
c0a0ee416f |
feat(state+runtime): option_chain_snapshots — catena opzioni storica per backtest reale
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> |
||
|
|
f664ea1a15 |
feat(backtest): stylized engine over market_snapshots + CLI subcommand
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>
|
||
|
|
18cc27a76e |
feat(gui): simulazione P/L con effetti dei miglioramenti FDAC + IV-RV
Estende il pannello "💰 P/L atteso" della pagina `📚 Strategia` per applicare gli effetti stimati di IV-RV gate, A (delta dinamico), D (vol-harvest) e F (auto-pause) leggendoli direttamente dai `strategy.*.yaml` di ciascun profilo. - Nuova `_detect_features(strategy)` che ispeziona la config: A → `short_strike.delta_by_dvol` non vuoto D → `exit.vol_harvest_dvol_decrease > 0` F → `auto_pause.enabled` IV → `entry.iv_minus_rv_filter_enabled` - `_compute_pl` accetta ora un dict `features` opzionale e applica: IV: +5 pp win-rate, −25% trade/anno (skip-week aggressivo) A: +1.5 pp win-rate, sl_loss × 0.95 (strike picking migliore) D: 5% trade convertiti da loss a harvest exit (+0.20×credito) F: −8% trade/anno (skip-week dopo streak) - `_render_profile_card` mostra ora: badge "🟢 Miglioramenti attivi" con la lista per profilo, delta vs base in E[trade] e P/L annuo, help con win_rate effettivo / prob_loss / trade/anno. - Checkbox "Applica effetti dei miglioramenti" (default ON) per switchare tra simulazione realistica e formula base. - Nuova mini-tabella "Contributo marginale di ogni feature": per ogni miglioramento mostra ΔP/L annuo e ΔAPR isolando l'effetto del singolo feature, con marker "✅ attiva nel YAML". - Sensibilità win-rate ora applica le feature attive ai due profili. Effetti dichiarati come **stime ex-ante** dalla letteratura short-vol systematic; i valori puntuali (+5 pp win, etc.) andranno calibrati sul dataset accumulato. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1c6baaee83 |
feat(strategy): F+D+A miglioramenti — auto-pause, vol-harvest, delta dinamico
Implementa tre miglioramenti dalla roadmap di "📚 Strategia" + scaffolding del quarto. Tutti retro-compatibili: i defaults della golden config disabilitano le nuove funzioni così il comportamento attuale resta invariato finché l'operatore non le accende esplicitamente in `strategy.yaml`. Il profilo `strategy.aggressiva.yaml` opta-in agli incrementi più impattanti. **F — Auto-pause su drawdown rolling (§7-bis)** Circuit breaker sopra il kill-switch tecnico. Quando le ultime N posizioni chiuse hanno cumulato perdite oltre `max_drawdown_pct × capitale_attuale`, l'engine si auto-mette in pausa per `pause_weeks` settimane. Difende dai regime change non rilevati dai filtri quant — se i filtri stanno fallendo sistematicamente, fermarsi è meglio che continuare a sanguinare. - `AutoPauseConfig` + `cfg.auto_pause` (top-level, default disabled). - Migrazione SQL `0004_auto_pause.sql`: `system_state.auto_pause_until` e `auto_pause_reason` (NULL = engine attivo). - Nuovo modulo puro `runtime/auto_pause.py` con `is_paused()` (gate I/O-free) e `evaluate_drawdown_breach()` (decide se armare). - `entry_cycle` consulta `is_paused` subito dopo il kill-switch e arma la pausa dopo aver calcolato il capitale; nuovo status `_STATUS_AUTO_PAUSED`. - Repository: `set_auto_pause`, `recent_closed_position_pnls_usd`. - 12 test unitari: gate filter on/off, lookback insufficiente, soglia esatta, capitale non valido, transizioni paused → not-paused. **D — Vol-collapse harvest (§7-bis)** Exit opportunistica: quando DVOL è scesa di tot punti rispetto all'entry e siamo in profit, esce subito. Edge IV-RV catturato, non c'è motivo di tenere fino al profit-take. Nuovo `ExitAction = "CLOSE_VOL_HARVEST"`, gate `exit.vol_harvest_dvol_decrease` (default 0 = off). 5 test unitari. **A — Delta target dinamico per regime DVOL (§3.2)** Strike short adattivo alla volatilità: a DVOL bassa il margine OTM è generoso ⇒ posso prendere più premio (delta 0.15); a DVOL alta voglio più safety distance (delta 0.10). Nuovo `DeltaByDvolBand` (step function); quando `delta_by_dvol` è popolato, `_select_short` legge la prima banda ascending con `dvol_now ≤ dvol_under`. Default vuoto = comportamento invariato. `select_strikes` accetta nuovo kwarg `dvol_now`, propagato da `entry_cycle`. 4 test unitari. **C — Scaffolding profit-take graduale (§7.1bis)** Schema in place ma runtime non ancora wirato. Aggiunge `PartialProfitLevel` e `exit.profit_take_partial_levels` (default vuoto). Nuovo `ExitAction = "CLOSE_PROFIT_PARTIAL"` nella Literal. La pipeline di chiusure parziali nel runtime (entry_cycle / repository / clients) richiede refactor del position model — lasciato come TODO per un PR dedicato. La schema è pronta a recepire la config futura senza altri breaking change. **Profili aggiornati** - `strategy.yaml` (golden, 1.2.0): tutto disabilitato by default. - `strategy.conservativa.yaml` (1.2.0-cons): identico al golden. - `strategy.aggressiva.yaml` (1.2.0-aggr): A+D+F enabled (delta_by_dvol 0.15/0.12/0.10, vol_harvest a 15 pt vol, auto_pause @ 15% DD su 5 trade, 2 settimane pausa). Bump versioni 1.1.0 → 1.2.0, hash ricalcolati, test pinning aggiornato. Suite: 426 passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c4cd2986a4 |
feat(gui): aggiunge max drawdown atteso (P99) e tail/gap nei profili
Due metriche per ciascun profilo nel pannello P/L: - **Max DD attesa (P99)**: streak di stop consecutivi con probabilità ≤ 1% nell'anno (union-bound: N_trade × p_loss^N ≤ 0.01) × perdita stop × contratti × posizioni concorrenti. - **Max DD coda (gap)**: scenario gap notturno in cui il mark salta oltre la copertura long PRIMA che lo stop sia eseguibile — perdita = larghezza intera meno credito iniziale, su tutte le posizioni aperte. Aggiunge anche colonna "Max DD" nella tabella di sensibilità win-rate, così si vede immediatamente il trade-off APR-vs-drawdown al variare del win-rate (da 65% a 82%). Effetto pratico: a default cap=10k, spot=3000, win=0.75, trades=18: - Conservativa: APR ≈ +1.8%, Max DD attesa ≈ −2.2% capitale - Aggressiva: APR ≈ +14%, Max DD attesa ≈ −30% capitale Numeri che rendono molto più tangibile la frase "drawdown scala con lo stesso fattore" del §4-ter del documento. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4ab7590745 |
feat(entry): IV richness gate (§2.9) + golden config bump 1.0.0 → 1.1.0
Aggiunge il filtro a maggior impatto sul win-rate atteso: l'entry
salta se la IV implicita non sta pagando un margine misurabile sopra
la realized vol. La letteratura short-vol systematic indica che
l'edge sostenibile della strategia esiste solo quando IV30g − RV30g
supera una soglia di alcuni punti vol; senza questo gate il selling
vol nudo è strutturalmente neutro a win-rate 70-72%.
Implementazione end-to-end:
- `EntryConfig`: due nuovi campi `iv_minus_rv_min` e
`iv_minus_rv_filter_enabled`, con default `0` / `false` per non
rompere setup pre-calibrazione.
- `validate_entry`: §2.9 hard gate che blocca l'entry se
`iv_minus_rv < iv_minus_rv_min` (skip silenzioso quando il dato è
`None`, coerente con il pattern §2.8 dei filtri quant).
- `entry_cycle._gather_snapshot`: nuovo `_safe_iv_minus_rv` che
legge `deribit.realized_vol("ETH")["iv_minus_rv_30d"]` in
best-effort e lo propaga via `_MarketSnapshot.iv_minus_rv` →
`EntryContext.iv_minus_rv` → audit `inputs.snapshot.iv_minus_rv`.
- `tests/unit/test_entry_validator.py`: 5 nuovi casi (default
permissivo, gate sotto/sopra/uguale soglia, dato mancante).
- `tests/integration/test_entry_cycle.py`: stub `get_realized_vol`
nel mock helper così tutti gli scenari di happy/edge path
continuano a passare.
Configurazione di profili coerente con la disciplina:
- `strategy.yaml` (golden 1.1.0) e `strategy.conservativa.yaml`:
gate `enabled=false, min=0`. Manteniamo i lunedì pre-calibrazione
per accumulare dati sulla distribuzione di `iv_minus_rv`.
- `strategy.aggressiva.yaml` (1.1.0-aggressiva): gate
`enabled=true, min=3`. Coerente con la filosofia del profilo —
size più grande pretende win-rate più alto. La soglia 3 è
conservativa; la documentazione raccomanda 5 dopo 4-8 settimane di
calibrazione.
Doc + GUI:
- `docs/13-strategia-spiegata.md` §4-quater: spiega gate, parametri,
default per profilo, effetto atteso sul P/L (trade/anno scendono
ma E[trade] sale → APR cresce comunque), roadmap di hardening
(soglia adattiva, vol-of-vol guard, multi-asset).
- pagina `📚 Strategia`: la riga "IV − RV" passa da informativa a
pass/fail reale; mostra "filtro DISABILITATO (info-only)" quando
spento, ✅/❌ contro la soglia di config quando acceso.
Bump versioni e hash di tutti e tre i file YAML
(`config_version: 1.1.0`, hash ricalcolato). Test pinning aggiornato
(`test_load_repo_strategy_yaml`).
Suite: 410 passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
21e865ffb0 |
feat(gui+infra): pagina Strategia, P/L parametrico, profili Conservativa/Aggressiva, dashboard via Traefik
Espone la GUI Streamlit su https://cerbero-bite.tielogic.xyz tramite il Traefik già attivo sull'host (label allineate al pattern di cerbero-mcp, TLS via Let's Encrypt, websocket pass-through). Aggiunge: - nuova tab `📚 Strategia` con stato live dei gate §2 confrontati con l'ultimo tick di market_snapshots, pannello P/L parametrico affiancato Conservativa vs Aggressiva, tabella di sensibilità win-rate → APR e rendering del documento canonico esteso. - doc `13-strategia-spiegata.md` che lega ogni regola §2-§9 al campo di market_snapshots che la alimenta, con sezioni §4-bis (P/L atteso realistico, win-rate empirico, drawdown, Sharpe) e §4-ter (confronto fra i due profili e quando passare dall'uno all'altro). - `strategy.conservativa.yaml` (golden config v1.0.0 esplicita) e `strategy.aggressiva.yaml` (cap_per_trade 4×, max_concurrent 2×, max_contracts 4×, deroga §11 documentata) con config_hash validi. - nel compose: servizio dedicato `cerbero-bite-gui` (Streamlit su 0.0.0.0:8765, healthcheck su /_stcore/health, label Traefik), env condivisi via anchor YAML `x-bite-env`, `--environment mainnet` passato a `start` per allineare il boot check al token del .env (era testnet vs mainnet → kill switch armato all'avvio). - Dockerfile installa anche l'extra `gui` (streamlit) e copia `docs/` + i due nuovi profili nell'immagine; `.dockerignore` non esclude più `docs/` (causa del primo build silenzioso). Fix bonus: `_try_load` nella pagina ritornava `LoadedConfig` ma la GUI leggeva `.sizing.*` direttamente — l'`except: pass` mascherava l'AttributeError facendo cadere sui default conservativi sia nel pannello P/L sia nello stato gate (stesso pattern presente nella Calibrazione). Ora ritorna `.config`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ce158a92dd |
feat(mcp+runtime): allineamento a Cerbero MCP V2 e flag operativi
Adegua Cerbero Bite alla nuova versione 2.0.0 del server MCP unificato (testnet/mainnet routing per token, header X-Bot-Tag obbligatorio) e introduce due interruttori operativi indipendenti per separare la raccolta dati dall'esecuzione di strategia. Auth e collegamento MCP - Token bearer letto dalla nuova variabile CERBERO_BITE_MCP_TOKEN; il valore sceglie l'ambiente upstream (testnet vs mainnet) sul server. Rimosso il caricamento da file (`secrets/core.token`, CERBERO_BITE_CORE_TOKEN_FILE, Docker secret /run/secrets/core_token). - Aggiunto header X-Bot-Tag (default `BOT__CERBERO_BITE`, override via CERBERO_BITE_MCP_BOT_TAG) su ogni call MCP, con validazione lato client (non vuoto, ≤ 64 caratteri). - Cartella `secrets/` rimossa, `.gitignore` ripulito, Dockerfile e docker-compose.yml aggiornati con env passthrough e fail-fast quando manca il token. Modalità operativa (RuntimeFlags) - Nuovo modulo `config/runtime_flags.py` con `RuntimeFlags( data_analysis_enabled, strategy_enabled)` e loader che parserizza CERBERO_BITE_ENABLE_DATA_ANALYSIS e CERBERO_BITE_ENABLE_STRATEGY (true/false/yes/no/on/off/enabled/disabled, case-insensitive). - L'orchestratore espone i flag, audita e logga la modalità al boot (`engine started: env=… data_analysis=… strategy=…`), e in `install_scheduler` esclude i job `entry`/`monitor` quando strategy è off e il job `market_snapshot` quando data analysis è off. I job di infrastruttura (health, backup, manual_actions) restano sempre attivi. - Default profile = "solo analisi dati" (data_analysis=true, strategy=false), pensato per la finestra di soak post-deploy. GUI saldi - `gui/live_data.py::_fetch_deribit_currency` riconosce il campo soft `error` nel payload V2 (HTTP 200 con `error` valorizzato dal server quando l'auth Deribit fallisce) e lo propaga come `BalanceRow.error`, evitando di mostrare un fuorviante equity = 0,00. CLI - Sostituita l'opzione `--token-file` con `--token` (stringa) sui comandi start/dry-run/ping; il default proviene dall'env. Le chiamate al builder dell'orchestrator passano anche `bot_tag` e `flags`. Documentazione - `docs/04-mcp-integration.md`: descrizione del nuovo flusso di auth V2 (token = ambiente, X-Bot-Tag nell'audit) e router unificati. - `docs/06-operational-flow.md`: nuova sezione "Modalità operativa" con i tre profili canonici e tabella di gating per ogni job; aggiunto `market_snapshot` al cron summary. - `docs/10-config-spec.md`: nuova sezione "Variabili d'ambiente" tabellare con tutti gli env, comprese le bool dei flag operativi. - `docs/02-architecture.md`: layout del repo aggiornato (`secrets/` rimosso, `runtime_flags.py` aggiunto), descrizione di `config/` estesa. Test - 5 nuovi test su `_fetch_deribit_currency` (soft-error, payload pulito, eccezione, error blank, signature parity). - 7 nuovi test su `load_runtime_flags` (default, override, parsing truthy/falsy, blank fallback, valore invalido). - 4 nuovi test su `HttpToolClient` (X-Bot-Tag default e custom, blank e troppo lungo rifiutati). - 3 nuovi test integration sull'orchestratore (gating dei job in base ai flag). - Test esistenti su token/CLI ping/orchestrator aggiornati al nuovo schema. Suite intera: 404 passed, 1 skipped (sqlite3 CLI assente sull'host di sviluppo). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d9454fc996 |
feat(state+runtime+gui): market_snapshots — calibrazione soglie da dati
Sistema dedicato di raccolta dati per scegliere le soglie dei filtri sui percentili reali invece di valori a istinto. Nuovi componenti: * state/migrations/0003_market_snapshots.sql — tabella + index, PK composta (timestamp, asset). Ogni colonna numerica è NULL-able per preservare la continuità della serie quando un singolo MCP fallisce. * state/models.py — MarketSnapshotRecord Pydantic. * state/repository.py — record_market_snapshot, list_market_snapshots, _row_to_market_snapshot. * runtime/market_snapshot_cycle.py — collettore best-effort che chiama spot/dvol/realized_vol/dealer_gamma/funding_perp/funding_cross/ liquidation_heatmap/macro per ogni asset; raccoglie gli errori in fetch_errors_json e segna fetch_ok=false ma persiste comunque la riga. * clients/deribit.py — generalizzati dealer_gamma_profile(currency), realized_vol(currency), spot_perp_price(asset). dealer_gamma_profile_eth resta come alias per la chiamata dell'entry cycle. * runtime/orchestrator.py — nuovo job APScheduler `market_snapshot` cron */15 con assets configurabili (default ETH+BTC); il consumer manual_actions ora dispatcha anche kind=run_cycle cycle=market_snapshot per la GUI. * gui/data_layer.py — load_market_snapshots, enqueue_run_cycle accetta market_snapshot; tipo MarketSnapshotRecord esposto. * gui/pages/6_📐_Calibrazione.py — selezione asset+finestra, conteggio fetch_ok, per ogni metrica: istogramma, soglia da strategy.yaml come vline rossa, percentili P5/P10/P25/P50/P75/P90/P95, % di tick che la soglia avrebbe filtrato. * gui/pages/1_📊_Status.py — bottone "📐 Forza snapshot" (4° del pannello Forza ciclo) per popolare la tabella senza aspettare il cron. 5 nuovi test sul collector (happy, fault tolerance, asset switch, macro fail, empty assets); test_orchestrator job set aggiornato. 368/368 tests pass; ruff clean; mypy strict src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
63d1aa4262 |
feat(gui): traduzione italiana, logo Cerbero, saldi live e Forza ciclo
* Localizzazione italiana di tutte le pagine (Stato, Audit, Equity,
Storico, Posizione) e della home; date relative ("5s fa", "12m fa").
* Logo Cerbero (cane a tre teste) in src/cerbero_bite/gui/assets/
cerbero_logo.png — sostituisce l'emoji 🐺 (lupo, semanticamente
errata) sia come favicon (`page_icon`) sia in sidebar e header.
* Caricamento automatico di `.env` dal CWD all'avvio della CLI (skip
sotto pytest tramite PYTEST_CURRENT_TEST), evitando di doversi
esportare manualmente le 4 URL MCP. Aggiunto python-dotenv come
dipendenza, `.env.example` committato come template, `.env` resta
ignorato da git.
* Pagina Stato: nuovo pannello "Saldi exchange" che fa fetch live
via gateway MCP (Deribit USDC + USDT, Hyperliquid USDC + opzionale
USDT spot) con cache TTL 60s e bottone refresh; tile riassuntivi
totale USD / EUR / cambio.
* Pagina Stato: nuovo pannello "Forza ciclo" con tre bottoni
(entry/monitor/health) che accodano azioni `run_cycle` nella tabella
manual_actions; il consumer dell'engine — quando in esecuzione —
dispatcha al `Orchestrator.run_*` corrispondente.
* manual_actions: nuovo `kind="run_cycle"` nello schema
ManualAction; consumer accetta dict di cycle_runners che
l'orchestrator popola in install_scheduler. 3 nuovi test (dispatch
entry, ciclo sconosciuto, fallback senza runner).
* gui/live_data.py — modulo dedicato al fetch MCP dalla GUI
(relax controllato della regola "no MCP from GUI" solo per i saldi,
non per i dati di trading).
363/363 tests pass; ruff clean; mypy strict src clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
da88e7f746 |
docs: align 05/06/09/11 with implemented GUI Phases A–D
* docs/11-gui-streamlit.md — replaces the original spec with what was actually built: implementation status table, real page filenames (1_Status, 2_Audit, 3_Equity, 4_History, 5_Position), per-page inventory of implemented vs deferred sections, GUI ↔ engine table showing arm_kill/disarm_kill via manual_actions and the not_supported markers for force_close + approve/reject_proposal, consumer signature with cron */1, lock model clarified (no GUI lockfile), DoD updated with current state. * docs/05-data-model.md — manual_actions is no longer "pianificata": populated by gui/data_layer.py, drained by the manual_actions job; per-kind status table (arm/disarm OK, others not_supported). * docs/09-development-roadmap.md — Phase 4.5 marked implemented with per-task ✅/⏳ markers for the deferred items (auto-refresh, AppTest, force-close hook). * docs/06-operational-flow.md — adds Flusso 5b describing the manual_actions consumer pattern (enqueue → KillSwitch transition → audit log linkage). 360/360 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e8345a29c8 |
feat(gui+runtime): Phase D — kill-switch arm/disarm from the dashboard
Wires the GUI's first write path through the manual_actions queue: * runtime/manual_actions_consumer.py — drains the queue and dispatches arm_kill / disarm_kill via KillSwitch (preserving the audit chain). Unsupported kinds (force_close, approve/reject_proposal) are marked result="not_supported" so they don't sit forever. * runtime/orchestrator.py — adds a `manual_actions` job at */1 cron to the canonical scheduler manifest. * gui/data_layer.py — write helpers enqueue_arm_kill / enqueue_disarm_kill (the only write path the GUI uses) plus load_pending_manual_actions for the pending strip. * gui/pages/1_📊_Status.py — kill-switch arm/disarm panel with typed confirmation ("yes I am sure") + reason field; pending-actions table rendered when the queue is non-empty. End-to-end smoke against the testnet state.sqlite: GUI enqueue → consumer dispatch → KillSwitch transition → audit chain hash linkage holds, "source":"manual_gui" recorded. 7 new unit tests for the consumer (arm, disarm, drain, unsupported, default-reason, KillSwitchError handling, empty queue); 360/360 pass. ruff clean; mypy strict src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
6f6dd4c8dd |
feat(gui): Phase C — Position drilldown with payoff diagram
* gui/data_layer.py — adds load_position_by_id, load_decisions_for_position, compute_payoff_curve (pure math: bull_put / bear_call piecewise linear P&L at expiry, with breakeven), compute_distance_metrics (OTM%, days-to-expiry, days-held, width%). * gui/pages/5_💼_Position.py — selector across open + 10 most-recent closed positions (with deep-link support via ?proposal_id=…), header metrics, distance summary, leg snapshot table (entry-time only — the GUI never calls MCP), plotly payoff diagram with strike/breakeven/ entry-spot annotations and max profit/max loss tiles, decision history table from the decisions table. Live greeks/mid are deliberately not pulled: per docs/11-gui-streamlit.md the GUI reads SQLite + audit log only and lets the engine refresh data. Validated math against a synthetic bull_put 2475/2350 × 2 contracts: breakeven 2452.50, max profit $45, max loss $-160 — all matching the expected formulas (credit, width × n − credit). 353/353 tests still pass; ruff clean; mypy strict src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
db888ce0e8 |
feat(gui): Phase B — Equity + History pages
Adds the analytics surface of the dashboard: * gui/data_layer.py — extended with load_closed_positions (windowed filter on closed_at) and three pure-function aggregators: compute_equity_curve, compute_kpis, compute_monthly_stats. Drawdown is measured against the running peak of cumulative realised P&L. * gui/pages/3_📈_Equity.py — KPI strip, plotly cumulative-PnL line, drawdown area below, P&L histogram by close_reason, per-month table with win-rate. * gui/pages/4_📜_History.py — windowed table of closed trades with multiselect close-reason and winners/losers radio filters, six-tile KPI strip, CSV export button. * pyproject.toml — relax mypy on plotly + pandas (no shipped stubs). Validated with synthetic data: 3 trades, 67% win rate, $50 total, max drawdown $30 — all matching expected math. GUI launches, HTTP 200 on / and /_stcore/health. 353/353 tests still pass; ruff clean; mypy strict src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1af983aff1 |
feat(gui): Phase A — read-only Streamlit dashboard (Status + Audit)
Implements the foundation of the local observation dashboard described in docs/11-gui-streamlit.md: * gui/data_layer.py — read-only wrappers over Repository (system_state, open positions) and audit_log (tail iteration, chain verify). The GUI never imports runtime/ nor calls MCP services. * gui/main.py — Streamlit entry point with sidebar (engine health badge, kill switch banner, last health check age), home overview. * gui/pages/1_📊_Status.py — engine status with colored health banner, kill switch detail, audit anchor, open positions table. * gui/pages/2_🔍_Audit.py — live audit log stream (newest-first), event filters, hash-chain integrity verify button. * cli.py gui — replaces the placeholder with os.execvpe to `python -m streamlit run` bound to 127.0.0.1, --browser.gatherUsageStats false; --db / --audit paths exported via env to the GUI process. * pyproject.toml — N999 ignore for src/cerbero_bite/gui/pages/* (Streamlit auto-discovers pages whose filename contains numbers and emoji icons). Smoke test: GUI launches, HTTP 200 on / and /_stcore/health, data layer correctly reflects current testnet state (engine=running, kill_switch disarmed, 0 open positions, audit chain integra 7 entries). 353/353 tests still pass; ruff clean; mypy strict src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
abf5a140e2 |
refactor: telegram + portfolio in-process (drop shared MCP)
Each bot now manages its own notification + portfolio aggregation: * TelegramClient calls the public Bot API directly via httpx, reading CERBERO_BITE_TELEGRAM_BOT_TOKEN / CERBERO_BITE_TELEGRAM_CHAT_ID from env. No credentials → silent disabled mode. * PortfolioClient composes DeribitClient + HyperliquidClient + the new MacroClient.get_asset_price/eur_usd_rate to expose equity (EUR) and per-asset exposure as the bot's own slice (no cross-bot view). * mcp-telegram and mcp-portfolio removed from MCP_SERVICES / McpEndpoints and the cerbero-bite ping CLI; health_check no longer probes portfolio. Docs (02/04/06/07) and docker-compose updated to reflect the new architecture. 353/353 tests pass; ruff clean; mypy src clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
067f74bc89 |
docs: align 02/05/07 with autonomous notify-only architecture
Conclude il doc drift residuo dei tre documenti che ancora descrivevano il modello di esercizio pre-Fase 4 (memory/brain-bridge, push_user_instruction, conferma manuale). Aggiornati per riflettere l'engine autonomo notify-only attuale, con tutti gli ultimi hardening integrati. docs/02-architecture.md: - Diagramma a blocchi: rimosso cerbero-memory ↔ Cerbero core, aggiunto annotation sull'audit chain con anchor SQLite. - Tabella stack: httpx pooling al posto dell'SDK mcp, hash chain con anchor in system_state. - Layout cartelle: aggiunte runtime/lockfile.py, runtime/orchestrator.py, runtime/recovery.py, scripts/dead_man.sh, state/migrations/0002_audit_anchor.sql. - Sequenze entry/monitor riscritte all'auto-execute via place_combo_order, niente attesa conferma utente. - Nuova sezione "Lifecycle del container" con boot order, scheduler, SIGTERM clean shutdown, lock release. - Failure modes aggiornati: environment mismatch, audit anchor mismatch, lock occupato. docs/05-data-model.md: - Filosofia estesa con la regola dell'audit chain e l'anchor. - Schema instructions: payload_json riferito ai response Deribit (combo_instrument, order_id, state) invece di push_user_instruction. - Aggiunta migration 0002_audit_anchor.sql con last_audit_hash. - Schema log JSONL: campi cycle e cycle_id propagati da structlog.contextvars. - Sezione "Audit log" descrive il formato concretamente in uso (separatori | con prev_hash/hash) ed elenco eventi reali (ENGINE_START, RECOVERY_DONE, ENTRY_PLACED, HOLD, EXIT_FILLED, KILL_SWITCH_*, ALERT, KELLY_RECALIBRATED). - Sezione backup riferita allo job APScheduler ora schedulato (0 * * * *). docs/07-risk-controls.md: - Nuova tabella trigger automatici allineata al codice (column "Implementato" punta ai moduli runtime/safety reali). - Sezione "Single-instance lock" introdotta (fcntl.flock, EngineLock, caveat multi-host). - Sezione "Anti-truncation" che descrive il flusso anchor: callback on_append → SQLite → check al boot. - "Cap di rischio" estesa con i due nuovi filter dealer-gamma e liquidation-heatmap (§2.8). - Sezione "Versionamento config" cita execution.environment, execution.eur_to_usd, dealer_gamma_min, dealer_gamma_filter_enabled, liquidation_filter_enabled. - Escalation tree concretizzata sull'AlertManager con i metodi reali (low/medium/high/critical). Test: 335 pass, 1 skip (sqlite3 CLI). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f4faef6fd1 |
Phase 4 hardening: dealer-gamma + liquidation-heatmap entry filters
Integra due nuovi filtri dal pacchetto quant indicators rilasciato in Cerbero_mcp (commit a13e3fe). 335 test pass, mypy strict pulito, ruff clean. Filtri (§2.8 — nuovo): - dealer-gamma: blocca entry quando total_net_dealer_gamma < dealer_gamma_min (default 0). Long-gamma regime favorisce credit spread (vol-suppressing dealer flow); short-gamma flow lo amplifica ed è da evitare. - liquidation-heatmap: blocca entry quando il segnale euristico di cerbero-sentiment riporta long o short squeeze risk = "high" (cluster di liquidations imminenti entro 24h). Entrambi sono best-effort: se il tool MCP fallisce o restituisce dati anomali l'entry_cycle popola EntryContext con None e validate_entry salta il gate per non bloccare entry su problemi infrastrutturali. Wrapper: - DeribitClient.dealer_gamma_profile_eth → DealerGammaSnapshot. - SentimentClient.liquidation_heatmap → LiquidationHeatmap con property has_high_squeeze_risk. Schema: - EntryConfig.dealer_gamma_min, dealer_gamma_filter_enabled, liquidation_filter_enabled. - EntryContext.dealer_net_gamma, liquidation_squeeze_risk_high opzionali. - strategy.yaml: nuovi campi documentati con commento + hash ricalcolato (4c2be4c5...). Documentazione: - docs/04-mcp-integration.md riscritto al modello attuale (HTTP REST, no mcp SDK, no memory/brain-bridge, place_combo_order documentato, environment_info al boot). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
b5b96f959c |
Hardening round 2: healthcheck, audit anchor, return_4h, exec config, signals
Sei interventi MEDIA priorità sul sistema. 323 test pass, mypy strict
pulito, ruff clean.
1. Docker HEALTHCHECK + cerbero-bite healthcheck:
- nuovo subcommand che esce 0 se kill_switch=0 e last_health_check
entro --max-staleness-s (default 600s);
- HEALTHCHECK direttiva nel Dockerfile (60s interval, 5s timeout,
start_period 120s, retries 3);
- healthcheck definition nel docker-compose.yml.
2. Audit hash chain anti-truncation:
- migration 0002: nuova colonna system_state.last_audit_hash;
- AuditLog accetta callback on_append, dependencies.py la wire al
repository.set_last_audit_hash;
- Orchestrator.boot verifica che il tail file matcha l'anchor
persistito; mismatch → kill switch CRITICAL.
3. return_4h bootstrap da deribit get_historical:
- quando dvol_history è vuoto _fetch_return_4h cade su
deribit.historical_close (1h candle 4h fa);
- alert LOW se anche il fallback fallisce.
4. execution.environment + execution.eur_to_usd in strategy.yaml:
- ExecutionConfig promosso a typed schema con i due campi
consumati al boot;
- CLI start preferisce i valori da config; CLI flag overridano
solo quando differenti dai default.
5. Cycle correlation ID:
- structlog.contextvars.bind_contextvars in run_entry/run_monitor/
run_health propaga cycle_id e cycle nei log strutturati.
6. SIGTERM/SIGINT clean shutdown:
- run_forever installa loop.add_signal_handler per SIGTERM e
SIGINT; il segnale set()ta un asyncio.Event che termina il
blocco principale, scheduler.shutdown e ctx.aclose finalizzano.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
411b747e93 |
Phase 4 hardening: status CLI, lock file, backup job, hash enforce, pooling, real bias
Sei interventi mirati sui rischi operativi rilevati nell'audit post-Fase 4. 317 test pass, mypy strict pulito, ruff clean. 1. status CLI: legge SQLite reale e mostra kill_switch, posizioni aperte, environment, config_version, last_health_check, started_at. Sostituisce il placeholder "phase 0 skeleton". 2. Lock file single-instance: runtime/lockfile.py acquisisce data/.lockfile via fcntl.flock al boot di run_forever; un secondo container fallisce subito con LockError. 3. Backup orario nello scheduler: nuovo job APScheduler 0 * * * * chiama scripts.backup.backup_database + prune_backups. 4. config_hash enforce su start: il CLI start verifica l'integrità del file (enforce_hash=True). Mismatch → exit 1 prima di toccare stato. dry-run resta enforce_hash=False per debug. 5. Connection pooling MCP: RuntimeContext espone un httpx.AsyncClient long-lived condiviso da tutti i wrapper (limits 20/10 connections/keepalive). aclose() chiamato in run_forever finale. 6. Bias direzionale reale: deribit.historical_close + deribit.adx_14 popolano TrendContext con spot a 30 giorni e ADX(14) effettivi. Sblocca bull_put e bear_call. Quando i dati storici mancano l'engine emette alert MEDIUM e cade su no_entry in modo deterministico. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ca1e6379df |
chore(deps): bump greenlet, hypothesis, pathspec, virtualenv
Routine upgrade dei pacchetti minor/patch. 311 test pass, mypy strict pulito, ruff clean. - greenlet 3.4.0 → 3.5.0 - hypothesis 6.152.3 → 6.152.4 - pathspec 1.1.0 → 1.1.1 - virtualenv 21.2.4 → 21.3.0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
42b0fbe1ab |
Phase 4: orchestrator + cycles auto-execute
Componente runtime/ che cabla core+clients+state+safety in un engine autonomo notify-only: nessuna conferma manuale, ordini combo piazzati direttamente quando le regole passano. 311 test pass, copertura totale 94%, runtime/ 90%, mypy strict pulito, ruff clean. Moduli: - runtime/alert_manager.py: escalation tree LOW/MEDIUM/HIGH/CRITICAL → audit + Telegram + kill switch. - runtime/dependencies.py: build_runtime() costruisce RuntimeContext con tutti i client MCP, repository, audit log, kill switch, alert manager. - runtime/entry_cycle.py: flusso settimanale (snapshot parallelo spot/dvol/funding/macro/holdings/equity → validate_entry → compute_bias → options_chain → select_strikes → liquidity_gate → sizing_engine → combo_builder.build → place_combo_order → notify_position_opened). - runtime/monitor_cycle.py: loop 12h con dvol_history per il return_4h, exit_decision.evaluate, close auto-execute. - runtime/health_check.py: probe parallelo MCP + SQLite + environment match; 3 strikes consecutivi → kill switch HIGH. - runtime/recovery.py: riconciliazione SQLite vs broker all'avvio; mismatch → kill switch CRITICAL. - runtime/scheduler.py: AsyncIOScheduler builder con cron entry (lun 14:00), monitor (02/14), health (5min). - runtime/orchestrator.py: façade boot() + run_entry/monitor/health + install_scheduler + run_forever, con env check vs strategy. CLI: - start: avvia engine bloccante (asyncio.run + scheduler). - dry-run --cycle entry|monitor|health: esegue un singolo ciclo per debug/test in produzione. - stop: documenta lo shutdown via SIGTERM al container. Documentazione: - docs/06-operational-flow.md riscritto per il modello notify-only auto-execute (no conferma manuale, no memory, no brain-bridge). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
466e63dc19 |
Phase 3: MCP HTTP clients + Dockerization
Wrapper async tipizzati sui sei servizi MCP HTTP che Cerbero Bite consuma in autonomia. 277 test pass, copertura clients 93%, mypy strict pulito, ruff clean. Base layer: - clients/_base.py: HttpToolClient con httpx + tenacity (retry esponenziale 3x, timeout 8s, mapping HTTP→eccezioni tipizzate). - clients/_exceptions.py: McpAuthError, McpServerError, McpToolError, McpDataAnomalyError, McpNotFoundError, McpTimeoutError. - config/mcp_endpoints.py: risoluzione URL via Docker DNS (mcp-deribit:9011, ...) con override per servizio via env var; caricamento bearer token da secrets/core.token o CERBERO_BITE_CORE_TOKEN_FILE. Wrapper: - clients/macro.py: next_high_severity_within() per filtro entry §2.5. - clients/sentiment.py: funding_cross_median_annualized() con annualizzazione per period nativo per exchange (Binance/Bybit/OKX 1095, Hyperliquid 8760). - clients/hyperliquid.py: funding_rate_annualized() per filtro §2.6. - clients/portfolio.py: total_equity_eur(), asset_pct_of_portfolio() per sizing engine + filtro §2.7. - clients/telegram.py: notify-only (no callback queue, no conferme — Bite auto-execute). - clients/deribit.py: environment_info, index_price_eth, latest_dvol, options_chain, get_tickers, orderbook_depth_top3, get_account_summary, get_positions, place_combo_order (combo atomico), cancel_order. CLI: - cerbero-bite ping: health-check parallelo di tutti gli MCP con tabella rich (OK/FAIL/SKIPPED). Docker: - Dockerfile multi-stage Python 3.13 + uv, user non-root. - docker-compose.yml con rete external "cerbero-suite", secret core_token montato a /run/secrets/core_token, env per ogni MCP. - secrets/README.md documenta il setup del token. Documentazione di intervento: - docs/12-mcp-deribit-changes.md: spec delle modifiche apportate al server mcp-deribit (place_combo_order + override testnet via DERIBIT_TESTNET). Dipendenze: - aggiunto pytest-httpx per i test HTTP. - rimosso mcp>=1.0 (non usiamo l'SDK MCP, parliamo via HTTP REST). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
263470786d |
Phase 2: persistence + safety controls
Aggiunge la persistenza SQLite, l'audit log a hash chain, il kill switch coordinato e i CLI di gestione documentati in docs/05-data-model.md e docs/07-risk-controls.md. 197 test pass, 1 skipped (sqlite3 CLI mancante), copertura totale 97%. State (`state/`): - 0001_init.sql con positions, instructions, decisions, dvol_history, manual_actions, system_state. - db.py: connect con WAL + foreign_keys + transaction ctx, runner forward-only basato su PRAGMA user_version. - models.py: record Pydantic, Decimal preservato come TEXT. - repository.py: CRUD typed con singola connessione passata, cache aware, posizioni concorrenti. Safety (`safety/`): - audit_log.py: AuditLog append-only con SHA-256 chain e fsync, verify_chain riconosce ogni manomissione (payload, prev_hash, hash, JSON, separatori). - kill_switch.py: arm/disarm transazionali, idempotenti, accoppiati all'audit chain. Config (`config/loader.py` + `strategy.yaml`): - Loader YAML con deep-merge di strategy.local.yaml. - Verifica config_hash SHA-256 (riga config_hash esclusa). - File golden strategy.yaml + esempio override. Scripts: - dead_man.sh: watchdog shell indipendente da Python. - backup.py: VACUUM INTO orario con retention 30 giorni. CLI: - audit verify (exit 2 su tampering). - kill-switch arm/disarm/status su SQLite reale. - state inspect con tabella posizioni aperte. - config hash, config validate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
fbb7753cc6 |
Phase 1: core algorithms
Implementa i sette algoritmi puri di docs/03-algorithms.md con disciplina TDD: 112 test, copertura statement+branch al 100% su core/ e config/, mypy --strict pulito, ruff pulito. Moduli: - config/schema.py: StrategyConfig Pydantic v2 con validatori di consistenza (kelly, delta, OTM, spread width, profit/stop). - core/types.py: OptionQuote e OptionLeg condivisi. - core/entry_validator.py: validate_entry (accumula motivi) e compute_bias (bull_put/bear_call/iron_condor/None). - core/liquidity_gate.py: check OI/volume/spread/depth + slippage stimato in % del credito. - core/sizing_engine.py: Quarter Kelly con cap 200/1000 EUR e bande DVOL. - core/combo_builder.py: select_strikes (DTE/OTM/delta/width/credit) e build (ComboProposal con credit/max_loss/breakeven). - core/greeks_aggregator.py: somma firmata BUY/SELL, theta in USD. - core/exit_decision.py: 6 trigger ordinati con eccezione skip-time vicino a profit (mark in (50%,70%] credito). - core/kelly_recalibration.py: full/quarter Kelly, confidence per sample size, blend medio in fascia 30-99 trade. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
881bc8a1bf |
Phase 0: project skeleton
- pyproject.toml with uv, deps for runtime + gui + backtest + dev - ruff/mypy strict config, pre-commit hooks for ruff/mypy/pytest - src/cerbero_bite/ layout with empty modules ready for Phase 1+ - structlog JSONL logger with daily rotation - click CLI with placeholder subcommands (status, start, kill-switch, gui, replay, config hash, audit verify) - 6 smoke tests passing, mypy --strict clean, ruff clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |