Volume-Mid Market Maker
Learn how the fill-priority midpoint bot retains approachable quotes, manages inventory, and controls refresh behavior.
Volume-Mid Market Maker
Volume-Mid is the fill-priority version of midpoint market making. It places post-only bids and asks around the live midpoint like Mid-Price, but it is less eager to cancel an order when the market moves toward that order.
This gives an approachable quote more time to fill and preserves its queue position. It is useful when the objective is traded volume, maker rebates, exchange points, or a higher fill rate. It does not guarantee profitable turnover.
Run it
Preview the bot without creating a job:
mlab bot run volume-mid ETH/USDT \
--venue bulk \
--margin 200 \
--leverage 8 \
--duration 3600 \
--spread-bps 6 \
--refresh-time 2 \
--refresh-tolerance-bps 1 \
--stop-loss-pct 5 \
--dry-runRemove --dry-run to deploy it:
mlab bot run volume-mid ETH/USDT \
--venue bulk \
--margin 200 \
--leverage 8 \
--duration 3600 \
--spread-bps 6 \
--refresh-time 2 \
--refresh-tolerance-bps 1 \
--stop-loss-pct 5The job runs inside mlabd, so the terminal is free after deployment.
--venue accepts bulk or hyperliquid. Hyperliquid currently means testnet native perpetuals and requires mlab auth set hyperliquid before live deployment.
What makes it different
Imagine a working buy order at $1,925.
- If the market falls toward
$1,925, Volume-Mid keeps the order resting. The order is becoming more likely to fill. - If the market rises away from
$1,925, the order becomes less competitive. After its minimum lifetime and allowed drift are exceeded, the bot cancels it and submits a higher bid around the new midpoint.
The sell side behaves in reverse:
- A rising market is moving toward the resting sell, so the bot keeps it.
- A falling market is moving away from the sell, so the bot eventually replaces it lower.
Volume-Mid therefore keeps quotes when the market approaches them and chases when the market moves away.
Mid-Price protects its configured spread more strictly. After a short fixed resting period, it replaces a stale quote whether the market moved toward it or away from it.
| Behavior | Mid-Price | Volume-Mid |
|---|---|---|
| Main objective | Preserve the configured midpoint spread | Prioritize fills and traded volume |
| Market approaches a quote | Reprice when its fixed threshold is exceeded | Keep the quote resting |
| Market moves away | Reprice | Reprice after the configured controls allow it |
| Refresh controls | Fixed by the mode | Set by the user |
| Queue retention | Lower | Higher |
| Fill probability | Generally lower | Generally higher |
Refresh controls
--refresh-time
This value is in seconds and is the minimum lifetime of each individual quote.
With --refresh-time 2, a newly resting order cannot be replaced for normal price drift during its first two seconds. Once replaced, the new order receives its own two-second minimum lifetime.
It is not a global loop that blindly cancels every two seconds. The local orderbook continues processing every update while the order rests.
Fills, completed orders, inventory-limit changes, market-data loss, and crossing recovery are handled immediately and do not wait for this time.
--refresh-tolerance-bps
This is how far the desired quote may move away from the resting quote before replacement is worthwhile.
With --refresh-tolerance-bps 1, the bot keeps the order until the new desired price is more than one basis point away. Near an ETH price of $1,927, one basis point is approximately $0.19.
A larger tolerance causes fewer replacements and keeps queue position longer. A smaller tolerance follows the market more closely but creates more cancellations.
Both refresh values are required for Volume-Mid because they define the fill-rate versus quote-freshness trade-off.
Sizing and inventory
--margin is the collateral allocated to the bot. Leverage converts it into the maximum one-sided inventory exposure.
With $200 margin at 8x, the maximum is approximately $1,600 of directional exposure. While inventory is flat, the bot starts with roughly $800 on the bid and $800 on the ask.
Those two working orders do not mean the bot immediately has $1,600 of directional risk. Equal buy and sell fills offset one another.
As fills create inventory:
- long inventory makes the next bid smaller and the ask larger;
- short inventory makes the ask smaller and the bid larger;
- reaching the long limit disables new risk-increasing bids;
- reaching the short limit disables new risk-increasing asks.
This continuous skew is why quote sizes change throughout a run. The bot is trying to keep making markets while guiding its own inventory back toward flat.
Use --size instead of --margin when you want to specify the exact maximum base-asset inventory.
Spread and fees
--spread-bps is the complete bid-to-ask distance around the current midpoint. With 6 bps, the bid begins about 3 bps below midpoint and the ask about 3 bps above it.
Volume-Mid may capture less than the configured spread because it deliberately retains a quote while the market approaches. That higher fill probability is the mode's trade-off.
Before choosing a spread, consider:
- maker fees or rebates on both fills;
- how much of the quoted spread is usually captured;
- adverse selection after a quote fills;
- the cost of carrying unmatched inventory;
- the possible taker cost of the final inventory unwind.
A bot can generate high volume while losing money if fees and adverse selection exceed its captured spread. Negative maker fees or rebates can materially change the result.
Stop loss
--stop-loss-pct is optional and is measured against allocated margin, not leveraged exposure.
With $200 margin and --stop-loss-pct 5, the configured maximum loss is approximately $10.
The bot combines its own realized PnL, midpoint-marked unrealized PnL, and signed fees or rebates. At the threshold it stops quoting, cancels its orders, unwinds its remaining inventory, and terminates.
Funding is excluded because account-level funding cannot yet be assigned safely to one bot. Fast markets, venue latency, and unwind slippage can also cause the final loss to exceed the configured threshold.
Read the logs
mlab bot logs <JOB_ID> --followAn example fill line:
fill BUY 0.81 @ 1926.796
buy=10.5413 sell=10.5212 inventory=0.0201
realized=13.0688 unrealized=0.0116 fees=-8.1192 pnl=4.9613buyandsellare cumulative quantities filled by this job.inventoryis the unmatched job-owned quantity. Positive is long and negative is short.realizedis gross PnL from inventory that has been matched.unrealizedmarks remaining inventory at the current venue midpoint.feesis cumulative and signed. A negative value is a cost; a positive value is a rebate.pnlis the bot's current net result after realized PnL, unrealized PnL, and fees.
Judge the settled spread result when inventory=0. While inventory is open, PnL moves with the midpoint. The shutdown market order and its fees can also change the final result.
Existing positions and other bots
Volume-Mid tracks fills by its own order IDs. It does not treat the account's complete ETH position as its inventory.
It can run while another position or bot uses the same symbol. When it stops, it cancels only its orders and submits the exact opposite of its own remaining inventory. It does not flatten the entire account position.
All jobs still share account collateral and liquidation risk. Overlapping algorithms can also compete or self-trade, subject to venue rules.
Duration and shutdown
The bot continues until its duration ends, it is stopped manually, its stop loss triggers, or an unrecoverable error occurs. Returning to flat starts another cycle; it does not complete the job.
On shutdown, Market Lab:
- accounts for in-flight order actions;
- cancels this job's working quotes;
- reconciles final fills;
- unwinds only this job's remaining inventory;
- confirms the job-owned inventory is flat.
Manage the job
mlab bot jobs
mlab bot status <JOB_ID>
mlab bot logs <JOB_ID> --follow
mlab bot stop <JOB_ID>Use --output jsonl for the full structured event stream.
Volume-Mid is an execution system, not a profitability claim or trading advice. A high fill rate can amplify fees, adverse selection, and inventory risk as easily as it can increase spread capture or rebates.