ADAMANT Market-making bot: A Safer, Smarter Spread Support
0
0
Spread Support liquidity orders have always been one of the more powerful parts of the ADAMANT Market-Making Bot — and also one of the most delicate.
They help keep spreads tight, make books look healthier, and improve tradability. But that strength comes with a challenge: if the logic is too naive, Spread Support can become exploitable. Refill loops can keep recreating exposure, volatile conditions can distort placement decisions, and one-sided market moves can turn a useful liquidity mechanism into a source of avoidable risk.
This update addresses that problem with a substantial three-phase upgrade. It introduces a dedicated simulation tool, separates Spread Support and Safe Liquidity into optional submodules, and replaces the old repeatable refill logic with a bounded mirror strategy designed to preserve tight spreads without opening unlimited loss loops.

The result is a more testable, more modular, and much safer liquidity system inside the Premium version of the ADAMANT Market-Making Bot.
Premium mm bot: https://marketmaking.app/
The “Liquidity SS Upgrade” issue overview: https://github.com/Adamant-im/adamant-tradebot/issues/100
Why this upgrade matters
Liquidity logic should do more than place orders. It should also behave predictably under stress.
That is especially true for Spread Support (SS). Unlike depth-based liquidity, which naturally respects average buy and sell prices, SS orders exist to support the spread itself. That means they can be much more sensitive to hostile fills, sudden directional moves, or placement rules that make sense in calm conditions but break down in volatile ones.
This release focuses on that exact boundary: how to keep Spread Support useful without letting it become an open-ended risk source.
Phase 1: a simulation and visualization tool for SS behavior
Before changing core logic, we built a dedicated standalone tool to inspect Spread Support behavior in a controlled environment.
The new harness consists of:
- trade/tests/liquidity_test.js
- trade/tests/liquidity_test.html
It runs as a standalone Express + Socket.io application and gives operators and developers a direct way to observe SS behavior before and after algorithm changes.

It supports two modes.
In paper mode, the tool keeps a single order book snapshot in memory. Spread Support iterations can be triggered manually, and clicking a price level simulates full fills of all orders up to that level. This makes it easy to reproduce edge cases, inspect reactions, and verify how the algorithm evolves after each iteration.
In live mode, the tool continuously refreshes the order book from the exchange and works with real ordersDb records. Iterations are still manually triggered, but the environment reflects actual market conditions.
The HTML interface was built to make SS behavior visually obvious. It includes a color-coded order book table that distinguishes external orders, depth liquidity, SS orders, and mirrored orders. It also includes a statistics panel with open, filled, and cancelled SS counts per side, buy and sell VWAP values, and per-iteration deltas. A read-only tradeParams panel shows the active runtime state, while manual controls allow operators to trigger SS liq iteration, inspect state changes, and even copy cell values with right-click. Every iteration highlights what changed, making the algorithm easier to reason about.
This tool matters because it turns liquidity behavior from something inferred from logs into something directly observable. That makes both development and verification much more reliable.
Phase 2: extracting Safe Liquidity and Spread Support into optional modules
The second phase was structural. It did not aim to change behavior. It aimed to make the system cleaner, easier to maintain, and more flexible across different builds.
Previously, core Safe Liquidity state and Spread Support placement logic lived inside mm_liquidity_provider. That worked, but it tightly coupled several distinct concerns inside one module.
This release separates them into two dedicated modules:
- trade/mm_liquidity_safe.js
- trade/mm_liquidity_ss.js
Safe Liquidity module
The new mm_liquidity_safe.js encapsulates the liqLimits state and all related helpers:
- updateLiqLimits()
- loadLiqLimits()
- storeLiqLimits()
- resetLiqLimits()
- getLiqLimits()
- getVwapRangeString()
It processes only depth fills, using a strict subPurpose === ‘depth’ filter. That keeps Safe Liquidity focused on what it is supposed to track: depth-based execution history and the limits derived from it.
Spread Support module
The new mm_liquidity_ss.js encapsulates Spread Support behavior itself, including:
- updateSsLiquidity(liquidityOrders, orderBookInfo)
- updateSsVwap()
- SS price logic
- SS order-count limits
- mirror placement logic
Constants such as minimum and maximum SS orders per side were moved here as well, making the module self-contained.
Backward-compatible loading
The main mm_liquidity_provider.js now loads both modules through utils.softRequire().
That detail is important. These modules are optional.
If either one is missing, the bot still works correctly. Depth liquidity continues to operate. If mm_liquidity_safe is absent, Safe Liquidity limits are simply inactive. If mm_liquidity_ss is absent, Spread Support is inactive. No crashes, no broken flow, no need for separate code branches.
This is not a breaking rewrite. It is a modular upgrade.
The provider also now delegates SS-specific closing rules to the SS module when present, replaces the inline SS placement loop with ss.updateSsLiquidity(), and refreshes the order book after SS placement so depth orders can use a current mid. That last detail improves order placement consistency by ensuring later modules work from fresh market state.
Phase 3: replacing refill loops with a bounded mirror strategy
This is the core behavioral change of the release.
The old repeatable refill pattern could keep recreating exposure in ways that were undesirable under certain fill scenarios. The new strategy takes a different approach.

