Risk envelope
A RiskEnvelope is a declarative spec of the limits your strategy must operate inside. The paper runtime enforces it before recording a simulated fill. Strategies declare the envelope as a class attribute; the runtime reads it once at deploy time and gates every ctx.place() against it.
Available limits
from decimal import Decimal
from banger.risk import RiskEnvelope
class MyStrategy(Strategy):
risk = RiskEnvelope(
max_position_usd=Decimal("200"),
max_daily_loss_usd=Decimal("500"),
max_open_positions=5,
max_concentration_pct=0.25,
max_orders_per_minute=10,
)
...| Field | Type | Effect |
|---|---|---|
max_position_usd | Decimal | Cumulative cost-basis cap for one venue/market/side position. |
max_daily_loss_usd | Decimal | Blocks new orders when mark-to-market loss since the current UTC day baseline reaches the limit. |
max_open_positions | int | Cap on simultaneous open positions across all venues. |
max_concentration_pct | float (0–1) | Max cost-basis share of the paper account for one position. |
max_orders_per_minute | int | Sliding 60-second limit on successful order attempts. |
All fields are optional. Unset = no limit. Set what you need.
What happens on a violation
When ctx.place() would breach an envelope limit:
- The order is not placed.
RiskViolationis raised.- The runtime logs a
strategy.risk_violationevent with the reason. - The next event handler invocation continues normally.
Strategies can also gate proactively with ctx.can_open_position() — true if the envelope currently permits a new position.
Why declarative?
Two reasons. First, it’s auditable: the envelope is a single block of declarative config that anyone reading the file can see. No buried if statements scattered through your strategy code. Second, the same declaration can be snapshotted with a deployment. Live execution is not released; its future control-plane risk engine must independently re-enforce every limit outside user code.
What the envelope doesn’t do
- It doesn’t hedge. If you want a market-neutral exposure, place the hedge leg yourself.
- It doesn’t close existing positions when a limit gets tighter — only blocks new ones.
- It doesn’t enforce the same limits across strategies. Account-wide aggregation is on the roadmap (per-strategy is what v0 ships).