A risk engine is a list of things the bot is not allowed to do
Risk management in a trading bot is not a calculation. It is a set of refusals, enforced in code, that the strategy cannot argue with.
Vizanix engineering · about the author
- SECTION
- Bot architecture
- PUBLISHED
- 2026-08-28
- CHAPTERS
- 6
- READ NEXT
- 3
- LANGUAGE
- written in English
Strategies are optimistic by construction — they exist to find reasons to trade. The risk engine exists to say no. If those two live in the same code, the optimism wins, because the person writing the strategy is the one under pressure to make it perform.
Refusals, not adjustments
A risk engine evaluates an intent and returns approved, resized, or rejected — with a reason recorded either way. It does not politely suggest. The execution layer obeys it, and there is no path from strategy code to the exchange that bypasses it.
@dataclass
class Verdict:
approved: bool
qty: Decimal # may be smaller than requested
reason: str # always populated, including on approval
def evaluate(intent, portfolio, day) -> Verdict:
for rule in RULES: # order matters: cheapest and hardest first
v = rule(intent, portfolio, day)
if not v.approved:
return v
return Verdict(True, intent.qty, "ok")The rules that earn their place
| Rule | Enforces | Typical failure it prevents |
|---|---|---|
| Max position per symbol | Notional cap per instrument | One signal repeatedly firing into an enormous position |
| Max total exposure | Gross and net across the book | Ten uncorrelated-looking symbols that are all beta to BTC |
| Concurrent position count | Slot limit | A regime change opening everything at once |
| Daily loss limit | Realised plus unrealised, since session open | A bad day compounding into a catastrophic one |
| Drawdown stop | Peak-to-current equity | Slow bleed nobody noticed |
| Leverage cap | Hard ceiling below the venue's | Effective leverage drifting up as equity falls |
| Liquidation distance | Minimum buffer per position | The venue closing the position for you, at its price |
| Loss streak per symbol | Auto-blacklist after N losses | One instrument the strategy has stopped understanding |
That last one is worth implementing even though it feels crude. Our signal engine tracks a loss streak per symbol and blacklists automatically. Sometimes an instrument changes character — a listing matures, liquidity moves, a market maker leaves — and the strategy is simply wrong about it now. Counting is a cheap proxy for noticing.
Positions correlate, and the risk engine must know
The most common quiet failure: five positions each risking one percent, described as five percent of risk. In a correlated market they are one position risking five percent, and they will hit their stops within the same minute.
You do not need a full covariance matrix to improve on this. A crude grouping — majors, alts, anything that moves with BTC — with a per-group exposure cap catches most of the damage. Our risk calculator makes the arithmetic visible: simultaneous risk against a daily limit, which is the comparison people skip.
The kill switch must be dumb
Every risk engine needs a single action that cancels all orders and flattens all positions, and it must be the simplest code in the system. No strategy consultation, no clever unwinding, no waiting for a better price.
Requirements that sound obvious and are frequently violated:
- It runs at the highest request priority — cancels go out before anything else.
- It is reachable manually, from the control plane, in one command.
- It is idempotent. Triggering it twice does nothing the second time.
- It works when the strategy layer is hung, because it does not call into it.
- It is tested. A kill switch nobody has fired is a hypothesis.
Unrealised counts
A daily loss limit that only counts closed trades can be satisfied while the account is deeply underwater in open positions. Count realised and unrealised together, marked to the current price, and re-evaluate on every position update rather than on a timer.
Every refusal gets logged
A risk engine that silently declines is indistinguishable from a broken strategy. Record the intent, the rule that rejected it and the state at the time. This is the same discipline as recording why a signal did not fire — it turns “the bot did nothing today” from a worry into a query.
It also produces the evidence for tuning. Limits that never bind are decoration; limits that bind constantly are miscalibrated or are telling you the strategy wants more risk than you agreed to give it. Both are worth knowing.
This article describes engineering practice. It is not investment advice. Vizanix develops software and does not promise trading returns.