# 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 |
|---|---|
| Delta short target | 0.12 |
| Tolleranza delta | [0.10, 0.15] |
| Distanza minima OTM | 15% (anche se delta è dentro tolleranza) |
| 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.

### 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 | 5% |

Se non esiste lo strike esatto a 4%, si prende il più vicino entro
[3%, 5%]; altrimenti no entry.

### 3.4 Rapporto credito/larghezza

Il credito netto incassato (mid-price del combo) deve essere ≥ **30%**
della larghezza dello spread. Sotto questa soglia il rapporto
rischio/rendimento è inferiore al minimo accettabile. → no entry.

## 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) |
| 45–60 | × 0.85 |
| 60–80 | × 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.
