AI Market Maker 6.2.4
2 September 2026
This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.
AI Market Maker v6.2.4
Release Date: September 2, 2026 Tags: MARKET-MAKING, PRICE-MODE, LIQUIDITY, RISK, FEES, ADMIN, DOCUMENTATION, BUG-FIXES
Overview
A market set to follow an exchange now actually follows it.
Until this release it could not, and the reason was structural rather than a bug in the tether. The containment band was pinned to the market's target price, and the leash that holds price inside that band is built to out-pull the tether two to one — six daily volatilities per day against three. A reference price outside the band was therefore not slow to reach, it was unreachable: the price settled at the edge of the band and stayed there while the exchange moved on without it. Raising correlation strength did not help, because the leash wins at any strength.
The band travels with the reference now. It is re-centred on the reference price at the width you configured, so the reference sits at its middle and the leash stops opposing the tether. The tether itself was left exactly as it was — strengthening it would have traded a visible failure for an invisible one, since its cap is what stops a mis-mapped symbol dragging a market anywhere it likes.
To be precise about what that buys: it makes a reference reachable at any distance, which it previously was not at any correlation strength. It does not make the market a mirror, and it is not fast. The leash is dormant through the inner four-fifths of the band, so once the price is inside, convergence is the tether alone — a drift that closes half of any remaining gap in about 33 hours at the shipped correlation of 50, 17 at 100, and 66 on Hybrid, which halves the strength again. The reference behind it is a 15-second cached poll, so even a perfectly tracking market is working from a price that may be a quarter of a minute old.
Raise correlation strength if you want it faster. That is now a decision with a real effect, which it was not before — at any strength the price used to park in the same place.
Two things had to change with it, and both were failures waiting to happen the moment tracking started working:
- The volatility auto-pause would have killed every well-tracking market. A market
following a 12%/day asset realises 12%/day, trips a threshold that ships at 5%, and
HIGH_VOLATILITYwas the one auto-pause nothing ever cleared. The better the tracking worked, the more certainly the market paused itself for good. - A market that tracks a public reference is a free option if it quotes too tight. Quotes now widen while the reference is moving.
Separately, and affecting every market that posts real liquidity: a cancelled maker quote was still tradeable. The cancel wrote the terminal status to storage but never removed the order from the matching engine's in-memory queue, and that queue is what the matcher actually fills from — so a quote the engine had retired stayed published as depth, and stayed fillable, for up to an hour. That includes quotes retired precisely because they had gone stale. This is fixed, and it is worth applying whether or not you use Follow external.
And on futures markets, an accounting fix worth reading if you report on revenue: cancelling a maker quote refunded the fee to the pool without taking it off the platform's books, so the treasury reported revenue on money it had given back and the insurance fund reserved against orders that no longer existed. Nothing was out of balance — which is why it went unnoticed — and it scaled with how often the maker re-quoted rather than with how much it traded.
Also in this release: the reporting that was missing when a tether was doing nothing, and the documentation corrections behind the original report.
No new platform requirement; unchanged from v6.2.2.
Update Instructions
pnpm updatorRestart the backend afterwards. No database migration and no setting changes.
If you run any market on Follow external or Hybrid, read Upgrade Notes — one setting changes meaning for those markets, and some paused markets will restart.
Upgrade Notes
The price range means something different on a following market
This is the one behaviour change to read carefully.
| Mode | What the price range is |
|---|---|
| Autonomous | Absolute bounds, exactly as before. The price stays inside that box |
| Follow external / Hybrid | A tracking tolerance. The box is re-centred on the reference and travels with it; its width is how far price may stray from the reference |
A following market cannot honour both readings at once — absolute bounds are precisely what stopped it following — and of the two, tolerance is what an operator configuring a tracking market actually wants. The width you configured is preserved, measured geometrically, so a market set to +/-10% of target keeps a +/-10%-shaped band around the reference wherever the reference goes.
The practical inversion: a narrower range now means tighter tracking, not a safer market. Tight tracking against a public reference is the configuration most exposed to arbitrage, because the price is being held close to a figure informed traders can also see. Widening the range makes a following market behave more like its own.
Nothing needs changing for this to work, and no existing market is rewritten. If you previously widened a range specifically so it would contain the reference, you can narrow it again — that is now a tracking-tightness decision rather than a workaround.
A reference that cannot be your asset is now refused
The static band was itself the protection against a mis-mapped external symbol: whatever the feed said, the leash held the price inside the box you configured. A band that travels to meet the reference would have removed exactly that — the leash would stop opposing a wrong price and start helping it.
So the bound moved rather than disappearing. A reference more than ten times away from the market's configured target price — in either direction — is treated as a mapping mistake rather than a market that moved, the tether switches off, and the static configured range holds. TRX at 0.32 pointed at a BTC feed is a factor of 200,000; an asset that genuinely tripled is still followed normally.
The Configuration tab names this case specifically, because unlike the others it is a concrete mistake with a concrete fix: the external symbol is not the pair you meant.
Markets paused for high volatility will resume on their own
HIGH_VOLATILITY auto-pauses were never cleared by anything; only daily-loss pauses
resumed. Two ways out now, both self-gating:
- A following market is released outright, because the absolute-volatility guard no longer applies to it. This is also the migration path for markets already stuck.
- Any other market resumes once measured volatility has fallen back to 80% of its threshold. If it climbs again the risk monitor re-pauses it; the gap between the two figures is what stops them flapping.
A market you paused yourself is never touched. The resume only acts where the most recent status decision was the automatic pause itself.
Following markets are no longer paused for absolute volatility
For Follow external and Hybrid, the risk monitor now measures tracking error — whether the price has come adrift from the reference — instead of how far the price moved. Tracking error is a real fault signal for these markets; absolute volatility is just a restatement of how lively the tracked asset is.
That guard alerts and does not pause. The money guard for these markets is the daily-loss limit, which is unchanged and still pauses.
Changed
Quotes on a following market are priced over the life of the quote
A resting quote is a free option written to anyone who can see the reference feed, and its premium has to cover how far that reference travels before the quote is repriced. The maker stated that principle and then charged the wrong interval for it: the reference is sampled every 15 seconds, the quote rests for an hour, and nothing reprices it in between. Because a price move grows with the square root of time, that underwrote the option by a factor of about fifteen.
- Added a reference premium on following markets, scaled from the observed move to the quote's full resting life. At ordinary volatility this is a sub-1% spread, not a wide one — a 2%/day market moves about 0.026% in fifteen seconds and about 0.41% in an hour.
- Capped at 3%, and the engine now says so when the cap binds. That is the signal that a quote cannot be priced honestly at its current life: the answer is repricing it faster, not widening it further, because nobody trades a 3% spread. Until that exists, the log names the market and suggests reducing its real liquidity.
- Autonomous markets are unaffected — the premium is zero for them, because nobody can forecast a synthetic price and so a quote on one is not an option anyone can exercise.
The Configuration tab reports what the tether is doing
- Added the live reference price beside the price-mode controls. A tether receiving nothing was previously indistinguishable from one that was working: every failure path returns no price and logs at debug level, while the badge kept reading Follow external.
- Added the current tracking error, and a warning when the price has come adrift from the band it should be tracking within.
- Added the tether's half-life beside the correlation slider. It closes half of any remaining gap in about 17 hours at 100% strength and 33 at the default of 50 — moving the band is what makes the reference reachable, this is how fast the price crosses what is left.
- Changed the correlation strength control, which shipped with no explanation at all, to state what it sets: how fast the market converges, not how close it ends up.
- Added the price-range adequacy reading to the market record and the tab. The engine has always calculated it and written it to the server log, where no operator would meet it.
- Added the tracking verdict to the market's own history whenever a price mode is saved, so a later investigation can tell a market that was misconfigured from the moment it was tethered from one whose reference drifted afterwards.
An external symbol your provider does not list is refused
The external symbol was free text that nothing checked, so a typo — or a pair your active provider does not carry — was accepted, stored, and then failed forever without a message.
- If your provider cannot be reached when you save, the symbol is accepted as before. Only a provider that positively answered with its market list can refuse one, so an offline or unlicensed provider cannot block a configuration change.
- Existing markets are not re-validated. The check applies the next time you save that market's price mode.
Added
Following markets keep their real book stocked
The other half of the five-minute quote life above, and the reason that change is safe to ship. Until now, real quotes reached the order book only as a side effect of the maker's own trades — there was no path that placed one deliberately. Resting real depth was therefore arrival rate times quote life, and cutting the life twelve-fold would have cut the book twelve-fold with nothing to replace it.
A following market now checks every thirty seconds whether its real book has fallen below a floor of three quotes a side, and places what is missing — at most two per check, so a cold start takes a minute and a half rather than arriving as a burst. Ordinary trade flow still builds depth above that floor; this only ever fills a deficit, and asks for nothing once the floor is met.
It is deliberately harder to reach than ordinary trading, never easier. It places nothing unless the market would also have been allowed to trade — two active bots, a funded pool, the daily volume cap, the volatility pause and the global risk gate all apply unchanged — and it carries three more conditions of its own:
- Only markets following an exchange. Autonomous markets keep the full hour, so nothing drained them.
- Only ecosystem markets. A futures quote reserves its margin and pays a fee when it is placed, so its depth was never unreserved and replacing it on a timer would buy reserved depth with real fees.
- Never while quotes cannot be priced honestly. If the reference is moving so fast that the fair premium exceeds the 3% cap, the maker stops topping up and says so, because every quote written in that state is below its value. Depth returns on its own once the reference settles. Ordinary trading still quotes there — that is behaviour you configured; this is the engine acting on its own initiative, and it holds to a higher bar.
It never cancels anything, so it cannot race a fill, and each quote it places is sized like the market's own prints and bounded by the same per-side pool budget as every other quote. A market that wants depth and cannot afford any now says so rather than going quiet — the log names the market and tells you to top up the pool or set real liquidity to zero.
The floor is yours to set. A new Real Depth Floor control on the market's Configuration tab takes 0–20 quotes a side and defaults to 3. Zero is a real setting — real depth then comes only from trade flow, which is what every market did before this release. The control appears only where it does something: an ecosystem market, following an exchange, with real liquidity above zero.
Set it deliberately rather than high. A maker quote on the ecosystem reserves nothing when it is placed — the pool moves only when a customer fills it — so every resting quote is a promise the pool has not yet been asked to keep. That is why the ceiling is 20 and why the per-side pool budget still bounds every individual quote regardless of the floor.
Nothing to enable, and autonomous markets behave exactly as they did.
Import a real exchange's history behind your chart
An ecosystem market's chart is drawn by the market maker from its own trades, so it does not resemble the same pair on Binance or Bybit — the candles form at different times, with different shapes. That is inherent to a synthetic market and no price-mode setting changes it.
The past, though, can be made to match. A new admin endpoint imports a real provider's own historical bars into the market's candle series:
POST /api/admin/ai/market-maker/market/{id}/backfill
{ "intervals": ["1h", "4h", "1d"], "fromMs": 1750000000000 }It defaults to the market's configured External Symbol, so a market already set to follow an exchange needs no arguments at all.
Every write lands strictly behind the history the market already has, and that bound is the whole safety argument rather than a detail. Five separate things read the newest candle of a series — binary option entry and settlement, the market maker's own price on restart, stop-order triggering, wallet P&L, and copy-trading and P2P rate lookups — so an imported bar that became the newest one would be a price that moves money. The importer refuses rather than risks it:
- A market with no candles at all is refused. With no existing history there is nothing to stay behind, so the newest imported bar would become the market's live price. Start the maker (or take one real fill) so a live candle exists, reconcile its price level to the provider's, and import behind it. Importing into a genuinely empty series otherwise shows up as one enormous bridging candle and mispriced binaries.
- The bar currently forming is never written. Both live candle writers only ever touch the current bucket, so a strictly-past import cannot collide with them — which is also why stopping the market maker is neither necessary nor sufficient.
- 3d and 1w cannot be imported. The ecosystem floors 3-day bars from the epoch and starts weeks on Sunday UTC; provider bars for those intervals would land beside your series rather than on it. Import 1d.
- Depth is capped per interval — 30 days of 1-minute bars, 6 months of 5- and 15-minute, years of the rest — because every interval of one market shares a storage partition.
One effect to expect deliberately: trading bots that use indicators will widen their window into the imported history, so bots that were silent on a short series may start signalling on real data.
Fixed
Quotes on a following market now rest for five minutes, not an hour
This is the change that makes a tethered market's spread competitive rather than merely honest.
The premium a resting quote must charge grows with the square root of how long it rests. At an hour, the honest spread on a 2%/day pair is about 0.41% — roughly forty times what the exchange being tracked quotes, which is a market no informed trader touches. At five minutes the same honest premium is about 0.12%.
- Autonomous markets are unchanged and keep the full hour. Nobody can forecast a generated price, so their quotes are not options anyone can exercise, and shortening their life would thin the book for no benefit.
- The expiry and the spread are priced from the same number, so the maker cannot charge for an exposure window it does not actually run.
This has a cost, and it is paid in the same release. Real quotes reach the book only as a side effect of the maker's ordinary trades, so resting real depth is arrival rate times quote life — a twelve-fold shorter life is a twelve-fold thinner real book at any trade rate, and an empty one between trades on a market that trades less often than every five minutes. None of it is visible: the displayed ladder is rewritten every ten seconds regardless, so the chart and the depth widget look identical while nothing a customer sends can fill. Keeping the real book stocked below replaces the depth this removes.
A market set to zero real liquidity can now clean up after itself
Lowering a live market maker's real liquidity to zero is the obvious way to remove pool exposure, and it did the opposite. On the next start the maker only adopted its resting orders when real liquidity was above zero — so the orders it had already placed stayed on the book, tracked by nothing, and permanently beyond the expiry sweep, the stale-quote retirement and the operator's own stop. Setting the exposure knob to zero created exactly the un-retirable quotes that knob exists to prevent.
The maker now adopts whatever it left resting, regardless of the setting.
Stale quotes are retired against the right price, and before they are taken
Two problems, both of which cost the pool money on any market with real liquidity.
The guard was watching the wrong price. It judged a resting quote against the market maker's own generated price. On a market following an exchange that price lags the reference deliberately — the tether is a slow drift — so a quote could be badly stale against the price an arbitrageur is actually trading on while still looking healthy against the maker's own. The guard was pointed at the one price that cannot see the danger. Following markets now judge against the exchange reference.
And it waited until the loss was certain. A quote was retired only once the price had already passed it — by which time it can only be taken at a loss, and on a market anyone can watch it very likely already has been. Quotes are now retired while the reference is still a margin away, sized from how far that reference actually moves between sweeps.
- Autonomous markets are unchanged in both respects. They keep their own price as the reference and a zero margin, because nobody can forecast a generated price and so there is no window to buy back.
- The margin is capped so a violent move widens the guard rather than emptying the book.
- The margin is sized per quote. The bots quote anywhere from 0.01% to 2% out, so a tight quote is hundreds of times more exposed to a reference move than a wide one; a single shared number would be useless for the first or absurd for the second. Each quote now records the distance it was written at, and is retired once most of that edge is gone. Quotes with no recorded distance — anything placed before this release — keep the sweep-wide margin.
An exhausted pool no longer takes the customer's order with it
Read this one even if you do not use Follow external.
A market maker's quote reserves no funds when it is placed — the pool moves only when a customer fills it. So a maker can rest more than its pool holds, and the shortfall is not discovered until a customer's fill tries to settle.
When that happened, the failure was misread as temporary. The pair was retried, and then both orders were set aside — the maker's and the customer's. The pool does not refill itself, so the next cycle did the same thing, and the customer's funds stayed held against an order that could never fill, on a market that otherwise looked healthy.
It is now recognised as what it is: a condition of the maker's own pool. Only the maker's quote is retired, and the customer's order stays in the book to match against the next one.
The pool size ceiling was losing to the size floor
Two holes in the only control that limits how much the pool can be asked to honour, both of which removed the limit exactly where it mattered.
- A ceiling below the minimum order printed the minimum anyway. A pool that could not back even the smallest order still quoted. It now declines to quote instead.
- The ceiling watched the wrong balance. It was measured against the base currency for both sides, so a bid — which spends the quote currency — was limited by nothing relevant, and a pool holding only quote had no limit at all on the side that spends base. Each side is now measured against the currency it actually spends.
- Added a running total: what the maker already has resting is subtracted from the budget before a new quote is sized. Previously each quote was checked on its own, so five hundred individually reasonable quotes could still add up to many times the pool.
Finished order rows no longer accumulate for ever
ai_real_liquidity_orders recorded every real quote the maker ever placed and never
removed any of them. That table is read on every market start, and because it is keyed
by order rather than by market, the read scans the whole table — so the cost of starting a
market grew with the total number of quotes the install had ever placed, across every
market, permanently.
Finished rows — filled and cancelled — now carry a 30-day expiry. The maker's own bot order table gets the same treatment: it is not read at startup, but it is keyed by market, so every order a market ever placed accumulated in a single ever-growing partition.
- Open rows are untouched and never expire. An open tracking row is how an orphaned quote is identified at all, so those are kept indefinitely.
- No action required, and nothing is deleted retroactively; existing rows stay until something updates them. This is not an audit trail — fills are recorded separately in the bot trade history and in the ecosystem's own order records.
Pausing a market could still leave a quote behind it
This is the one that made withdrawing a pool unsafe, and it applies to every market with real liquidity.
Pausing a market sets it to PAUSED and then cancels its resting quotes — and that ordering is deliberate, because PAUSED is the state in which the pool behind those quotes may be withdrawn. The cancel takes a list of what is resting and works through it.
What nothing accounted for was a tick already in flight. The engine reads a market's status once, at the start of its tick, and then does several things that wait — writing price history, saving engine state, fetching the external reference. A pause landing during any of those was seen by nothing: the tick carried on to the end and placed a fresh order, after the cancel had already taken its list. The operator then saw PAUSED, withdrew the pool, and left a live quote with no funds behind it.
Stopping a market was worse. A stopped market is unloaded from the engine, so a quote placed in that same window belonged to nothing: no expiry sweep reached it, and an ecosystem order has no expiry of its own. It rested indefinitely.
The status is now re-read immediately before each order is placed, on both paths.
- The window was always narrow — the pause had to land inside an in-flight tick — and on a paused market the quote was retired by the ordinary expiry sweep within the hour. Only the stopped case was open-ended.
- Existing orphaned orders are not affected by this; use
pnpm eco:mm:orders:cleanto find and cancel them. This stops new ones being created.
Depositing or withdrawing pool funds now reaches the running market
A running market keeps its pool balances as a snapshot taken when it started. Only two things refreshed that snapshot: the midnight-UTC daily reset, and the eight admin configuration screens. A pool deposit or withdrawal was neither.
So the documented sequence for changing a pool — pause the market, move the funds, resume — left the market running on the balances it had before. Every guard that decides whether the maker may risk money reads that snapshot: whether there is a pool at all, and how large a quote each side can back. After a withdrawal all of them were reading a figure that was no longer true, for as long as a day.
An ecosystem quote reserves nothing when it is placed, so the shortfall was not discovered until a real customer's order tried to settle against a pool that had been emptied.
Both pool routes now push the new balances into the running market, exactly as the configuration screens do. Adding funds takes effect immediately too, rather than at midnight.
A dead price feed silently disabled the stale-quote guard
When an exchange provider stops answering, the market maker deliberately keeps using the last reference price it received rather than dropping the tether — a brief outage should not snap a following market back to its own band. But nothing distinguished holding the last price from receiving one, and two things quietly depended on the difference.
The stale-quote guard compares every resting quote against the reference. Against a frozen number, every quote looks healthy for as long as the feed stays down, while the real market walks away from all of them — the guard reporting all-clear at exactly the moment it is needed. And the spread widens with recent reference movement, which decays to nothing when no new prices arrive, so quotes were also written at their tightest.
- Fixed the stale-quote guard falling back to the market's own price when the reference has not been refreshed for a minute. That is the behaviour it had before a reference was introduced, so a dead feed now degrades to the old guard rather than to none.
- Fixed the depth top-up continuing against a frozen reference. It stops and names the provider instead.
- The tether itself is unchanged and still rides out an outage. Dropping it on a blip would snap the price back toward its configured band, which is a larger and more visible fault than drifting toward a slightly old number.
A market's own resting-order ceiling was read but never loaded
The limit on how many real orders one market may leave resting has three sources: the
market's own value, the AI_MM_MAX_RESTING_REAL_ORDERS environment variable, then 500.
The engine read the first of those, the settings and troubleshooting pages both described
it as a per-market setting — and nothing ever loaded it from the database.
So every market on every install resolved through the environment variable or the default, whatever its own value said. An operator following the troubleshooting page set it, saw no change, and had no way to tell a knob that turns nothing from a ceiling working as intended: the two look identical from outside.
- The per-market value now takes effect, and wins over the environment variable. A market without one still falls through to the variable, so the incident lever is unchanged for every market that has not been configured individually.
- Set through the admin API rather than the Configuration tab. It is a fault threshold
— reaching it means quotes are not being cancelled — and raising it is how a real leak
gets hidden, so it is deliberately not one click away. 50 to 10000, or
nullfor the default. The change is recorded in the market's history. - Nothing changes for an existing market unless it already carried a value that was being ignored. If you set one before this release and saw no effect, it applies now.
A market never learned what its pool actually held
Every market with real liquidity, not only following ones.
A running market keeps its pool balances as a snapshot, and customer fills settle against the database row without telling it. So the figure the maker used to decide how large a quote it could back only ever went stale in one direction — and the error compounded rather than settling, because retiring a filled quote also removed it from the "already committed" subtraction, returning the market to the full stale balance after every fill.
A pool that opened the day at 10 BTC and was down to 0.03 by evening still reported 10 to every guard. The consequence lands on a customer: their order fails to settle against a pool that cannot cover it.
The balance was in fact being read correctly from the database every minute — for the P&L and pool statistics screens — and simply never reached the part of the engine that spends it. It does now.
- The reconciliation runs on the existing minute cadence and adds no new database queries; it connects a read that was already happening.
- Paused markets are updated too, so a market resumed after a pool change starts on the right figure.
- An unreadable balance leaves the previous one in place. A database blip must not read as an empty pool and silently stop a market quoting.
Cancelling a futures quote reported the fee as revenue
Futures markets only, and it affects your accounts rather than anyone's balance.
When the maker places a futures quote it pays a fee: the money leaves the pool wallet, the platform's treasury is credited the whole of it, and a slice is moved into the insurance fund. Cancelling that quote refunded the pool — correctly, including the fee — and then stopped. The treasury kept the fee and the fund kept the slice.
Nothing was ever out of balance, which is why it went unnoticed: every wallet was internally consistent and every ledger row had a counterparty. What it produced was revenue on money that had been given back. Admin → Finance → Profit counted the fee on quotes that never traded, and the insurance fund carried a reserve against orders that no longer existed.
It scaled with quote turnover, not with trading — a maker that cancels and re-places all day booked fee revenue all day without a single fill — so the five-minute quote life above would have multiplied it by twelve had it shipped alone.
A cancel now performs all three movements: the margin back to the pool, the slice back out of the fund, and the fee off the treasury, in that order. Partly-filled quotes are handled proportionally — the platform keeps exactly the fee on the part that traded. This is the same reversal the user-facing cancel and the futures refund path have always done; the maker's own cancel was the one copy that omitted it.
- Ecosystem markets are unaffected. No fee is taken when a maker quote is placed there.
- No action required, and nothing is restated retroactively. Past reports keep the figures they were generated with; this stops new ones being overstated.
And the reversal now survives a restart. This applies to every futures cancel — a trader's own, the engine's, and the maker's — not only to the market maker.
A cancel refunds the trader in one step and adjusts the platform's books in the next. Those were separate commits, so a process stopped in between left the trader paid and the fee still counted as revenue, with nothing to finish the job: the order is already cancelled, and every cancel path refuses a second attempt before it reaches the money. A deploy, a restart, or a crash at the wrong moment was enough.
The cancel now records what it still owes in the same commit as the refund, and completes it immediately. A new five-minutely maintenance job, Finish Interrupted Cancel Bookkeeping, completes anything a stopped process left behind.
- On a healthy install this job does nothing, and that is the expected reading. A non-zero settled count means a restart caught a cancel mid-way.
- It confirms the refund actually reached the trader before it adjusts the treasury. A reversal booked for a refund that never happened would understate revenue by exactly as much as the missing one overstated it, so a record it cannot confirm is set aside rather than acted on.
- A reversal that keeps failing stays in the queue rather than being cleared. It is
visible in
futures_fee_reversal, and the job warns while any remain.
A cancelled maker quote stayed tradeable for up to an hour
This one is not about following an exchange, and it applies to every market with real liquidity enabled.
The maker's cancel wrote the order's terminal status to storage and stopped there. The matching engine does not build its book from storage — it matches from an in-memory queue that it prunes on a status field only a fill ever changes. So a cancelled quote stayed in that queue, stayed published as depth, and stayed fillable until an hourly audit or a process restart happened to rebuild it.
Every retirement path ran through it: the expiry sweep, the operator's own stop, and the stale-quote retirement. That last one is the sharp end — the engine retires a quote specifically because it has drifted to the wrong side of the market and can now only be taken at a loss, and then left it there to be taken.
- Fixed the engine's cancel not removing the order from the matching queue. The eviction runs after the terminal status is written, which is the same order the customer-facing cancel uses, and it is best-effort — a process with no live engine cannot turn a completed cancel into a failed one.
- No action required. Existing stale rows are cleared by the audit and by restart as before; this stops new ones being created.
Documentation
The interaction behind the original report was documented, correctly, on a page nothing linked to, while every route an operator was actually given omitted it.
- Fixed the guide to Following an external price not being linked from the add-on's start page or from the create-a-market guide.
- Fixed a statement in that guide that the target price is independent of the tether.
- Fixed the same guide describing correlation strength as "how closely to follow", contradicting its own later explanation that it sets convergence speed.
- Added a troubleshooting entry for a market that will not follow the exchange it is set to track.
- Fixed the risk-and-emergency page describing the volatility auto-pause as permanent, and not mentioning that following markets are exempt from it.
- Updated all of the above for the travelling band, including what the price range now means in each mode.
A note on what this feature is and is not
Following an external price makes a synthetic market track a real one. It is now genuinely capable of that, which it was not before. It is still not a mirror: every candle is written by the price engine from the market's own trades, and the tether is a restoring drift rather than an assignment — there is no code path that sets the price to the external price.
Tracking accuracy and pool P&L also trade off against each other, permanently. The
closer a market follows a public reference while the house is the counterparty, the more
it pays traders who watch both. That is a property of the arrangement rather than
something an implementation can remove — real market makers pay it too, and price it
into their spread, which is what the reference-move component above is doing. Set the
tracking tolerance deliberately, and treat realLiquidityPercent as the dial that
decides how much of that cost you are exposed to.