Files
Cerbero-Bite/docs/01-strategy-rules.md
T
Adriano Dal Pastro 8a1fb823dc docs: profilo B, collettore research, colonna source, backup giornaliero
Allinea la documentazione alle modifiche di v1.7.0.

- 01-strategy-rules: §3.2 delta short 0.18 (banda 0.12-0.22, OTM>=10%)
  con la motivazione dell'analisi (credit/width ~6% irraggiungibile a
  delta basso); delta_by_dvol aggressiva ritarata; §3.3 width fino a 6%
  (griglia strike 100pt); §3.4 credit/width min 30% -> 8%.
- 05-data-model: option_chain_snapshots alimentata da due collettori
  (live/research) via colonna source; CREATE TABLE + indice aggiornati;
  book_depth_top3 popolato sulle righe research; migrazioni 6 e 7 in
  tabella; backup orario -> giornaliero con nota storica.
- 10-config-spec: valori structure profilo B + nuovo blocco
  research_collector.
- 06-operational-flow: cron summary con i due collettori opzioni.

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

327 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01 — Regole della strategia (Cerberus Bite)
Le regole qui formalizzate sono la versione **canonica e immutabile** che
il rule engine deve applicare. Modifiche richiedono una review esplicita
con Adriano (e una nuova versione di questo documento).
Sorgente teorica: `Cerbero_Office/NewStrategy/strategia-credit-spread-eth.md`
+ analisi Monte Carlo + cap operativi Cerbero v4.
## 1. Universo e strumenti
| Parametro | Valore |
|---|---|
| Sottostante | ETH/USD |
| Exchange | Deribit |
| Tipo opzioni | Europee, cash-settled, USDC-margined |
| Strutture ammesse | Bull Put Spread, Bear Call Spread, (Iron Condor solo in regime laterale, vedere §6) |
| Strutture vietate | Naked options, calendar spread, ratio spread, condor sbilanciati |
## 2. Trigger di apertura (entry)
Il rule engine valuta l'apertura di un nuovo trade **una volta al
giorno**, alle **14:00 UTC** (orario UE pomeridiano stabile, fuori
dai picchi di funding statunitensi). Crypto è 24/7: non c'è un "giorno
buono" intrinseco, sono i gate quantitativi a decidere se entrare o
saltare. Se il giorno è festività italiana e `skip_holidays_country`
è attivo, l'engine attende il giorno successivo.
Una nuova posizione viene aperta **solo se tutte** le seguenti condizioni
sono vere:
1. **Nessuna posizione Cerberus Bite già aperta.**
2. **Capitale corrente ≥ 720 USD.** Sotto questa soglia il sizing in
contratti non può raggiungere 1 unità Deribit.
3. **DVOL corrente ≥ 35.** Sotto 35 il premio è troppo magro per
mantenere il rapporto fees/credit accettabile.
4. **DVOL corrente ≤ 90.** Sopra 90 si è in regime di stress, no entry.
5. **Nessun evento macro** (FOMC, CPI USA, NFP, ECB, Powell speech)
nei prossimi DTE giorni dall'apertura.
6. **Funding rate ETH-PERP** in valore assoluto annualizzato ≤ 80%
(filtra regimi di liquidazioni a cascata imminenti).
7. **Holdings ETH** in `cerbero-portfolio` non superiori al 30% del
patrimonio totale (correlazione direzionale già alta).
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,
ritento il giorno successivo.
## 3. Selezione struttura
### 3.1 Bias direzionale
Il bias è dedotto deterministicamente da due indicatori, mai in modo
discrezionale:
| Indicatore | Calcolo | Soglia bull | Soglia bear |
|---|---|---|---|
| Trend ETH 30g | (ETH_now / ETH_30g_ago - 1) × 100 | ≥ +5% | ≤ -5% |
| Funding cross-exchange | mediana funding annualizzato 4 maggiori exchange | ≥ +20% | ≤ -20% |
Risultato:
- Entrambi bull → **Bull Put Spread**.
- Entrambi bear → **Bear Call Spread**.
- Discordanti → **no entry** (mercato indeciso, edge incerto).
- Entrambi in range neutro `(-5%, +5%)` E DVOL ≥ 55 E ADX(14) < 20 →
**Iron Condor stretto** ammesso (vedi §6).
- Tutti gli altri casi neutri → **no entry**.
### 3.2 Strike short
Si seleziona lo strike short più vicino a delta target, in valore
assoluto.
| Parametro | Valore (profilo B, v1.7.0) |
|---|---|
| Delta short target | 0.18 |
| Tolleranza delta | [0.12, 0.22] |
| Distanza minima OTM | 10% (anche se delta è dentro tolleranza) |
| Distanza massima OTM | 25% |
> **Perché delta 0.18 e non 0.12.** A delta 0.10-0.15 il miglior
> `credit/width` fisicamente ottenibile su ETH (analisi 3.689 snapshot,
> 1mag-8giu '26) è ~6%, sotto il minimo richiesto: 0 spread fattibili.
> Per uno spread verticale `credit/width ≲ delta_short`, quindi l'unica
> leva che produce credito vendibile è vendere più vicino. Trade-off:
> la prob. di assegnazione sale da ~12% a ~18-22%.
**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.22 | 0.18 | 0.25 |
| 70 | 0.18 | 0.12 | 0.22 |
| 90 | 0.15 | 0.10 | 0.18 |
Se nessuno strike disponibile rientra in entrambe le tolleranze → no entry.
### 3.3 Strike long (protezione)
Si seleziona lo strike a distanza fissa dallo short:
| Parametro | Valore |
|---|---|
| Larghezza spread (in % di spot) | 4% |
| Larghezza minima accettabile | 3% |
| Larghezza massima accettabile | 6% |
Se non esiste lo strike esatto a 4%, si prende il più vicino entro
[3%, 6%]; altrimenti no entry. La banda arriva a 6% perché la griglia
strike ETH sotto i $1500 è a 100pt (~6% a spot <$2k): con cap 5%
nessuna gamba long rientrava in banda.
### 3.4 Rapporto credito/larghezza
Il credito netto incassato (mid-price del combo) deve essere ≥ **8%**
della larghezza dello spread (profilo B). → altrimenti no entry.
> Era **30%**, ma è fisicamente irraggiungibile con delta short ≤0.22
> in questo mercato: il miglior `credit/width` misurato su ETH è ~6%
> (anche vendendo a delta 0.30 non si superava il 20%). La soglia 8% è
> allineata al realizzabile a delta ~0.18 e mantiene un floor sul
> rapporto rischio/rendimento.
## 4. Liquidità (filtro hard pre-entry)
Per ciascuno strumento delle due gambe, **tutte** le condizioni:
| Misura | Soglia |
|---|---|
| Open interest | ≥ 100 contratti |
| Volume 24h sullo strumento | ≥ 20 contratti |
| Spread bid-ask | ≤ 15% del mid (≤ 10% per ATM, irrilevante qui) |
| Profondità book ai primi 3 livelli | ≥ 5 contratti aggregati |
Calcoliamo inoltre uno **slippage stimato** moltiplicando la larghezza
del bid-ask di entrambe le gambe per la size proposta. Se lo slippage
totale > 8% del credito atteso → no entry.
## 5. Sizing
### 5.1 Calcolo numero contratti
```
risk_target_usd = capitale_corrente * 0.13 # Quarter Kelly
risk_target_usd = min(risk_target_usd, 200_eur_in_usd) # cap Cerbero
n_contracts = floor(risk_target_usd / max_loss_per_contract)
n_contracts = min(n_contracts, 4) # cap aggregato implicito
```
`max_loss_per_contract` = larghezza spread × multiplier ETH (1 ETH).
### 5.2 Vincolo aggregato
Se `n_contracts × max_loss_per_contract + engagement_aperto_totale > 1.000_eur` →
riduci `n_contracts` finché il vincolo è rispettato. Se risulta < 1 → no entry.
### 5.3 Volatilità di volatilità
Sizing dinamico per regime DVOL:
| DVOL corrente | Aggiustamento `n_contracts` |
|---|---|
| < 45 | × 1.0 (base) |
| 4560 | × 0.85 |
| 6080 | × 0.65 |
| > 80 | (no entry, vedi §2) |
Arrotondamento sempre per difetto a intero, minimo 1.
## 6. Iron Condor (ammesso solo in regime laterale)
Se le condizioni del §3.1 attivano IC, struttura:
- Bull Put Spread alle stesse regole §3.2/§3.3
- Bear Call Spread speculare (delta 0.12, 4% width)
- Sizing: `n_contracts` calcolato come sopra ma **dimezzato** per gamba
(rischio totale = somma max loss dei due lati, ma su ETH i due lati
non possono essere entrambi violati, quindi rischio effettivo = max
loss del lato peggiore + credito del lato vincente)
- Profit take: 25% del credito totale (più aggressivo)
- Tutto il resto delle regole §7-§9 si applica per lato.
## 7. Gestione attiva (decision loop ogni 12 ore)
Per ogni posizione aperta, il rule engine valuta in ordine:
1. **Profit take** — se mark price del combo ≤ 50% del credito incassato,
`decision = CLOSE_PROFIT`.
2. **Stop loss stretto** — se mark price del combo ≥ 250% del credito
(perdita = 1.5× credito), `decision = CLOSE_STOP`.
3. **Vol stop** — se DVOL corrente ≥ DVOL all'entry + 10,
`decision = CLOSE_VOL`.
4. **Time stop** — se `(scadenza - oggi) ≤ 7 giorni`,
`decision = CLOSE_TIME` (a meno che non siamo già al 50% di profit:
in quel caso teniamo per regola 1 in arrivo).
5. **Strike testato** — se `|delta_short_corrente| ≥ 0.30`,
`decision = CLOSE_DELTA`. Su ETH non si difende, si esce.
6. **Movimento esplosivo** — se `|return_4h_ETH| ≥ 5%` direzione avversa,
`decision = CLOSE_AVERSE` (azione conservativa, può essere finalizzata
alla prossima fenestra).
7. Altrimenti `decision = HOLD`.
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_days` giorni (skip-day 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%, 14
giorni di pausa.
## 8. Esecuzione di apertura
1. Engine costruisce **combo order Deribit** (un solo ordine atomico
con due gambe). Mai due ordini separati.
2. Limit price = mid-price calcolato dall'engine.
3. Ordine inviato come limit GTC con time-in-force che scade alle
16:00 UTC dello stesso giorno.
4. Se non riempito entro 30 min, engine alza limit di 1 tick verso
ask combinato fino a un massimo di 3 step (poi cancella e log
"no fill").
5. Riempimento → engine persiste lo stato (vedi `05-data-model.md`)
includendo: spot ETH, DVOL, strike, scadenza, credit incassato,
timestamp.
## 9. Esecuzione di chiusura
1. Stessa logica di combo, in direzione inversa.
2. Limit di partenza al mid-price.
3. Se non riempito entro 30 min: alza limit fino a 3 step verso il
bid combinato. Su trigger `CLOSE_STOP` o `CLOSE_VOL` o `CLOSE_DELTA`
l'engine può accettare slippage maggiore (fino a 5 step) perché
l'urgenza prevale sul prezzo.
4. Riempimento → posizione marcata `CLOSED`, P&L calcolato e loggato,
record archiviato per Kelly recalibration mensile.
## 10. Cosa NON fa il rule engine — esplicito
- Non rolla mai una posizione (regola §7.5: si esce e basta).
- Non aggiunge gambe a una posizione esistente (no conversione in IC
durante un trade aperto).
- Non aggiusta strike o size dopo l'apertura.
- Non apre nuovi trade per "compensare" perdite recenti.
- Non opera fuori dalla finestra delle 14:00 UTC, eccetto chiusure.
- Non deroga ai cap nemmeno per "opportunità eccezionali".
- Non si aggiorna automaticamente: nuovo set di regole = nuovo deploy
con review esplicita.
## 11. Riepilogo soglie (parametri di config)
Tutti i numeri sopra sono **parametrizzati** in `strategy.yaml` (vedi
`10-config-spec.md`). Modificarli è una decisione di Adriano con
giustificazione scritta nel commit message. La regola di default
fissata da questo documento è la **golden config** che il sistema parte
con al primo deploy.