Files
fn_registry/dev/issues/0088f-trading-risk-capability-group-and-kill-switch.md
T

59 lines
2.2 KiB
Markdown

---
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.