The core mirror rule
When a regular SS order is filled, the bot places a mirror order on the opposite side at the reflected price and with the same size.

It does not place a replacement on the same side.
That sounds simple, but the consequences are significant. Instead of endlessly refilling where liquidity was just consumed, the system acknowledges the fill and responds with a bounded counterpart across the spread. This keeps the market tighter without creating an unlimited feedback loop of same-side replenishment.
Mirror order properties
Mirror orders are explicitly marked with:
- subType: ‘mirrored’
- subTypeString: ‘ (ss mirrored)’
- priceCorrected: true
That last field is especially useful. It allows existing closeLiquidityOrders logic to skip valid mirrored orders even when they sit outside the normal SS spread window. In other words, mirrors can survive where they are supposed to survive without needing a separate cancellation pathway.
Cascade prevention
One major danger in mirrored logic is recursive behavior: a mirror gets filled, then mirrored again, then mirrored again, and so on.
That is explicitly blocked.
Filled mirror orders are not mirrored further. The module checks subType, and once a mirror is created, the original order is marked as mirror-source. This prevents cascade chains and keeps the mechanism bounded.
Risk controls inside the mirror strategy
The mirror algorithm was designed not just to respond, but to respond safely. Several controls were added for that reason.
Mirror distance cap
If the mathematically “true” mirror price would land too far from mid, the bot does not blindly place it there. Instead, it falls back to a bounded price near the SS spread edge.
This prevents mirrors from ending up so far away that they become detached from meaningful liquidity behavior.
VWAP relevance guard
SS now maintains its own fill statistics through a dedicated fillsEngine epoch keyed with subPurpose: ‘ss’. That means the bot can track SS buyVWAP and sellVWAP separately from depth liquidity.
But historical VWAP is only useful while it remains relevant. If SS VWAP drifts too far from current mid, it is treated as stale and ignored for placement constraints. The relevance threshold is set at 2%.
This matters after strong directional reversals. Without such a guard, an old VWAP anchor could keep SS logic trapped on one side of the market long after conditions changed.
Wide-spread relaxation
In volatile markets, the external spread may temporarily grow much wider than the intended SS zone. When that happens by a defined multiplier, mirror occupancy checks are relaxed so Spread Support can continue operating instead of freezing due to strict placement assumptions that no longer fit the market.
Bounded new regular SS placement
Regular SS placement now also respects SS VWAP when it is relevant. New regular buys are placed below SS buyVWAP, and new regular sells above SS sellVWAP.
That further reduces the chance of repeatedly adding fresh exposure at increasingly unfavorable levels.
Better statistics, better visibility, better operator control
This release also significantly improves observability and command output.
/stats improvements
The /stats command is now more accurate and more readable:
- it validates pairs through parseCommandParams
- accepts any pair or perpetual ticker, not just the default pair
- formats 24h spread values in bold
- uses stable precision for volumeInCoin2
- shows trading volume and executed-order statistics only for the default pair
- includes ladder (ld) orders in executed-order stats
- adds a Notes section

