Global settings
Every AI Market Maker setting — the four global switches, the concurrency cap that is not what its label says, the risk limits, history retention and the one environment variable — with what each actually gates.
Global settings live at /admin/ai/market-maker/settings, behind
access.ai.market_maker.settings. They are stored in the platform's central
settings table and saved through the shared settings endpoint, so a change
invalidates the settings cache and reaches every process without a restart.
Four tabs: Trading, Bots, Risk and Emergency.
The platform stores every setting as a string. false is the string "false",
which is truthy in JavaScript. All four global switches on this screen once
compared against a true/false value and could therefore never match whichever way
they were flipped — Enable AI Trading, Global Pause, Maintenance Mode
and Enable Stop Loss all read as working controls and had no effect on
anything.
They work now, and accept every form the settings screen and the API actually
produce: true/false, on/off, yes/no, 1/0. If you are on a build
before v6.1.5, do not rely on any of them.
Trading
Enable AI Trading is read by the engine and by every scheduled job. With it off, the risk monitor and the price sync skip their passes entirely.
Global Pause and Maintenance Mode suppress trading only. Prices and charts keep advancing, and nothing jumps when the pause is lifted.
Halting the engine outright would freeze every market's price, flatten every chart, and produce a visible gap the moment the pause ended. Suppressing trades while the price process keeps running avoids that. Nobody ever saw a frozen chart from this, because none of the global gates could fire before they were fixed — this is the companion change that makes turning them on safe.
Trade History Retention governs processAiHistoryRetention. This is the
addon's largest table by a wide margin: a MODERATE market writes about 3,500 rows
a day and an AGGRESSIVE one about 9,000. 0 keeps everything. Anything below 2
is treated as 2, because the daily summariser reads yesterday's trades. Daily
summaries and lifecycle audit rows are never pruned.
Bots
The engine reads it into maxConcurrentMarkets. The market manager refuses to
load a market once that many are already running, logs "Max concurrent markets
reached", and returns a failed start. The label on the screen is wrong; the
behaviour is what matters.
The symptom is specific and easy to misread: markets that will not start, with no error on the admin screen, and a dashboard alert saying the engine holds fewer markets than the database says are ACTIVE. Accepted range is 1–500; the engine falls back to 50 if the setting is unreadable.
Risk
Minimum Liquidity is checked twice — by the status endpoint when you press Start, and again by the engine when it loads the market. Both compare it against the pool's quote balance, not its TVL. A market that passes the first check and fails the second fails to start with the reason in the log and nothing on screen.
Max Daily Loss (0–25%) is the platform-wide limit. Breaching it trips the circuit breaker, which gates every market at once. A single market that loses more than its own limit is paused on its own; only a book-wide loss halts everything. See Risk and emergency controls.
Volatility Threshold (0–50%) is the fallback for a market that has not set
its own volatilityThreshold. It is a measured daily percentage, computed from
the engine's own published price on every tick and scaled using the real spacing
between samples.
Before v6.1.5 volatility was only ever sampled inside the branch handling a successful external exchange price — a path an autonomous market never reaches. Two features read that number and both were therefore inert: the high-volatility auto-pause, which never ran once, and the spread quoted on real-liquidity orders, which was pinned at its minimum no matter how violently the price moved.
Emergency
The Emergency tab hosts the fleet-wide stop. It is documented in full on Risk and emergency controls.
The dashboard's emergency stop requires a written reason and stores it on every market's history entry. The panel on this screen still posts without one, so a stop triggered from here records the fallback sentence "Emergency stop triggered by admin". Use the dashboard's button if you want the record.
Per-market settings
These are not on this screen. They live on each market's Configuration tab and are documented in Creating and configuring a market:
| Setting | Range | Gate it feeds |
|---|---|---|
targetPrice |
Inside the price range | Steering |
priceRangeLow / priceRangeHigh |
At most 50% either side of target | Containment |
aggressionLevel |
CONSERVATIVE, MODERATE, AGGRESSIVE |
Bot seeding only |
maxDailyVolume |
0 or more | Hard trade gate |
volatilityThreshold |
0–100 | Hard trade gate, when the pause is on |
pauseOnHighVolatility |
on/off | Enables that gate |
realLiquidityPercent |
0–100 | Whether real orders are placed at all |
priceMode + externalSymbol + correlationStrength |
— | External tether |
marketBias + biasStrength |
0–100 | Phase transitions |
baseVolatility / volatilityMultiplier / momentumDecay |
0.1–20 / 0.5–2.0 / 0.8–0.999 | Price process |
The environment variable
A market that reaches the ceiling stops placing new real orders until existing ones fill or expire, and says so once in the log. It refuses to place rather than force-cancelling the oldest quote: cancelling mid-tick races the matching engine's settlement, and a maker sitting at its ceiling is something you should see rather than have quietly worked around.
500 is generous — a maker showing depth at 20 levels a side needs 40 — and small
enough that hitting it is unmistakably a leak rather than a busy market. A market
can carry its own maxRestingRealOrders; the environment variable is the blunt
instrument for moving every market at once during an incident.
Before v6.1.5 every print appended a new resting LIMIT order to the real Ecosystem book and nothing reliably removed the previous one — no refresh cycle, no cancel-before-replace, no cap. One live market reached 704,353 open orders. The backend loads open orders at startup, so that one market made the API take minutes to bind its port: the site served connection refused while the log filled with successful startup messages.
Orders accumulated before the fix do not disappear on update. Clean them with
pnpm eco:mm:orders:clean.
What is not configurable
- The engine tick interval is fixed at 1 second. Trade cadence is driven by the bots' daily budgets and the intraday activity curve, so changing the tick rate could not change how often a market trades even if you could reach it.
- Bot personalities are seeded and cannot be changed.
- The two-bot minimum is a constant in the engine.
- The 20% band edge where containment engages is a constant in the price process.