N°04 / Build

Risk envelope

A RiskEnvelope is a declarative spec of the limits your strategy must operate inside. The runtime enforces it before any order leaves your machine. 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,
    )
    ...
FieldTypeEffect
max_position_usdDecimalSingle-position notional cap. Exceeding it raises RiskViolation.
max_daily_loss_usdDecimalHalts new orders for the rest of the 24h window once cumulative loss crosses this.
max_open_positionsintCap on simultaneous open positions across all venues.
max_concentration_pctfloat (0–1)Max share of portfolio any one position can hold.
max_orders_per_minuteintToken-bucket rate limit on order placement.

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.
  • RiskViolation is raised.
  • The runtime logs a strategy.risk_violation event 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 ifstatements scattered through your strategy code. Second, it’s consistent across paper and live — the same gate runs in both modes, so you can’t accidentally ship a strategy whose risk only exists in paper.

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

See also