Files
Cerbero-Bite/docs/10-config-spec.md
T
root 6ff021fbf4 feat(strategy): abbandono gating settimanale — entry daily 24/7
Crypto opera 24/7: la cadenza settimanale lunedì-only era un retaggio
TradFi senza giustificazione. La nuova cadenza è giornaliera (cron
0 14 * * *), con i gate quantitativi a decidere se entrare o saltare.

Cambiamenti principali:

* runtime/orchestrator.py — _CRON_ENTRY 0 14 * * * (era MON)
* runtime/auto_pause.py — pause_until(days=) (era weeks=); minimo
  clamp 1 giorno (era 1 settimana)
* core/backtest.py — MondayPick→DailyPick, monday_picks→daily_picks
  (1 pick per calendar-day all'ora target); Sharpe annualization su
  ~120 trade/anno (era 52)
* config/schema.py — default cron daily; max_concurrent_positions 1→5;
  AutoPauseConfig.pause_weeks→pause_days, default 14
* runtime/option_chain_snapshot_cycle.py + orchestrator — cron */15
  per accumulo continuo dataset di backtest empirico

Strategy yamls (config_version 1.3.0 → 1.4.0, hash rigenerati):

* strategy.yaml — max_concurrent 1→5, cap_aggregate coerente
* strategy.aggressiva.yaml — max_concurrent 2→8, cap_aggregate
  3200→6400, max_contracts_per_trade invariato a 16
* strategy.conservativa.yaml — max_concurrent 1→3
* tutti — pause_weeks→pause_days: 14

GUI (pages/7_📚_Strategia.py):

* slider Trade/anno: range 20-200 (era 8-30), default 110, help
  riallineato sulla math 365 candidature × pass-rate 30-40%
* card profili: versione letta dinamicamente da config_version invece
  che hard-coded "v1.2.0"
* warning "entrambi perdono soldi" ora valuta i P/L effettivi
  (cons['annual_pl'], aggr['annual_pl']) invece del win_rate grezzo;
  aggiunto stato intermedio quando solo conservativo è in perdita

Tests (450/450 passati):

* test_auto_pause: pause_days, clamp ≥1 giorno
* test_backtest: rinomina + ridisegno daily picks (assert su
  calendar-day dedupe e hour filter)
* test_sizing_engine: other_open_positions=5 per cap default
* test_config_loader: version 1.4.0

Docs (README + 9 file in docs/) — tutti i riferimenti weekly/lunedì
allineati a daily/24-7, volume option_chain ricalcolato per cron
*/15 (~1.1 MB/giorno, ~400 MB/anno).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 16:21:16 +00:00

338 lines
10 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.
# 10 — Config Spec (`strategy.yaml`)
Tutti i parametri della strategia sono esposti in un file YAML
versionato. Modificare il file = decisione esplicita di Adriano.
Modifiche richiedono nuovo `config_version`, ricalcolo `config_hash`
e commit con motivazione.
## Schema completo (golden default)
```yaml
# strategy.yaml — Cerberus Bite golden config v1.0.0
# Riferimento: docs/01-strategy-rules.md
# NB: hash auto-calcolato dal CLI `cerbero-bite config hash`
config_version: "1.0.0"
config_hash: "0000000000000000000000000000000000000000000000000000000000000000" # placeholder
last_review: "2026-04-26"
last_reviewer: "Adriano"
asset:
symbol: "ETH"
exchange: "deribit"
# === ENTRY ===
entry:
# finestra di valutazione giornaliera (crypto 24/7)
cron: "0 14 * * *" # ogni giorno 14:00 UTC
skip_holidays_country: "IT"
# filtri di accesso (vedi 01-strategy-rules.md §2)
capital_min_usd: 720
dvol_min: 35
dvol_max: 90
funding_perp_abs_max_annualized: 0.80
eth_holdings_pct_max: 0.30
no_position_concurrent: true # 1 sola posizione alla volta
exclude_macro_severity: ["high"]
exclude_macro_countries: ["US", "EU"]
# bias direzionale (§3.1)
trend_window_days: 30
trend_bull_threshold_pct: 0.05
trend_bear_threshold_pct: -0.05
funding_bull_threshold_annualized: 0.20
funding_bear_threshold_annualized: -0.20
iron_condor_dvol_min: 55
iron_condor_adx_max: 20
iron_condor_trend_neutral_band_pct: 0.05
# === STRUCTURE ===
structure:
dte_target: 18
dte_min: 14
dte_max: 21
short_strike:
delta_target: 0.12
delta_min: 0.10
delta_max: 0.15
distance_otm_pct_min: 0.15
distance_otm_pct_max: 0.25
spread_width:
target_pct_of_spot: 0.04
min_pct_of_spot: 0.03
max_pct_of_spot: 0.05
credit_to_width_ratio_min: 0.30
# === LIQUIDITY GATE ===
liquidity:
open_interest_min: 100
volume_24h_min: 20
bid_ask_spread_pct_max: 0.15
book_depth_top3_min: 5
slippage_pct_of_credit_max: 0.08
# === SIZING ===
sizing:
kelly_fraction: 0.13 # Quarter Kelly basato su MC
# cap nominali (Cerbero v4 hard prohibitions)
cap_per_trade_eur: 200
cap_aggregate_open_eur: 1000
max_concurrent_positions: 1 # da 2+ solo via override esplicito
# soft cap difensivi (interni a Cerbero Bite)
max_contracts_per_trade: 4
# aggiustamento volatilità
dvol_adjustment:
- {dvol_under: 45, multiplier: 1.00}
- {dvol_under: 60, multiplier: 0.85}
- {dvol_under: 80, multiplier: 0.65}
# >= 80 → no entry (gestito da entry filters)
# === EXIT ===
exit:
# ordine di valutazione vincolante
profit_take_pct_of_credit: 0.50
stop_loss_mark_x_credit: 2.50 # mark = 250% credito → perdita 1.5×
vol_stop_dvol_increase: 10
time_stop_dte_remaining: 7
time_stop_skip_if_close_to_profit_pct: 0.70 # skip se mark ≤ 70% di profit_take
delta_breach_threshold: 0.30
adverse_move_4h_pct: 0.05
monitor_cron: "0 2,14 * * *" # 02 + 14 UTC
user_confirmation_timeout_min: 30
# escalation per urgenza alta
escalate_on_timeout:
- "CLOSE_STOP"
- "CLOSE_VOL"
- "CLOSE_DELTA"
# === EXECUTION ===
execution:
combo_only: true # mai due ordini separati
initial_limit: "mid"
reprice_step_ticks: 1
reprice_max_steps: 3
reprice_max_steps_urgent: 5 # per chiusure urgenti
order_tif: "GTC"
order_expiry_min: 30
ack_timeout_s: 300 # ack Cerbero core
# === MONITORING ===
monitoring:
health_check_interval_s: 300
health_failures_before_kill: 3
health_failures_before_restart: 5
daily_digest_cron: "0 8 * * *"
monthly_report_cron: "0 12 1 * *"
# === STORAGE ===
storage:
sqlite_path: "data/state.sqlite"
log_path: "data/log/"
log_retention_days: 365
backup_path: "data/backups/"
backup_retention_days: 30
# === MCP ===
mcp:
config_file: "~/.config/cerbero-suite/mcp.json"
call_timeout_s: 8
retry_max: 3
retry_base_delay_s: 1
required_versions:
cerbero-deribit: "^2.0.0"
cerbero-hyperliquid: "^1.5.0"
cerbero-memory: "^4.0.0"
cerbero-portfolio: "^1.2.0"
cerbero-macro: "^1.0.0"
cerbero-sentiment: "^1.0.0"
cerbero-telegram: "^1.0.0"
cerbero-brain-bridge: "^1.0.0"
# === TELEGRAM ===
telegram:
parse_mode: "MarkdownV2"
confirmation_timeout_min: 60
exit_confirmation_timeout_min: 30
backup_channel_on_critical: true # canale BotPapà su severity critical
# === KELLY RECALIBRATION ===
kelly_recalibration:
lookback_days: 365
min_sample_low_confidence: 30
min_sample_high_confidence: 100
weight_when_medium_confidence: 0.50
```
## Validazione (`config/schema.py`)
```python
from pydantic import BaseModel, Field, model_validator
from decimal import Decimal
class StrategyConfig(BaseModel):
config_version: str
config_hash: str
last_review: str
last_reviewer: str
asset: AssetConfig
entry: EntryConfig
structure: StructureConfig
liquidity: LiquidityConfig
sizing: SizingConfig
exit: ExitConfig
execution: ExecutionConfig
monitoring: MonitoringConfig
storage: StorageConfig
mcp: McpConfig
telegram: TelegramConfig
kelly_recalibration: KellyConfig
@model_validator(mode="after")
def validate_consistency(self) -> "StrategyConfig":
# short delta range coerente
s = self.structure.short_strike
if not (s.delta_min <= s.delta_target <= s.delta_max):
raise ValueError("delta_target outside [delta_min, delta_max]")
# OTM range coerente
if s.distance_otm_pct_min >= s.distance_otm_pct_max:
raise ValueError("OTM range invalid")
# Kelly range
if not (0 < self.sizing.kelly_fraction < 0.5):
raise ValueError("kelly_fraction out of safe range (0, 0.5)")
# spread width range
sw = self.structure.spread_width
if not (sw.min_pct_of_spot <= sw.target_pct_of_spot <= sw.max_pct_of_spot):
raise ValueError("spread_width target outside min/max")
# exit thresholds sensati
if self.exit.profit_take_pct_of_credit >= 1.0:
raise ValueError("profit_take >= 100% impossible")
if self.exit.stop_loss_mark_x_credit <= 1.0:
raise ValueError("stop_loss multiple <= 1× makes no sense")
return self
```
## Override locale
Se esiste `strategy.local.yaml` (gitignored), i suoi campi sovrascrivono
`strategy.yaml`. Usato per:
- Test in dry-run con cap dimezzati
- Personalizzazioni dello sviluppatore senza inquinare il main
- Override emergenza ("max_concurrent_positions: 0" per congelare entry
senza disabilitare l'engine)
L'override viene loggato all'avvio:
```
2026-04-27T10:00:00Z | OVERRIDE_APPLIED | sizing.cap_per_trade_eur: 200 → 100
```
## Hash integrity
```bash
# Calcolo manuale
cerbero-bite config hash
# Aggiornamento automatico (richiede review prompt)
cerbero-bite config update --reason "Reduce kelly to 0.10 after Apr drawdown"
```
Il comando:
1. Apre il file in editor.
2. All'esci, ricalcola SHA-256 escludendo la riga `config_hash`.
3. Aggiorna `config_hash`, `last_review`, `last_reviewer`.
4. Mostra diff ad Adriano.
5. Firma in audit chain.
Mismatch hash a runtime = kill switch immediato (vedi `07-risk-controls.md`).
## Esempi di modifiche valide
### Riduzione difensiva post-drawdown
```diff
sizing:
- kelly_fraction: 0.13
+ kelly_fraction: 0.10
```
Commit: `chore(config): reduce kelly to 0.10 after April -20% DD`.
### Aggiunta nuovo evento macro escluso
```diff
entry:
exclude_macro_severity: ["high"]
+ exclude_macro_keywords: ["Powell", "Lagarde", "ETF approval"]
```
Commit: `chore(config): exclude ETF-related events from entry window`.
### Disabilitazione temporanea iron condor
```diff
entry:
- iron_condor_dvol_min: 55
+ iron_condor_dvol_min: 999 # de facto disabled
```
Commit: `chore(config): disable IC pending review of vol regime`.
## Cosa NON è in config
Non è permesso parametrizzare:
- L'**ordine** dei trigger di uscita (è una scelta strategica codificata).
- Le **strutture** ammesse (vietato vendita nuda, ecc., scolpito nel codice).
- Le **hard prohibitions** Cerbero v4 (cap 200/1000 EUR sono limiti
superiori, non ulteriormente liberalizzabili).
- Lo **scheduler** per intervalli più stretti (un'ottimizzazione che
non si fa via config).
## Variabili d'ambiente
`strategy.yaml` definisce **cosa** fa il bot quando è acceso. Le
variabili d'ambiente in `.env` definiscono **come** si collega al
mondo esterno e **quali interruttori operativi** sono attivi.
Queste vivono fuori da `strategy.yaml` perché cambiano per ambiente
(testnet vs mainnet, soak vs trading) ma non per regola di strategia.
| Variabile | Tipo | Default | Uso |
|---|---|---|---|
| `CERBERO_BITE_MCP_TOKEN` | string (obbligatoria) | — | Bearer token presentato a Cerbero MCP V2. Il valore decide l'ambiente upstream (testnet o mainnet). Cambia il valore = cambia l'ambiente. |
| `CERBERO_BITE_MCP_BOT_TAG` | string ≤ 64 char | `BOT__CERBERO_BITE` | Header `X-Bot-Tag` registrato nell'audit log del server MCP per ogni write. |
| `CERBERO_BITE_MCP_DERIBIT_URL` | URL | gateway pubblico | Override URL router Deribit. |
| `CERBERO_BITE_MCP_HYPERLIQUID_URL` | URL | gateway pubblico | Override URL router Hyperliquid. |
| `CERBERO_BITE_MCP_MACRO_URL` | URL | gateway pubblico | Override URL router Macro. |
| `CERBERO_BITE_MCP_SENTIMENT_URL` | URL | gateway pubblico | Override URL router Sentiment. |
| `CERBERO_BITE_ENABLE_DATA_ANALYSIS` | bool (`true`/`false`) | `true` | Abilita il job `market_snapshot` (raccolta dati MCP ogni 15 min). |
| `CERBERO_BITE_ENABLE_STRATEGY` | bool (`true`/`false`) | `false` | Abilita i job `entry` e `monitor` (esecuzione regole §2-§9). |
| `CERBERO_BITE_TELEGRAM_BOT_TOKEN` | string | — | Token bot Telegram (notify-only). Senza, il client è in modalità disabled. |
| `CERBERO_BITE_TELEGRAM_CHAT_ID` | string | — | Chat ID destinatario notifiche Telegram. |
I valori bool accettano in input `1`/`0`, `true`/`false`, `yes`/`no`,
`on`/`off`, `enabled`/`disabled` (case-insensitive). Qualunque altro
valore fa fallire il boot con `ValueError`.
Vedi `06-operational-flow.md` §"Modalità operativa" per i profili
canonici di `ENABLE_DATA_ANALYSIS` e `ENABLE_STRATEGY`.