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>
10 KiB
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)
# 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)
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
# 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:
- Apre il file in editor.
- All'esci, ricalcola SHA-256 escludendo la riga
config_hash. - Aggiorna
config_hash,last_review,last_reviewer. - Mostra diff ad Adriano.
- Firma in audit chain.
Mismatch hash a runtime = kill switch immediato (vedi 07-risk-controls.md).
Esempi di modifiche valide
Riduzione difensiva post-drawdown
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
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
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.