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