--- id: "0088f" title: "Trading: capability group `risk` + kill_switch" status: pendiente type: feature domain: - trading - meta scope: multi-app priority: alta depends: [] blocks: [] related: [] created: 2026-05-17 updated: 2026-05-17 tags: [] --- # 0088f — Trading: capability group `risk` + kill_switch **Status:** pendiente **Created:** 2026-05-14 **Type:** feature **Parent:** 0088 **Depends:** 0088a **Blocks:** 0088h (live_runner no arranca sin esto) ## Problema Cualquier intent emitido por una Strategy debe pasar por un risk gate **antes** de tocar el broker. El kill_switch debe ser invocable desde CLI/cron/UI antes de que exista un broker live — fail-safe absoluto. ## Piezas 1. Funciones puras: - `position_size_kelly_py_finance(edge, variance, bankroll, kelly_fraction)`. - `position_size_fixed_risk_py_finance(stop_distance, risk_per_trade_pct, equity)`. - `cap_max_loss_per_trade_py_finance(intent, stop_price, equity, max_loss_pct)`. - `cap_exposure_py_finance(intent, current_exposure, exposure_limit)`. - `filter_correlation_py_finance(intents, current_positions, correlation_matrix, max_corr)`. - `apply_risk_pipeline_py_finance(intents, portfolio, risk_config) -> list[OrderIntent]` (pipeline puro que compone las anteriores). 2. Funcion impura `halt_all_strategies_py_finance(reason)`: - Escribe flag `halted=true` en `~/.fn_state/trading_halt.json` (o tabla `system_state` en ledger). - Notifica (telegram via 0061 si aplica). - Idempotente: re-llamar no falla. 3. Funcion pura `is_halted_py_finance(state_path) -> bool` que el live_runner consulta cada ciclo. 4. Funcion `release_halt_py_finance(reason)` (impura, escribe). Solo via CLI manual, NO via API. 5. Tag `risk`. Pagina madre `docs/capabilities/risk.md`. 6. Tests deterministicos sobre cada cap/filter. ## Aceptacion - `./fn run halt_all_strategies` deja el sistema en estado halted en frio (verificable con `is_halted`). - Cualquier intent que falle un cap retorna `[]` (no se emite), motivo logueado en operations.db del live_runner. - Kill_switch invocable sin que el live_runner este corriendo (state file persistente). ## No-objetivos - Risk dinamico aprendido (eso es feature futura). Risk_config se lee de YAML. - UI para risk_config: editable a mano en YAML primero.