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>
This commit is contained in:
@@ -41,6 +41,34 @@ sono vere:
|
|||||||
patrimonio totale (correlazione direzionale già alta).
|
patrimonio totale (correlazione direzionale già alta).
|
||||||
8. **Liquidità degli strike candidati** entro le soglie del §3.
|
8. **Liquidità degli strike candidati** entro le soglie del §3.
|
||||||
|
|
||||||
|
### 2.8 Filtri quant (introdotti in Phase 4)
|
||||||
|
|
||||||
|
Due gate aggiuntivi che leggono i campi del `market_snapshot`:
|
||||||
|
|
||||||
|
- **Dealer net gamma > 0** (default: `dealer_gamma_min: 0`). Long-gamma
|
||||||
|
regime = dealer hedge che sopprime la vol → ideale per vendere
|
||||||
|
credit spread. Short-gamma = vol-amplifying flow, statisticamente
|
||||||
|
perdente. Disattivabile via `dealer_gamma_filter_enabled: false`.
|
||||||
|
- **Liquidation risk ≠ high** (default: `liquidation_filter_enabled:
|
||||||
|
true`). Salta entry quando il modulo sentiment flagga uno squeeze
|
||||||
|
imminente su long o short side.
|
||||||
|
|
||||||
|
### 2.9 IV richness gate (introdotto in Phase 5, opt-in)
|
||||||
|
|
||||||
|
Filtro a maggior impatto sul win-rate. **Disabilitato** di default
|
||||||
|
nella golden config — abilitato esplicitamente nel profilo
|
||||||
|
`strategy.aggressiva.yaml`:
|
||||||
|
|
||||||
|
- `iv_minus_rv_filter_enabled: true|false` — master switch.
|
||||||
|
- `iv_minus_rv_min: <pt vol>` — soglia: l'entry passa solo se la
|
||||||
|
IV implicita 30g supera la realized vol 30g di almeno tot punti.
|
||||||
|
Default 0; valori sensati 3-5 dopo calibrazione sui dati raccolti.
|
||||||
|
|
||||||
|
Razionale: il selling vol nudo è strutturalmente neutro a win-rate
|
||||||
|
70-72%. L'edge della strategia esiste solo quando il premio è
|
||||||
|
"ricco" — IV30 > RV30 + N. Vedere `13-strategia-spiegata.md §4-quater`
|
||||||
|
per il razionale completo.
|
||||||
|
|
||||||
Se anche **una sola** condizione fallisce → **no entry**, log con motivo,
|
Se anche **una sola** condizione fallisce → **no entry**, log con motivo,
|
||||||
ritento la settimana successiva.
|
ritento la settimana successiva.
|
||||||
|
|
||||||
@@ -77,6 +105,20 @@ assoluto.
|
|||||||
| Distanza minima OTM | 15% (anche se delta è dentro tolleranza) |
|
| Distanza minima OTM | 15% (anche se delta è dentro tolleranza) |
|
||||||
| Distanza massima OTM | 25% |
|
| Distanza massima OTM | 25% |
|
||||||
|
|
||||||
|
**Variante dinamica per regime DVOL (Phase 5, opt-in).** Il campo
|
||||||
|
`short_strike.delta_by_dvol` (lista step-function) sostituisce il
|
||||||
|
delta target singolo con bande ordinate per `dvol_under`: a DVOL
|
||||||
|
bassa il bot prende delta più alto (più premio), a DVOL alta sceglie
|
||||||
|
delta più basso (più safety distance). Lista vuota = comportamento
|
||||||
|
classico col delta target sopra. Esempio bande nel profilo
|
||||||
|
`strategy.aggressiva.yaml`:
|
||||||
|
|
||||||
|
| dvol_under | delta_target | delta_min | delta_max |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 50 | 0.15 | 0.13 | 0.17 |
|
||||||
|
| 70 | 0.12 | 0.10 | 0.15 |
|
||||||
|
| 90 | 0.10 | 0.08 | 0.12 |
|
||||||
|
|
||||||
Se nessuno strike disponibile rientra in entrambe le tolleranze → no entry.
|
Se nessuno strike disponibile rientra in entrambe le tolleranze → no entry.
|
||||||
|
|
||||||
### 3.3 Strike long (protezione)
|
### 3.3 Strike long (protezione)
|
||||||
@@ -179,6 +221,49 @@ Per ogni posizione aperta, il rule engine valuta in ordine:
|
|||||||
|
|
||||||
L'ordine è importante: il primo trigger soddisfatto vince.
|
L'ordine è importante: il primo trigger soddisfatto vince.
|
||||||
|
|
||||||
|
## 7-bis. Estensioni opzionali (Phase 5)
|
||||||
|
|
||||||
|
Tre miglioramenti opt-in al decision loop. Tutti **disabled** di
|
||||||
|
default nella golden config; il profilo `strategy.aggressiva.yaml`
|
||||||
|
li abilita.
|
||||||
|
|
||||||
|
### 7-bis.1 Vol-collapse harvest (D)
|
||||||
|
|
||||||
|
Inserito tra il profit-take §7.1 e lo stop-loss §7.2:
|
||||||
|
|
||||||
|
> Se `vol_harvest_dvol_decrease > 0`, siamo in profit
|
||||||
|
> (`debit < credit`) E `DVOL_now ≤ DVOL_entry − vol_harvest_dvol_decrease`,
|
||||||
|
> `decision = CLOSE_VOL_HARVEST`.
|
||||||
|
|
||||||
|
Razionale: edge IV-RV già catturato, vol attesa rientrata, non c'è
|
||||||
|
motivo di tenere fino al profit-take. Default disabilitato (`0`);
|
||||||
|
profilo aggressivo: `15` punti vol.
|
||||||
|
|
||||||
|
### 7-bis.2 Profit-take graduale (C — scaffolding)
|
||||||
|
|
||||||
|
Schema in place per chiusure parziali; pipeline runtime di
|
||||||
|
chiusura partial-close NON ancora wirata. Default vuoto. Quando
|
||||||
|
popolato, ogni livello `{mark_at_pct_credit, close_pct_of_initial_contracts}`
|
||||||
|
emette un'azione `CLOSE_PROFIT_PARTIAL` advisory che il runtime
|
||||||
|
attualmente ignora. Il completamento richiede refactor del position
|
||||||
|
model (contracts_open vs contracts_initial) — PR dedicato.
|
||||||
|
|
||||||
|
### 7-bis.3 Auto-pause su drawdown (F)
|
||||||
|
|
||||||
|
Circuit breaker sopra il kill-switch tecnico. Valutato all'inizio di
|
||||||
|
ogni entry-cycle:
|
||||||
|
|
||||||
|
> Se `auto_pause.enabled` e P/L cumulato delle ultime
|
||||||
|
> `lookback_trades` posizioni chiuse < `−max_drawdown_pct ×
|
||||||
|
> capitale_corrente`, l'engine si auto-mette in pausa per
|
||||||
|
> `pause_weeks` settimane (skip-week mode).
|
||||||
|
|
||||||
|
Difende dai regime change non rilevati dai filtri quant. La pausa
|
||||||
|
si annulla automaticamente alla scadenza, oppure manualmente con
|
||||||
|
`UPDATE system_state SET auto_pause_until = NULL`. Default
|
||||||
|
disabilitato; profilo aggressivo: lookback 5 trade, soglia 15%, 2
|
||||||
|
settimane di pausa.
|
||||||
|
|
||||||
## 8. Esecuzione di apertura
|
## 8. Esecuzione di apertura
|
||||||
|
|
||||||
1. Engine costruisce **combo order Deribit** (un solo ordine atomico
|
1. Engine costruisce **combo order Deribit** (un solo ordine atomico
|
||||||
|
|||||||
+63
-6
@@ -202,7 +202,9 @@ CREATE TABLE system_state (
|
|||||||
last_kelly_calib TEXT,
|
last_kelly_calib TEXT,
|
||||||
config_version TEXT NOT NULL,
|
config_version TEXT NOT NULL,
|
||||||
started_at TEXT NOT NULL,
|
started_at TEXT NOT NULL,
|
||||||
last_audit_hash TEXT -- aggiunto dalla migration 0002
|
last_audit_hash TEXT, -- aggiunto dalla migration 0002
|
||||||
|
auto_pause_until TEXT, -- aggiunto dalla migration 0004 (§7-bis.3)
|
||||||
|
auto_pause_reason TEXT -- aggiunto dalla migration 0004
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -212,6 +214,54 @@ Al boot l'orchestrator confronta questo valore con il tail del file
|
|||||||
`audit.log`: discrepanza → kill switch CRITICAL, vedi
|
`audit.log`: discrepanza → kill switch CRITICAL, vedi
|
||||||
`07-risk-controls.md`.
|
`07-risk-controls.md`.
|
||||||
|
|
||||||
|
I campi `auto_pause_until` / `auto_pause_reason` implementano il
|
||||||
|
circuit breaker §7-bis.3 (pausa automatica su drawdown rolling).
|
||||||
|
NULL = engine attivo.
|
||||||
|
|
||||||
|
### `option_chain_snapshots`
|
||||||
|
|
||||||
|
Snapshot della catena opzioni Deribit prelevata settimanalmente
|
||||||
|
(cron `55 13 * * MON`, 5 minuti prima del trigger entry). Ogni
|
||||||
|
tick contiene un quote per strumento entro la finestra
|
||||||
|
`[dte_min, dte_max]` di config; tutti i quote prelevati nello stesso
|
||||||
|
tick condividono ``timestamp``. Migration `0005`.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE option_chain_snapshots (
|
||||||
|
timestamp TEXT NOT NULL,
|
||||||
|
asset TEXT NOT NULL,
|
||||||
|
instrument_name TEXT NOT NULL,
|
||||||
|
strike TEXT NOT NULL,
|
||||||
|
expiry TEXT NOT NULL,
|
||||||
|
option_type TEXT NOT NULL CHECK (option_type IN ('C','P')),
|
||||||
|
bid TEXT,
|
||||||
|
ask TEXT,
|
||||||
|
mid TEXT,
|
||||||
|
iv TEXT,
|
||||||
|
delta TEXT,
|
||||||
|
gamma TEXT,
|
||||||
|
theta TEXT,
|
||||||
|
vega TEXT,
|
||||||
|
open_interest INTEGER,
|
||||||
|
volume_24h INTEGER,
|
||||||
|
book_depth_top3 INTEGER,
|
||||||
|
PRIMARY KEY (timestamp, instrument_name)
|
||||||
|
) WITHOUT ROWID;
|
||||||
|
```
|
||||||
|
|
||||||
|
Indici: `(asset, timestamp DESC)` per listing recenti, `(asset,
|
||||||
|
expiry)` per query per scadenza specifica. ``book_depth_top3`` è
|
||||||
|
NULL by design — il collector non chiama l'order book per ogni
|
||||||
|
strike per non saturare l'API; lo legge il liquidity gate live solo
|
||||||
|
sugli strike candidati al picker.
|
||||||
|
|
||||||
|
**Sblocca**: il backtest non-stilizzato (modulo `core/backtest.py`
|
||||||
|
con prezzi reali invece di Black-Scholes), la calibrazione empirica
|
||||||
|
dello skew premium, la validazione ex-post dello strike picker.
|
||||||
|
|
||||||
|
Volume atteso: ~50 strike × 3 scadenze × 1 snapshot/settimana ×
|
||||||
|
17 colonne ≈ 12 KB/settimana, ~600 KB/anno.
|
||||||
|
|
||||||
## Log file
|
## Log file
|
||||||
|
|
||||||
Sotto `data/log/` un file per giorno: `cerbero-bite-YYYY-MM-DD.jsonl`.
|
Sotto `data/log/` un file per giorno: `cerbero-bite-YYYY-MM-DD.jsonl`.
|
||||||
@@ -289,11 +339,18 @@ da altri processi (es. CLI `state inspect`) non vedano stati parziali.
|
|||||||
|
|
||||||
## Migrations
|
## Migrations
|
||||||
|
|
||||||
Lo schema viene tracciato con il counter `PRAGMA user_version`. La
|
Lo schema viene tracciato con il counter `PRAGMA user_version`.
|
||||||
prima volta `0001_init.sql` viene applicato e versione → 1; alla
|
`state.db.run_migrations` applica in ordine ogni file
|
||||||
seconda esecuzione (o su DB già a versione 1) `0002_audit_anchor.sql`
|
`NNNN_<name>.sql` con versione superiore a quella corrente,
|
||||||
viene applicato e versione → 2. `state.db.run_migrations` è
|
idempotente, forward-only:
|
||||||
idempotente. Nessun rollback supportato (migrations forward-only).
|
|
||||||
|
| Versione | File | Cosa aggiunge |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | `0001_init.sql` | tabelle base (positions, decisions, ...) |
|
||||||
|
| 2 | `0002_audit_anchor.sql` | `system_state.last_audit_hash` |
|
||||||
|
| 3 | `0003_market_snapshots.sql` | tabella `market_snapshots` |
|
||||||
|
| 4 | `0004_auto_pause.sql` | `system_state.auto_pause_until / _reason` |
|
||||||
|
| 5 | `0005_option_chain_snapshots.sql` | tabella `option_chain_snapshots` |
|
||||||
|
|
||||||
## Backup
|
## Backup
|
||||||
|
|
||||||
|
|||||||
@@ -595,6 +595,47 @@ questa logica: muovi da 0.72 a 0.78 e vedi l'APR scattare.
|
|||||||
3. **Multi-asset (ETH+BTC)**: come da §4-ter, sblocca il
|
3. **Multi-asset (ETH+BTC)**: come da §4-ter, sblocca il
|
||||||
moltiplicatore 2× sulle opportunità a parità di filtri.
|
moltiplicatore 2× sulle opportunità a parità di filtri.
|
||||||
|
|
||||||
|
## 4-quinquies. Catena opzioni storica (Phase 5)
|
||||||
|
|
||||||
|
In aggiunta a `market_snapshots` (cron `*/15`), il bot raccoglie
|
||||||
|
ora una seconda fonte di dati: la **catena opzioni Deribit completa**
|
||||||
|
ogni lunedì alle 13:55 UTC (5 minuti prima del trigger entry).
|
||||||
|
|
||||||
|
Tabella `option_chain_snapshots` — vedi `05-data-model.md` per lo
|
||||||
|
schema. Cosa registra per ogni strumento entro la finestra
|
||||||
|
`[dte_min, dte_max]`:
|
||||||
|
|
||||||
|
| Campo | Cosa misura | A che serve |
|
||||||
|
|---|---|---|
|
||||||
|
| `bid` / `ask` / `mid` | Prezzi reali Deribit in ETH | P/L reale per backtest |
|
||||||
|
| `iv` | IV implicita allo strike | Calibrazione skew premium |
|
||||||
|
| `delta`/`gamma`/`theta`/`vega` | Greeks | Sizing + risk monitoring |
|
||||||
|
| `open_interest` / `volume_24h` | Liquidità | Validazione gate §4 |
|
||||||
|
|
||||||
|
**Cosa sblocca:**
|
||||||
|
|
||||||
|
- **Backtest non-stilizzato**: il modulo `core/backtest.py` può
|
||||||
|
sostituire la stima Black-Scholes (con `skew_premium` hardcoded a
|
||||||
|
1.5×) leggendo i `mid` reali. Numeri da "stime ex-ante per
|
||||||
|
ranking" a "P/L empirico per dimensionare capitale".
|
||||||
|
- **Calibrazione empirica dello skew**: rapporto fra prezzi
|
||||||
|
Deribit reali e BS pulito → valore data-driven invece di stima a
|
||||||
|
istinto. Va fatto dopo 4-8 settimane di accumulo.
|
||||||
|
- **Validazione ex-post strike picker**: "il delta-0.12 era davvero
|
||||||
|
a 25% OTM in quella settimana?" diventa una `SELECT`.
|
||||||
|
|
||||||
|
**Strumenti CLI:**
|
||||||
|
|
||||||
|
- `cerbero-bite option-chain trigger` — esegue UNA volta il
|
||||||
|
collector senza aspettare il cron. Utile per test e per popolare
|
||||||
|
prima del primo lunedì utile.
|
||||||
|
- `cerbero-bite option-chain analyze [--bias bull_put|bear_call]` —
|
||||||
|
legge l'ultimo snapshot, simula il selector di strike con la
|
||||||
|
strategy passata e stampa: short/long strike, delta, width,
|
||||||
|
credito reale, ratio credit/width, PASS/FAIL del gate
|
||||||
|
`credit_to_width_ratio_min`. Risponde in tempo reale: "il rule
|
||||||
|
engine aprirebbe un trade adesso?".
|
||||||
|
|
||||||
## 5. Come leggere il dato giorno per giorno
|
## 5. Come leggere il dato giorno per giorno
|
||||||
|
|
||||||
Tre euristiche operative sui campi raccolti:
|
Tre euristiche operative sui campi raccolti:
|
||||||
|
|||||||
Reference in New Issue
Block a user