These changes are not cosmetic. They reduce confusion and make the command reflect context correctly.
New /orders liq full liquidity panel
A new rich liquidity statistics view is now available through /orders liq full.
It includes:
- a Depth liquidity block with status, spread parameters, order counts, open amounts, Safe Liquidity limits, and fill history
- a Spread Support block with SS spread range, order-size limits, regular and mirrored order counts, SS fill stats, VWAP, and MTM PnL
- a Combined total block that aggregates depth and SS fill data
- the current liquidity epoch start time
- exchange minimum order information
- current order book information via reusable depth helpers
Fill statistics tables are rendered in a compact four-column layout: label, Buy, Sell, and Delta.

This gives operators a much clearer picture of what liquidity is doing right now and how it got there.
/orders liq and /orderbook improvements
The regular liquidity order list now shows percentage filled for partially filled orders and includes subPurpose and subType labels for liquidity orders, such as ss, mirrored.
The /orderbook command now includes a new Purpose column that shows which bot modules correspond to each price level. That information is derived from live ordersDb records, so the operator can immediately see whether a level belongs to depth liquidity, SS, mirrored liquidity, or another bot subsystem.

Safer operator commands
The /enable liq command now includes a confirmation step before changing liquidity parameters. It also validates build capabilities: depth range notation is rejected if mm_liquidity_safe is absent, and ss parameters are rejected if mm_liquidity_ss is absent, with a clear message explaining the limitation.
A new /enable liq reset subcommand resets mm_liquidityInitTs and clears liqLimits, effectively restarting the VWAP epoch after confirmation.
Manual /buy and /sell commands also received an important safety improvement. If a requested order price deviates from market by more than 1000%, the bot stops and asks for confirmation with /y. This protects operators from accidental extreme-price orders caused by stale assumptions or input mistakes.
Finally, /account info now handles empty fee lists from exchange APIs more gracefully and shows a proper message instead of blank output.
No breaking changes
One of the strongest parts of this release is that it delivers a substantial internal upgrade without introducing hard breakage.
Both mm_liquidity_safe and mm_liquidity_ss are optional. If either is absent, mm_liquidity_provider continues to operate correctly. Depth liquidity remains active. Safe Liquidity and Spread Support are simply inactive where unavailable.
The only format-level evolution is that fillsEngine stats keys may now include an optional :
What this release really changes
At a high level, this upgrade does three things.
First, it makes Spread Support visible. The simulation tool turns hidden liquidity behavior into something that can be inspected, replayed, and validated.
Second, it makes Spread Support modular. Safe Liquidity and SS are no longer entangled inside one provider path, which makes builds cleaner and maintenance easier.
Third, and most importantly, it makes Spread Support safer. The mirror strategy replaces a more repeatable refill model with a bounded response pattern designed to keep the spread tight without enabling runaway loss loops.

For market-making systems, that is the right direction: not more activity for its own sake, but smarter behavior under real market pressure.
Looking ahead
Spread Support is useful precisely because it sits close to the market’s most sensitive zone: the spread itself. That also means it needs stronger controls, clearer visibility, and better operator tooling than simpler liquidity mechanisms.
This release moves ADAMANT Market-Making Bot decisively in that direction.
The bot now has a dedicated SS simulation environment, cleaner liquidity architecture, richer liquidity reporting, safer operator controls, and a mirror-based Spread Support mechanism that is designed to be both practical and bounded.
In other words, Spread Support is no longer just tighter.
It is more understandable, more maintainable, and much harder to exploit.
ADAMANT Market-making bot: A Safer, Smarter Spread Support was originally published in ADAMANT on Medium, where people are continuing the conversation by highlighting and responding to this story.
0
0
Ապահովաբար կցեք ձեր օգտագործած պորտֆոլիոն՝ սկսելու համար:




