881bc8a1bf
- pyproject.toml with uv, deps for runtime + gui + backtest + dev - ruff/mypy strict config, pre-commit hooks for ruff/mypy/pytest - src/cerbero_bite/ layout with empty modules ready for Phase 1+ - structlog JSONL logger with daily rotation - click CLI with placeholder subcommands (status, start, kill-switch, gui, replay, config hash, audit verify) - 6 smoke tests passing, mypy --strict clean, ruff clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
310 lines
8.1 KiB
Markdown
310 lines
8.1 KiB
Markdown
# 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 settimanale
|
||
cron: "0 14 * * MON" # lunedì 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).
|