Operations
Risk controls for autonomous trading agents
You don't hope an autonomous agent respects risk limits. You enforce them. How polybot's risk service works, and the defence-in-depth design that keeps agents honest.
Published Apr 16, 2026
Every serious failure of “AI trading” in the public record has the same shape: the model did something unhinged, and the system had no gate to stop it. Not a model-quality problem. An architecture problem. polybot’s risk service is designed assuming the agent is adversarial — not because it is, but because that assumption produces better invariants.
Three layers
polybot enforces risk in three places:
- Pre-submission checks. Every
Signalis validated against global and strategy-local limits before it becomes an order. - In-flight monitoring. While orders are working, exposure is recalculated and limits re-checked on every fill.
- Post-fill invariants. Reconciliation runs on a schedule and triggers auto-halts if the on-venue state disagrees with the local model.
Layers 1 and 2 are preventive. Layer 3 is the tripwire.
Pre-submission checks
Before a signal becomes an order, the risk service validates:
| Check | Default |
|---|---|
| Per-market position cap (USD) | $500 |
| Per-category exposure cap | $2,000 |
| Per-venue exposure cap | $5,000 |
| Global net exposure cap | $10,000 |
| Per-strategy daily loss stop | $300 |
| Global daily loss stop | $1,000 |
| Cooldown after loss stop trigger | 24h |
| Max concurrent positions per strategy | 20 |
| Max USD per single order | $1,000 |
All of these are configurable. Defaults are conservative so new operators don’t blow up on day one.
polybot risk show
polybot risk set --per-market-usd 300 --global-net-usd 8000
polybot risk show --strategy momentum # per-strategy overrides
The risk service subscribes to the signal stream via NNG. Strategies can’t bypass it — there is no direct path from strategy to executor.
In-flight monitoring
Orders can take seconds to fill on Polymarket (on-chain latency) and milliseconds on Kalshi. Between submission and fill, market conditions change. The in-flight monitor:
- Tracks working orders per strategy.
- Recomputes exposure including partial fills.
- Cancels working orders if a limit is breached mid-fill.
This is the reason polybot uses async services instead of a monolithic strategy runner — the risk service operates on a separate event loop and can always act on the exchange, regardless of what the strategy is doing.
Post-fill reconciliation
Every 60 seconds, the reconciler fetches canonical state from each venue (positions, balances) and diffs against the local model. Disagreements fall into three buckets:
- Expected drift (fills not yet propagated): no action.
- Small drift (< 0.1% notional): logged, monitored.
- Large drift or persistent small drift: auto-halt. New orders are rejected; existing positions are reported; operator must manually
polybot reconcile resume.
Reconciliation is paranoid by design. A silent disagreement between your local position state and the venue’s state is how losses compound unnoticed.
Agent-specific controls
When the MCP server is enabled, two more gates kick in:
Approval gates on place_order
In live mode, the MCP place_order tool doesn’t submit directly. It creates an approval request, optionally routing through:
- Inline prompt — operator accepts/rejects via CLI.
- Pre-authorised thresholds — orders under $100 auto-approve in specific markets.
- Callback webhook — an approval UI you host.
polybot mcp approve --threshold 100 --strategy ai_model --markets "politics"
polybot mcp audit approvals --pending
No pre-auth is transitive: if you approve $100 autos in ai_model, momentum doesn’t inherit it.
Token budgets
Agents that call LLM-backed tools can burn tokens. polybot’s risk service tracks token spend per MCP client and enforces per-day caps.
polybot mcp budget set --client claude --usd-per-day 5.00
Exceeded budget: tool calls from that client return a structured BudgetExceededError. No silent failures.
What polybot explicitly does not defend
Honest list:
- Venue outages. If Polymarket’s API is down, polybot sees that, halts new orders on that venue, and reports. It can’t magic in liquidity.
- Resolution disputes. If a market resolves ambiguously, your position marks correctly but may take days to settle. polybot’s P&L reflects the uncertainty; it doesn’t eliminate it.
- Model risk in strategies themselves. If your
ai_modelcalibration is off by 20%, you’ll lose money within the risk limits. Shadow mode catches this; the risk service doesn’t. - You overriding your own limits.
polybot risk set --global-net-usd 100000will work. The platform trusts the operator.
Lessons from the design
- Checks happen in one place. There is a single risk service. Strategies don’t check limits themselves; they just emit signals. This is the hardest rule to keep as the codebase grows — and the most valuable.
- Halts are loud. When the risk service halts a strategy, it logs at ERROR, posts to the event stream, and (if configured) emits a webhook. Silent halts are the worst kind.
- The operator is always the final authority. Pre-auth is an escape valve for speed, not a permanent bypass. Every pre-auth has a TTL.
- Agents are first-class, not second-class. MCP callers hit the same risk gates as human-invoked CLI commands. No “agent exception”.
If you’re building an autonomous agent platform — for trading or anything else — steal this layout. A single risk service, orthogonal to the strategy/agent logic, treating all actors (human, agent, automation) uniformly. That’s the shape.
Need an agent system built like this?
Cryptuon builds production AI agents, MCP integrations, and trading systems. polybot is our open-source showcase.