Creating and configuring a market

The four-step create wizard, every field it writes and the validation that rejects it, plus the price controls that only appear afterwards — price mode, bias, forced phase, volatility and the target price.

10 min readUpdated 5 September 2026markets, configuration, price-range, volatility, bias

A market maker attaches one-to-one to a market, and a market is a venue plus an id — the pair (marketType, marketId) carries the unique index. A second attempt on the same market is refused with "AI Market Maker already exists for this market"; the same pair on the other venue is a different market and is allowed.

Creation happens in a four-step wizard at /admin/ai/market-maker/market/create. Everything else — price mode, bias, phase, volatility, the running-state controls — lives on the market's own Configuration tab afterwards.

Choosing the venue

Step 1 asks which venue first, because it decides which markets exist. The selector appears only when this install has both.

Ecosystem (spot) Futures (perpetual)
What the pool holds Base and quote inventory Quote currency only, as margin
What a fill does Moves both balances Opens or closes a position
Who owns the orders Each bot, settled against the pool One shared pool account
Leverage None — orders are funded, not margined 1x by default, up to 125x
Rebalance Available Refused — there is no ratio to rebalance
Liquidation Not possible Yes, on the same terms as any trader

That last row is the one to read twice. A futures maker posts real margin and holds a real position, so a large enough adverse move liquidates it exactly as it would liquidate a customer. That is deliberate: the money is the operator's either way, and an unliquidatable position would accrue a loss nothing bounds.

It buys when the market sells to it and sells when the market buys from it, so at any moment it is carrying inventory in whichever direction the market last ran — and that inventory is marked against a price it does not control. The maker closes a position before it opens the opposite one, so it never holds a long and a short at once, but it does hold one of them. Size the pool for a move against you, not for the spread you expect to earn.

Leverage

A futures market maker has one extra field, on step 3: futures leverage.

It ships at 1x, which is a risk decision rather than a placeholder. At 1x the pool posts the full notional of every order and the position cannot be liquidated by anything short of the price reaching zero. At 10x a 10% adverse move takes the whole allocation. Raise it deliberately or not at all.

The field is hidden on ecosystem markets and the endpoint refuses it there, because a maker on that venue funds its orders from pool balances rather than posting margin — there is nothing for a leverage to divide.

What creation actually produces

One request writes four things in a single transaction:

  • the market maker row, status STOPPED;
  • a pool with zero balances on both sides;
  • six bots, all PAUSED — Scalper Alpha, Scalper Beta, Swing Trader, Accumulator, Distributor and Market Maker;
  • a CONFIG_CHANGE history entry recording the parameters it was created with.

Nothing trades. The market is created stopped on purpose: it has to be funded and started deliberately.

Step 1 — Select market

The list offers markets on the selected venue that do not already have a market maker. The target price field is pre-filled from the market's own metadata price where one exists.

Step 2 — Price settings

  1. Pick the ecosystem market to attach to

Two inputs: a target price and a range, expressed as a percentage either side of it. The wizard converts that percentage into the two absolute bounds the API stores.

priceRangeLow  = targetPrice x (1 - percent/100)
priceRangeHigh = targetPrice x (1 + percent/100)

The API validates the result, and every one of these is a hard refusal:

Rule Message
All three prices above zero "Target price must be greater than 0"
priceRangeLow < priceRangeHigh "Price range low must be less than price range high"
Target inside the range "Target price must be within the price range"
Deviation from target at most 50% on each side "Price range deviation from target must be within 50%"
No value below 0.00000001 "Price values must be at least 0.00000001 (8 decimal places)"

The price process is contained inside the band you configure — but the restoring force only engages in the outer 20% of it. Once it is pulling, the direction of the next move becomes progressively predictable, which on a synthetic market is an exploitable edge and on one that settles binary options is a free bet.

That is why the dashboard reports at range edge as its own state rather than lumping it in with "inside the band": you can still fix it by widening the range, before the price actually leaves. A range too tight for the configured volatility also produces a startup warning in the server log naming the edge an observer would hold.

The band is measured geometrically, not linearly. On a range of 1 to 100 the centre is 10, not 50.5 — so a market sitting exactly on its anchor reads as centred rather than as 90% of the way to the floor.

Step 3 — Trading configuration

Aggression is a 1–10 slider that maps onto the three levels the API stores:

Slider Level Bot risk tolerance Bot average order size Bot daily trade budget
1–3 CONSERVATIVE 0.3 50 1,200
4–7 MODERATE 0.5 100 3,500
8–10 AGGRESSIVE 0.8 200 9,000

Those figures seed the six bots at creation and are editable per bot afterwards. They are sized from measured density, not from nominal arithmetic: a MODERATE market prints roughly 3,500 trades a day, one every 25 seconds on average, about every 10 seconds across the US/EU overlap and every 35 seconds overnight.

Older builds seeded 50/100/200 daily trades, which a market spent inside the first hour of each UTC day and then printed nothing at all until midnight. The allowance is now paced across the whole day along an activity curve, so an old market with an old number is strictly better off — the same allowance simply lasts until midnight. If it reads as abandoned rather than conservative, raise maxDailyTrades on its bots.

