Metadata-Version: 2.4
Name: kadmos-risk
Version: 0.2.0
Summary: Deterministic pre-trade risk gate: ATR sizing, fail-closed counters, atomic state, operator lock
Author: Rafael Viegas / BRAVENDI
License: MIT
Project-URL: Homepage, https://github.com/Bravendi/kadmos-risk
Keywords: trading,risk,position-sizing,crypto,futures,atr
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# kadmos-risk

Deterministic pre-trade risk gate for crypto futures bots: ATR-based sizing,
fail-closed counters, atomic state, single-operator lock. Framework-agnostic
(works with ccxt or any exchange that gives you price + ATR inputs).

**The rule that matters:** position size = risk budget ÷ real stop distance.
Not capital ÷ leverage. Not gut feeling. This package makes that arithmetic
enforced, auditable, and un-skippable.

```python
from kadmos_risk import size_position, RiskLimits, load_gate_state, register_trade

state = load_gate_state("state/risk_state.json")
plan = size_position(
    capital=4178.0,
    price=0.2105,
    atr=0.0062,           # from your candles (4h default)
    limits=RiskLimits(risk_per_trade_pct=2.0, max_positions=2,
                      max_trades_per_day=30, max_consecutive_losses=5,
                      max_daily_loss_pct=6.0),
    state=state,
)
if plan.approved:
    # plan.quantity, plan.stop_distance_pct, plan.risk_usdt
    ...execute...
    register_trade(state, symbol="ENA/USDT")   # counters are fail-closed
```

## What it enforces

| Guard | Behaviour |
|---|---|
| **ATR sizing** | quantity = capital × risk% ÷ stop distance (same ATR source used for the stop itself — mismatch = silent 3× real risk) |
| **Daily limits** | trades/day, consecutive losses, daily loss kill-switch, max simultaneous positions |
| **Fail-closed counters** | if the trade registration fails, the gate refuses further trades until a successful register (a counter that never increments is decoration) |
| **Atomic state** | all state writes are tmp + fsync + os.replace — one SIGKILL never wipes the ledger |
| **Operator lock** | `require_operator(env_var, key_file)` — mutating entry points exit 75 without the key |

## Why

Built the hard way on a live demo-trading bot. Every guard in this package
corresponds to a real incident: sizing on one timeframe while the stop was
computed on another; a mkdir lock that froze the pipeline after SIGKILL; a
state file truncated by a non-atomic write; alert floods caused by watching
state instead of events. None of it is theoretical.

MIT licensed. Not financial advice. The exchange always gets the last word.
