Bots
The six bots a market maker is created with, what each personality changes about the tape, every configuration field and the range it accepts, and the statuses that decide whether a market can quote at all.
Bots are the roster that produces the tape. They do not decide the price — that belongs to the price engine alone, and nothing else is allowed to touch it. What the bot layer decides is when a trade prints, how large it is, and which bot takes each side.
Six are created with every market maker, and the Bots tab on the market detail screen is where you manage them. There is no create-a-bot screen: the roster is fixed at six and you configure the ones you have.
| Name | Personality | Default spread |
|---|---|---|
| Scalper Alpha | SCALPER |
0.10% |
| Scalper Beta | SCALPER |
0.15% |
| Swing Trader | SWING |
0.30% |
| Accumulator | ACCUMULATOR |
0.20% |
| Distributor | DISTRIBUTOR |
0.20% |
| Market Maker | MARKET_MAKER |
0.10% |
The two-bot gate
A print needs two sides. The engine checks the count of ACTIVE bots before it consults the bot layer at all, and a market below two prints nothing — while keeping its ACTIVE status and its green badge. This is the single most common reason a market goes silent, and the dashboard names it as the closed gate.
Bots are created PAUSED. Starting a market maker activates all of them; stopping or pausing it pauses all of them. You can pause individual bots afterwards — just not below two if you want the market to keep quoting.
What each personality changes
A personality is a small table of numbers, not a strategy. Three things differ:
| Personality | Buy affinity | Size multiplier | Minimum gap between its own trades |
|---|---|---|---|
SCALPER |
0.5 — neutral | 0.6x | 1s |
SWING |
0.45 — mild sell lean | 1.4x | 12s |
ACCUMULATOR |
0.7 — buys more often | 1.0x | 6s |
DISTRIBUTOR |
0.3 — sells more often | 1.0x | 6s |
MARKET_MAKER |
0.5 — neutral | 0.8x | 2s |
Buy affinity biases which bot is picked as the buyer when a trade happens. It does not bias the market's direction — direction is settled by the price process before any bot is selected. An accumulator is simply more often found on the bid than the ask, which is what the word means.
The minimum gap is a floor against rapid-fire, not the rate limiter. Trade cadence comes from a 24-hour activity curve applied to each bot's daily budget.
The personality column is set when the six bots are seeded and there is no
endpoint to change it. What you tune is the numbers below.
Configuration
Every field is on the Bots tab, and every change applies to the running market immediately and is recorded in the audit trail.
| Field | Accepted range | Refusal |
|---|---|---|
riskTolerance |
0.1 – 1.0 | "Risk tolerance must be between 0.1 and 1" |
tradeFrequency |
HIGH, MEDIUM, LOW |
"Trade frequency must be HIGH, MEDIUM or LOW" |
avgOrderSize |
greater than 0 | "Average order size must be greater than 0" |
orderSizeVariance |
0.1 – 0.5 | "Order size variance must be between 0.1 and 0.5 (50%)" |
preferredSpread |
0.0001 – 0.1 | "Preferred spread must be greater than 0" |
maxDailyTrades |
1 or more | "Max daily trades must be greater than 0" |
Seeded values follow the market's aggression level: risk tolerance 0.3 / 0.5 / 0.8, average order size 50 / 100 / 200 and a daily budget of 1,200 / 3,500 / 9,000 for CONSERVATIVE, MODERATE and AGGRESSIVE respectively.
Before v6.1.5 the Bot Management form posted field names the server does not read, so trade frequency, order size and risk tolerance were silently thrown away. Risk tolerance was worse: the slider ran 1 to 10 in whole steps against a server that accepts 0.1 to 1, so nine of the ten positions were refused outright — and because the request fails as a whole, they took Max Daily Trades down with them, the one field that did work. If you are on an older build, none of your bot edits have applied.
How the daily budget behaves
maxDailyTrades is a budget paced across the whole UTC day, not a fuse. The
order-flow layer spends it along a 24-hour activity curve — roughly one trade
every 10 seconds across the US/EU overlap and every 35 seconds overnight — so it
lasts until midnight.
A market does not spend its full budget. Two bots are needed per print but only one initiates, and simultaneous initiators on the same tick collapse into a single trade, so realised use lands near a third of the cap. In the 1,000–5,000 range the observed result is close to one trade per day per unit of cap.
Both the per-bot counter and the market's currentDailyVolume are zeroed by the
daily reset job at the UTC boundary. That job checks whether the day has already
been reset before handing out a fresh allowance — two separate resets that
disagreed about when a day starts could otherwise hand a market a second full
allowance mid-session.
Order sizes and spreads
Order sizes follow a realistic distribution — mostly small, occasionally large,
snapped to round lots — rather than a uniform band around the average, which is
the most obvious synthetic-tape tell an addon can have. orderSizeVariance
shapes that spread and riskTolerance scales it.
preferredSpread sets how far from mid a bot quotes real liquidity, so the
five personalities sit at visibly different distances from the touch rather than
stacking onto the same two levels of the book. It has no effect on a market
running at 0% real liquidity.
Statuses
| Status | Meaning |
|---|---|
ACTIVE |
Counts toward the two-bot gate and can be selected for a trade |
PAUSED |
Present but not trading |
COOLDOWN |
Temporarily out, with an expiry, and returns to ACTIVE on its own |
A bot can only be activated while its market maker is ACTIVE. Activating one on a stopped market is refused with "Cannot activate bot when market maker is not active".
Cooldown takes a duration. The dialog asks for minutes and defaults to 15. Setting any other status clears the cooldown. Before v6.1.5 nothing recorded a duration and nothing brought a bot back, so cooldown was a one-way door: the bot stayed out until an operator noticed and reactivated it by hand.
Pausing and activating individual bots reaches the running market immediately. The engine loads every bot on a market, not just the active ones, precisely so that a paused bot has a row to flip — otherwise activating it did nothing until the next daily reset or a full stop/start cycle.
Reading bot performance
The bot list and the individual bot screen report what was actually measured:
| Figure | What it counts |
|---|---|
| Total trades | Every trade, AI-to-AI and real |
| Real trades | Fills against real user orders — the only trades with P&L |
| Profitable trades | Profitable real fills |
| Realised P&L | The bot's lifetime accumulator, written by the matcher on each real fill |
| Position and average entry | The bot's current inventory |
| Trades remaining today | Daily budget less trades made |
A trade between two of the platform's own bots has no profit or loss at all, so on a market at 0% real liquidity most bots have never had a trade capable of winning or losing. Those screens show blanks, not zeros and not an assumed rate.
An older build reported every bot's success rate as 50% and its profitable trades as exactly half its total on the list, and a flat 65% win rate on the detail screen with the counts derived from it. None of it was measured.
Two tiles that could only ever read N/A — the bot's next scheduled trade and its behaviour seed — were removed rather than left on the page.