Real Liquidity (0–100) is the share of each trade's size that is placed as a genuine resting order in the Ecosystem book, backed by the pool. Zero means bot-to-bot only — a price series and a tape with no user-fillable orders and no money at risk. Start there.

Max daily volume is a hard trade gate, not a target. A market that reaches it stops quoting until the daily UTC reset. Its counter is currentDailyVolume, and it is zeroed by the daily reset job — so it is volume today, never a rolling 24 hours.

Step 4 — Review

The review step restates what will be created. Creating writes the transaction described above and lands you on the market's detail screen.

After creation: the Configuration tab

  1. Open the market row from the Markets list

These controls do not exist in the wizard. Each is its own endpoint, each writes a history entry, and — since v6.1.5 — each applies to the running market immediately rather than at the next full reload.

Price mode

priceModetype: enumdefault: AUTONOMOUS
How the price relates to the outside world
  • AUTONOMOUS — the price process alone. No external reference.
  • FOLLOW_EXTERNAL — tethered to an external symbol at correlationStrength (0–100).
  • HYBRID — the same tether at half that strength. It is a blend, not a peg.

externalSymbol is required for both non-autonomous modes; the request is refused without it, and a symbol the active exchange provider does not list is refused too. The external price is fetched on a slow cached cadence, off the price step, so a slow exchange can never stall a tick.

On an autonomous market the range is absolute bounds: the price stays inside that box.

On a following market it is a tracking tolerance. The band is re-centred on the reference at the width you configured and travels with it, so the width is how far price may stray from the reference — a narrower range tracks more tightly, a wider one lets the market keep more of its own character. You do not need to widen it to "cover" where the reference might go.

The tether is still a slow restoring drift rather than a peg: at 100% strength it takes about a day to close half of any remaining gap. Full detail in Following an external price.

The first time a tether engages, the server log states the estimated directional edge a client watching both feeds would hold over the next hour. That is a legitimate configuration for an ordinary market and a poor one for a market that also settles binary options. Use AUTONOMOUS there.

Market bias

marketBiastype: enumdefault: NEUTRAL
Directional guidance for phase transitions
biasStrengthtype: numberdefault: 50
How strongly bias affects phase transitions

BULLISH, BEARISH or NEUTRAL, with a strength of 0–100. Bias influences how the market moves between phases; it is not a guaranteed direction.

Volatility

baseVolatilitytype: numberdefault: 2
Base daily volatility percentage
volatilityMultipliertype: numberdefault: 1
Multiplier applied to the current phase
momentumDecaytype: numberdefault: 0.95
How quickly momentum decays

Accepted ranges are 0.120 for base volatility, 0.52.0 for the multiplier and 0.80.999 for momentum decay. At least one of the three must be present or the request is refused.

Volatility is integrated against wall-clock time, not against tick count, so a market's realised volatility matches what you configured regardless of how often the engine happens to tick, and a restart resumes on the correct distribution.

Market phase

Four Wyckoff-style phases — ACCUMULATION, MARKUP, DISTRIBUTION, MARKDOWN. The market transitions between them on its own; Market Phase Control forces one, bypassing the normal transition rules, and the response says so.

A forced phase now reaches the live market and expires when told to. Its volatility multiplier is applied by the engine only — an older build applied it twice, once in the engine and once written back onto the market's own volatility setting, so a forced phase ran at roughly 2.25x the volatility intended.

Target price

targetPricetype: number
The price the market steers toward

Must sit inside the configured range or the request is refused with the range quoted back. A move of more than 5% is flagged as a large change but still allowed.

The price sync job warns when a target price has drifted more than 10% from its external reference, at most once per market per hour.

Reset daily counters

Zeroes currentDailyVolume and the bots' dailyTradeCount immediately rather than waiting for the UTC reset. Use it to bring a market that has spent its budget back to quoting inside the same day — but understand that you are handing out a second full allowance, and the budget existed for a reason.

Editing the core fields later

The same fields the wizard writes are editable from the Configuration tab: target price, both range bounds, aggression, max daily volume, volatility threshold, pauseOnHighVolatility and real liquidity percent. Validation is identical to creation.

Only fields that actually changed are recorded in history. An earlier build compared a DECIMAL column (which arrives from the database as a string) against a number, so every save wrote a CONFIG_CHANGE for fields nobody had touched — and a market with a 9–10 range could not be edited at all, because "9" > "10" is true as text.

Deleting a market maker

Deleting stops the market through the engine first, waits up to ten seconds for the engine to confirm, cancels the bots' open ecosystem orders so locked funds return, and only then removes the row. The pool, the bots and the entire history cascade with it.

Deleting a funded market pays the pool out first, and it does so silently: whatever the pool still holds in either currency is credited to the platform's wallet — the Super Admin's, whoever clicked — in the same transaction that zeroes the pool, and the delete goes on from there. The confirmation dialog says so, but nothing asks you to confirm the amount. If you want to see the money move, or to land it somewhere you can check, withdraw the pool yourself before you delete.

The payout goes to the platform wallet and not to you because the delete runs under delete.ai.market_maker.market, a permission that says nothing about money — an admin granted it to retire markets must not be paid a pool's balance for doing so. Before v6.2.5 it was. See Funding the pool for whose wallet that is and why.