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>
This commit is contained in:
Adriano Dal Pastro
2026-06-09 08:31:59 +00:00
parent 4d7b02b6cb
commit 8a1fb823dc
4 changed files with 93 additions and 30 deletions
+26 -12
View File
@@ -100,13 +100,20 @@ Risultato:
Si seleziona lo strike short più vicino a delta target, in valore Si seleziona lo strike short più vicino a delta target, in valore
assoluto. assoluto.
| Parametro | Valore | | Parametro | Valore (profilo B, v1.7.0) |
|---|---| |---|---|
| Delta short target | 0.12 | | Delta short target | 0.18 |
| Tolleranza delta | [0.10, 0.15] | | Tolleranza delta | [0.12, 0.22] |
| Distanza minima OTM | 15% (anche se delta è dentro tolleranza) | | Distanza minima OTM | 10% (anche se delta è dentro tolleranza) |
| Distanza massima OTM | 25% | | 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 **Variante dinamica per regime DVOL (Phase 5, opt-in).** Il campo
`short_strike.delta_by_dvol` (lista step-function) sostituisce il `short_strike.delta_by_dvol` (lista step-function) sostituisce il
delta target singolo con bande ordinate per `dvol_under`: a DVOL delta target singolo con bande ordinate per `dvol_under`: a DVOL
@@ -117,9 +124,9 @@ classico col delta target sopra. Esempio bande nel profilo
| dvol_under | delta_target | delta_min | delta_max | | dvol_under | delta_target | delta_min | delta_max |
|---|---|---|---| |---|---|---|---|
| 50 | 0.15 | 0.13 | 0.17 | | 50 | 0.22 | 0.18 | 0.25 |
| 70 | 0.12 | 0.10 | 0.15 | | 70 | 0.18 | 0.12 | 0.22 |
| 90 | 0.10 | 0.08 | 0.12 | | 90 | 0.15 | 0.10 | 0.18 |
Se nessuno strike disponibile rientra in entrambe le tolleranze → no entry. Se nessuno strike disponibile rientra in entrambe le tolleranze → no entry.
@@ -131,16 +138,23 @@ Si seleziona lo strike a distanza fissa dallo short:
|---|---| |---|---|
| Larghezza spread (in % di spot) | 4% | | Larghezza spread (in % di spot) | 4% |
| Larghezza minima accettabile | 3% | | Larghezza minima accettabile | 3% |
| Larghezza massima accettabile | 5% | | Larghezza massima accettabile | 6% |
Se non esiste lo strike esatto a 4%, si prende il più vicino entro Se non esiste lo strike esatto a 4%, si prende il più vicino entro
[3%, 5%]; altrimenti no entry. [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 ### 3.4 Rapporto credito/larghezza
Il credito netto incassato (mid-price del combo) deve essere ≥ **30%** Il credito netto incassato (mid-price del combo) deve essere ≥ **8%**
della larghezza dello spread. Sotto questa soglia il rapporto della larghezza dello spread (profilo B). → altrimenti no entry.
rischio/rendimento è inferiore al minimo accettabile. → 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) ## 4. Liquidità (filtro hard pre-entry)
+35 -12
View File
@@ -229,12 +229,23 @@ NULL = engine attivo.
### `option_chain_snapshots` ### `option_chain_snapshots`
Snapshot della catena opzioni Deribit prelevata in continuo Snapshot della catena opzioni Deribit. La tabella è alimentata da
(cron `*/15 * * * *`, allineato a `market_snapshots`). Crypto è **due collettori distinti**, separati dalla colonna `source`:
24/7: l'accumulo dataset deve essere continuo, non gateato sulla
settimana. Ogni tick contiene un quote per strumento entro la * `source='live'` — collettore operativo (cron `*/15 * * * *`,
finestra `[dte_min, dte_max]` di config; tutti i quote prelevati allineato a `market_snapshots`). Ogni tick contiene un quote per
nello stesso tick condividono ``timestamp``. Migration `0005`. strumento entro la finestra `[dte_min, dte_max]` di config (1
scadenza, ~13-15 strike); `book_depth_top3` NULL.
* `source='research'` — collettore full-chain (§13-bis, cron orario,
opt-in via `research_collector.enabled`). Cattura tutte le scadenze
`expiry_max_days` ed entrambe le ali, con `book_depth_top3`
popolato. Trasforma il dataset da "skew/premi medi" a backtest
opzioni vero (per-trade e standing put).
Crypto è 24/7: l'accumulo dataset deve essere continuo, non gateato
sulla settimana. Tutti i quote prelevati nello stesso tick
condividono ``timestamp``. Migration `0005` (tabella), `0007`
(colonna `source`).
```sql ```sql
CREATE TABLE option_chain_snapshots ( CREATE TABLE option_chain_snapshots (
@@ -255,15 +266,19 @@ CREATE TABLE option_chain_snapshots (
open_interest INTEGER, open_interest INTEGER,
volume_24h INTEGER, volume_24h INTEGER,
book_depth_top3 INTEGER, book_depth_top3 INTEGER,
source TEXT NOT NULL DEFAULT 'live',
PRIMARY KEY (timestamp, instrument_name) PRIMARY KEY (timestamp, instrument_name)
) WITHOUT ROWID; ) WITHOUT ROWID;
``` ```
Indici: `(asset, timestamp DESC)` per listing recenti, `(asset, Indici: `(asset, timestamp DESC)` per listing recenti, `(asset,
expiry)` per query per scadenza specifica. ``book_depth_top3`` è expiry)` per query per scadenza specifica, `(asset, source,
NULL by design — il collector non chiama l'order book per ogni timestamp DESC)` per separare live/research nelle query di backtest.
strike per non saturare l'API; lo legge il liquidity gate live solo ``book_depth_top3`` è NULL sulle righe `live` (il collector operativo
sugli strike candidati al picker. 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)
ed è **popolato sulle righe `research`** (1 call orderbook/strumento,
concorrenza limitata) per modellare lo slippage reale.
**Sblocca**: il backtest non-stilizzato (modulo `core/backtest.py` **Sblocca**: il backtest non-stilizzato (modulo `core/backtest.py`
con prezzi reali invece di Black-Scholes), la calibrazione empirica con prezzi reali invece di Black-Scholes), la calibrazione empirica
@@ -363,12 +378,20 @@ idempotente, forward-only:
| 3 | `0003_market_snapshots.sql` | tabella `market_snapshots` | | 3 | `0003_market_snapshots.sql` | tabella `market_snapshots` |
| 4 | `0004_auto_pause.sql` | `system_state.auto_pause_until / _reason` | | 4 | `0004_auto_pause.sql` | `system_state.auto_pause_until / _reason` |
| 5 | `0005_option_chain_snapshots.sql` | tabella `option_chain_snapshots` | | 5 | `0005_option_chain_snapshots.sql` | tabella `option_chain_snapshots` |
| 6 | `0006_dvol_history_multi_asset.sql` | `dvol_history` multi-asset |
| 7 | `0007_option_chain_source.sql` | colonna `source` (live/research) + indice |
## Backup ## Backup
Backup orari di `state.sqlite` in Backup **giornalieri** di `state.sqlite` in
`data/backups/state-YYYYMMDD-HH.sqlite`, ritenuti per 30 giorni. `data/backups/state-YYYYMMDD-HH.sqlite`, ritenuti per 30 giorni.
Operazione idempotente con SQLite `VACUUM INTO`. Lo job è registrato Operazione idempotente con SQLite `VACUUM INTO`. Lo job è registrato
nello scheduler dell'orchestrator (`backup_cron = "0 * * * *"`); è nello scheduler dell'orchestrator (`backup_cron = "0 0 * * *"`); è
disponibile anche come CLI `python scripts/backup.py` per backup disponibile anche come CLI `python scripts/backup.py` per backup
ad-hoc. ad-hoc.
> Nota storica: il cron era orario (`0 * * * *`) e accumulava ~16 GB
> di snapshot full per ~98 MB di dato unico (la stessa catena opzioni
> ricopiata ~24×/giorno). Portato a giornaliero per ridurre il
> footprint di ~24× a parità di retention — rilevante prima di
> accendere il collettore research, che 2-4× la crescita del DB.
+2
View File
@@ -234,6 +234,8 @@ proposed
| `0 12 1 * *` | Kelly recalibration | Mensile | | `0 12 1 * *` | Kelly recalibration | Mensile |
| `*/5 * * * *` | Health check | 5 min | | `*/5 * * * *` | Health check | 5 min |
| `*/15 * * * *` | Market snapshot (calibrazione soglie) | 15 min | | `*/15 * * * *` | Market snapshot (calibrazione soglie) | 15 min |
| `*/15 * * * *` | Option chain snapshot (live, finestra DTE strategia) | 15 min |
| `0 * * * *` | Option chain research (full-chain + book_depth, opt-in) | Orario |
| `0 0 * * *` | Backup SQLite + rotation log | Giornaliero | | `0 0 * * *` | Backup SQLite + rotation log | Giornaliero |
| `0 8 * * *` | Daily digest Telegram | Giornaliero | | `0 8 * * *` | Daily digest Telegram | Giornaliero |
+30 -6
View File
@@ -55,19 +55,43 @@ structure:
dte_min: 14 dte_min: 14
dte_max: 21 dte_max: 21
# Profilo B (v1.7.0). L'analisi su 3.689 snapshot (1mag-8giu '26) ha
# mostrato che a delta 0.10-0.15 il miglior credit/width fisicamente
# ottenibile è ~6%, quindi il vecchio credit_to_width_ratio_min=0.30
# era irraggiungibile (0 spread fattibili). La sola leva efficace è
# vendere più vicino → delta alzato a ~0.18.
short_strike: short_strike:
delta_target: 0.12 delta_target: 0.18
delta_min: 0.10 delta_min: 0.12
delta_max: 0.15 delta_max: 0.22
distance_otm_pct_min: 0.15 distance_otm_pct_min: 0.10
distance_otm_pct_max: 0.25 distance_otm_pct_max: 0.25
spread_width: spread_width:
target_pct_of_spot: 0.04 target_pct_of_spot: 0.04
min_pct_of_spot: 0.03 min_pct_of_spot: 0.03
max_pct_of_spot: 0.05 # 0.06: la griglia strike ETH sotto i $1500 è a 100pt (~6% a spot
# <$2k); con cap 0.05 nessuna gamba long rientrava in banda.
max_pct_of_spot: 0.06
credit_to_width_ratio_min: 0.30 credit_to_width_ratio_min: 0.08 # era 0.30 (irraggiungibile a delta ≤0.22)
# === RESEARCH COLLECTOR (§13-bis) ===
# Collettore opzioni full-chain, indipendente dal live. Cattura tutte
# le scadenze ≤ expiry_max_days ed entrambe le ali, popolando
# book_depth_top3 (1 call orderbook/strumento) → backtest opzioni
# per-trade e standing. Disabilitato di default: costo API non
# trascurabile. Scrive righe con source='research'.
research_collector:
enabled: false
cron: "0 * * * *" # orario, indipendente dal */15 del live
expiry_max_days: 95 # 1g..3mesi
moneyness_band_pct: null # null = catena completa (entrambe le ali)
open_interest_min: 100
fetch_book_depth: true
book_depth_concurrency: 8 # concorrenza max delle call orderbook
assets: ["ETH", "BTC"]
# === LIQUIDITY GATE === # === LIQUIDITY GATE ===