Risk and emergency controls
Every automatic brake in the addon — the four trade gates, the volatility and loss auto-pauses, the error pause, the circuit breaker — and the fleet-wide emergency stop, what it actually halts and how to come back from it.
There are five layers between a misconfigured market and a bad day: the four hard trade gates, the two automatic pauses, the error pause, the circuit breaker, and the emergency stop. This page is what each one actually does, in the order they fire.
The trade-level risk layer existed in full — a per-trade assessment, a per-market loss limit, a global circuit breaker, a volatility-proportional reduction in trade size — and nothing called any of it. The risk level and global loss percentage shown to operators were not measurements of anything. Separately, a market's Max Daily Loss compared against a daily P&L figure that no part of the platform ever wrote, so it was always exactly zero and the limit was never reached however badly a market performed. Update before you rely on any limit on this page.
Layer 1 — the four hard trade gates
Checked on every tick, before the bot layer is consulted at all. Failing any one of them means the market prints nothing while keeping its status.
| Gate | Condition | Visible on the dashboard |
|---|---|---|
| Bots | Fewer than 2 ACTIVE bots | Yes — "needs active bots" |
| Pool | Real liquidity above 0% and TVL at or below 0 | Yes — "unfunded pool" |
| Budget | currentDailyVolume at or above maxDailyVolume |
Yes — "daily budget spent" |
| Volatility | Measured volatility above volatilityThreshold, when pauseOnHighVolatility is on |
No |
The volatility gate is evaluated from price history held in the engine's memory,
which no query can reach — so the dashboard does not claim a market passes it.
The log carries the reason instead, throttled to once a minute:
High volatility (x.xx%), skipping SYMBOL.
Every non-trading path publishes a price heartbeat, so the chart stays continuous and the order book keeps showing depth while a market is quiet, over its budget, volatility-guarded or globally paused. A heartbeat carries no volume and consumes no allowance.
Layer 2 — the automatic pauses
processAiRiskMonitor runs every 10 seconds over every ACTIVE and PAUSED market.
It skips entirely when aiMarketMakerEnabled is off.
High volatility. If pauseOnHighVolatility is on and measured volatility
exceeds the market's volatilityThreshold — or the global
aiMarketMakerDefaultVolatilityThreshold where the market has none — an ACTIVE
market is auto-paused and an alert is raised.
Daily loss. The market's daily P&L is measured against its TVL. If the loss
exceeds aiMarketMakerMaxDailyLossPercent, the market is auto-paused on its own.
Inactivity. A market that has not traded for over an hour raises an alert without pausing anything. Bot cadence is configurable, so on a slow market this is information, not a verdict.
Daily loss is measured from each bot's running realised total against a baseline taken at UTC midnight, and only fills against real users produce a profit or loss — so adding or removing a bot cannot fabricate one.
A market paused by loss protection resumes the next day. A pause an operator applied is never auto-resumed: the resume job reads the recent history rather than a single record, and stops on any later decision.
Layer 3 — the error pause
A market that fails repeatedly pauses itself. It clears the run on every successful price step and retries on its own after about a minute, with backoff.
A market kept a count of every error it had ever had, never reset. Ten transient failures — spread across a day, a week or six months — put it into an error pause it could never leave: the engine had stopped it while the database still said ACTIVE, and activating an already-active market is refused. Because withdrawals and rebalancing both refuse an ACTIVE market, the pool was locked with no way to reach it from the admin panel at all.
Layer 4 — the circuit breaker
Platform-wide. It trips when the book-wide daily loss exceeds
aiMarketMakerMaxDailyLossPercent, gates every market at once, and auto-resets
after a 30-minute cooldown. It also clears itself at the next UTC midnight.
An operator who has resolved the cause can clear it sooner:
The response tells you three things rather than reporting a bare success: whether the engine was running at all, whether the breaker was actually tripped, and why. Those distinctions matter — a silent success would read as "cleared" to an operator whose markets are halted for an entirely different reason.
Trading resumes on the next tick and the daily loss counter is untouched, so it can trip again immediately if losses continue. There is no button for this in the admin panel; it is available through the API only.
An earlier build tripped the global breaker on five consecutive losses, gating every market on one market's bad run. A market that loses more than its own limit is now paused on its own, and only a book-wide loss halts everything. The global loss percentage was also a currency amount divided by 100 and labelled a percent; it is a real percentage of capital now.
Layer 5 — the emergency stop
The button is on the dashboard, and on the settings screen's Emergency tab. Use the dashboard's.
What it does, in order:
-
Marks every market STOPPED — every market that is not already stopped, which is ACTIVE plus PAUSED. The confirmation names that count before it runs, along with the bot count.
-
Pauses every bot.
-
Flips the global switches —
aiMarketMakerGlobalPauseEnabledto on andaiMarketMakerEnabledto off. -
Writes an
EMERGENCY_STOPhistory entry on every market, carrying the reason you typed. -
Commits. Everything above is one transaction, and it commits before anything below runs. The recorded stop is the safety action and must never be rolled back by a failure in the machinery that carries it out.
-
Halts the running engine. Best-effort, after the commit.
-
Cancels open orders, unless you pass
cancelOpenOrders: false. It cancels the bots' open ecosystem orders through the matching engine and clears their AI-side order rows. If the Ecosystem extension is unavailable this step is skipped without failing the stop.
Before v6.1.5 steps 1 to 4 were the whole action. The global switch suppresses trades and nothing else, so every market kept advancing its price, kept writing candles, and kept republishing its synthetic order book. The only things that changed were a status badge and a gate.
It also counted only ACTIVE markets while stopping everything, so a stop that halted a dozen paused markets reported "0 markets stopped" and recorded no history for them.
The reason is now required, and your old rows do not have one
The dashboard's confirmation asks for a written reason and will not run without it. The endpoint has always accepted one and has always written it onto each market's history entry — but the button posted an empty request, so every emergency-stop entry already in your history reads "Emergency stop triggered by admin", regardless of what happened, who decided it, or why. Those rows cannot be reconstructed.
The panel on the settings screen still posts without a reason. A stop triggered from there still records the fallback sentence.
Coming back
Recovery is deliberate, and it is manual:
-
Fix the cause. The history entries name the markets and the reason.
-
Turn the global switches back —
aiMarketMakerEnabledon,aiMarketMakerGlobalPauseEnabledoff, on the settings screen. Nothing restores them for you. -
Start each market again from its detail screen. Every market was written to STOPPED, so each one needs a START — which re-runs the funding and minimum liquidity checks.
-
Check the dashboard's quoting meter, not the status column, to confirm they came back.
Recovery works on the first start rather than depending on a later scheduled pass happening to notice.
Trade-level risk
Below all of this, a risk assessment runs before every trade: it rejects extreme volatility outright and scales trade size down in proportion to measured volatility. A failure to assess does not block trading — the assessment is an extra safeguard on top of the four gates, not a precondition for correctness.
aiMarketMakerStopLossEnabled gates the automatic stop-loss on trades. Like the
other three global switches it was inert before v6.1.5.
What has no automatic brake
- Inventory skew. Nothing pauses a market for becoming lopsided. Watch it on the dashboard and rebalance deliberately — see Funding the pool.
- A predictable configuration. Following an external price closely, or a price range too narrow for the configured volatility, makes a market readable by anyone watching it. Both are legitimate choices and both are warned about in the server log only, with the percentage edge an observer would hold. Nothing about them appears in the admin panel.
- Two engines driving one market. Leadership is arbitrated by Redis and a database lease, but if neither is reachable the claim fails open. See Install and enable.