Grid Market Maker
Learn how Market Lab maintains a fixed multi-level quote ladder, controls inventory, locks gross spread, and rescues stalled exposure.
Grid Market Maker
The Grid bot maintains several post-only buy and sell orders around one anchored market price. It is designed for range-bound markets: repeated movement through the ladder can create matched buys and sells at different prices.
This is grid market making, not a static grid-trading bot:
- the ladder is built from the live best bid and ask;
- order sizes change automatically with the bot's inventory;
- the bot can move the complete ladder after the market leaves its range;
- bot-owned inventory, PnL, soft reset, and shutdown are managed continuously.
It is also not a participation schedule. --levels controls how many prices are quoted, while --step-bps controls the distance between them. The bot does not target a percentage of market volume.
Run it
Preview the complete ladder without creating a job:
mlab bot run grid BTC/USDT \
--venue bulk \
--margin 100 \
--leverage 10 \
--duration 3600 \
--levels 5 \
--step-bps 1 \
--reset-threshold-pct 0.1 \
--stop-loss-pct 5 \
--dry-runRemove --dry-run to deploy it:
mlab bot run grid BTC/USDT \
--venue bulk \
--margin 100 \
--leverage 10 \
--duration 3600 \
--levels 5 \
--step-bps 1 \
--reset-threshold-pct 0.1 \
--stop-loss-pct 5The command returns after deployment. The bot continues inside mlabd.
--venue accepts bulk or hyperliquid. Hyperliquid currently means testnet native perpetuals and requires mlab auth set hyperliquid before live deployment.
Start with one concrete example
Assume:
margin: $100
leverage: 10x
maximum exposure: approximately $1,000
levels: 5 per side
step: 1 bpsWhile inventory is flat, the bot divides the working exposure like this:
approximately $500 across five bids = about $100 per bid
approximately $500 across five asks = about $100 per askIf the anchored best bid is $65,930, the buy ladder is conceptually:
| Level | Location | Initial exposure |
|---|---|---|
| Bid 1 | 1 bps below the anchored best bid | about $100 |
| Bid 2 | 2 bps below the anchored best bid | about $100 |
| Bid 3 | 3 bps below the anchored best bid | about $100 |
| Bid 4 | 4 bps below the anchored best bid | about $100 |
| Bid 5 | 5 bps below the anchored best bid | about $100 |
The ask ladder is the mirror image above the anchored best ask. Final prices and quantities are rounded to the venue's valid tick and lot sizes.
--step-bps is therefore not the full bid-to-ask spread. It is the distance from the anchored touch to Level 1 and the distance between following levels.
The grid stays anchored
The bot does not pull the whole ladder behind every midpoint update. Each level keeps its anchored price while that price remains a valid maker order.
When a level fills, the bot tries to replenish that level at the same price. Existing safe orders remain untouched, which preserves their queue position.
If a stored price would now cross the book, the venue may report rejectedCrossing. The bot treats this as a temporary market-state conflict, waits for a fresh book state, and tries again when the level is maker-safe. It does not convert the order into a taker trade.
Inventory changes the next sizes
Order sizes begin equal only while the bot is flat. Replenished levels are automatically skewed as inventory changes.
Suppose Bid 1 fills and creates a long position:
- newly replenished bids become smaller, because another buy would add risk;
- newly replenished asks become larger, because a sell would move inventory back toward flat;
- at the maximum long limit, the bot stops creating new risk-increasing bids.
If an ask fills first and creates a short position, the behavior reverses: new asks shrink and new bids grow.
The user does not configure a size-growth multiplier. Market Lab derives the skew from current bot-owned inventory and the maximum inventory limit. Existing resting levels are not cancelled merely to apply a small size change; the new size is used when a level must be replenished.
Reducing inventory locks gross spread
Normal grid mode remembers the bot's weighted average entry price.
For long inventory, an inventory-reducing ask cannot be placed below the average entry plus that level's grid distance. For short inventory, a reducing bid cannot be placed above the average entry minus that distance.
Example:
average long entry: $66,000
grid step: 1 bps
Ask 1 cannot reduce below approximately $66,006.60
Ask 2 cannot reduce below approximately $66,013.20
Ask 3 cannot reduce below approximately $66,019.80This protects a positive gross price difference when normal grid recovery completes. It does not guarantee net profit: exchange fees, rebates, partial fills, adverse movement, soft reset, and shutdown execution still affect the result.
Automatic recentering happens while flat
The full grid range is:
levels × step-bpsFive levels at 1 bps produce a 5 bps recenter range. When the bot is flat and the midpoint has moved more than 5 bps from the current anchor, it cancels the old ladder and builds a new one around the latest best bid and ask.
The bot does not normally recenter while inventory is open. Moving the reducing ladder to the new midpoint could give away the price difference it is trying to capture. Returning to flat also does not force a reset unless the market has left the configured grid range.
Soft reset rescues stalled inventory
--reset-threshold-pct is an optional adverse move from the bot's weighted average entry. Its accepted range is 0 through 1 percent; 0 disables it.
Example for a long position:
average entry: $66,000
reset threshold: 0.1%
trigger price: approximately $65,934If the midpoint falls to that trigger, waiting for the profitable ask ladder may leave the bot stuck in a falling market. Soft reset therefore:
- cancels the normal grid;
- stops adding more exposure;
- places one post-only sell near the current midpoint for the exact remaining long inventory;
- reprices that reducing order as the midpoint changes;
- reanchors a fresh grid after inventory returns to flat.
For a short position, the trigger is the configured percentage above its average entry and the rescue order is a buy.
Soft reset can realize a loss. Its purpose is to accept a smaller controlled loss and restore neutral inventory before the hard stop is reached. It is not a second take-profit rule and does not promise break-even after fees.
Hard stop loss
--stop-loss-pct is measured against the margin allocated to this bot, not its leveraged exposure.
With $100 margin and --stop-loss-pct 5, the configured maximum loss is approximately $5.
The bot watches its own realized PnL, midpoint-marked unrealized PnL, and signed fees or rebates. At the threshold it cancels its quotes, unwinds its exact remaining inventory, and terminates. Funding is excluded because account-level funding cannot yet be attributed safely to one bot.
Fast movement and unwind slippage can make the final loss larger than the configured amount. The stop defines when Market Lab reacts; it is not a guaranteed exit price.
Soft reset and stop loss are different
| Control | Trigger | Action | Job continues? |
|---|---|---|---|
| Soft reset | Price moves adversely from average entry | Work only the reducing side near midpoint | Yes, after returning flat |
| Stop loss | Net bot PnL reaches a percentage of allocated margin | Cancel, unwind, and terminate | No |
The soft reset handles a stalled leg. The stop loss caps the complete job's loss.
Read the logs
mlab bot logs <JOB_ID> --followGrid levels are labeled directly:
resting BUY L1 ... @ 65959.0 size=0.00151
resting SELL L3 ... @ 65994.0 size=0.00151
fill SELL 0.00151 @ 65994.0 ... inventory=-0.00303 ... pnl=-0.008376
recentered grid 65970.0 -> 65980.5
SOFT RESET short exposure=1937.56 trigger=1939.50 mark=1940.05; quoting BUY near midL1is nearest to the anchored touch; higher numbers are farther away.inventoryis bot-owned unmatched quantity. Positive is long, negative is short, and zero is flat.realizedis gross PnL from matched quantity.unrealizedmarks open inventory at the newest midpoint.feesis signed: negative is a cost and positive is a rebate.pnlcombines realized, unrealized, and fees.
Parameters
| Input | Meaning |
|---|---|
SYMBOL | Market to quote, such as BTC/USDT |
--venue | Execution venue: bulk or hyperliquid |
--margin | Collateral allocated to the bot; conflicts with --size |
--size | Exact maximum one-sided inventory in base units; conflicts with --margin |
--leverage | Multiplies margin into the hard maximum inventory exposure; default 1 |
--duration | Maximum runtime in seconds |
--levels | Simultaneous price levels on each side; default 3, range 1–100 |
--step-bps | Distance behind the anchored touch and between levels; default 2, must be positive |
--reset-threshold-pct | Optional adverse move from average entry that starts soft reset; range 0–1% |
--stop-loss-pct | Optional net loss as a percentage of allocated margin; range 0–100% |
--dry-run | Print the plan without creating a job or placing orders |
--yes | Skip the live deployment confirmation |
Existing positions and shutdown
The bot attributes inventory and PnL only to its own order IDs. An existing account position or another bot on the same symbol does not become part of this grid's inventory.
When the duration ends, the job is stopped, or an error requires shutdown, Market Lab cancels only this job's orders and unwinds only this job's unmatched quantity. Other algorithms remain responsible for their own exposure.
All activity still shares the same account collateral, liquidation risk, and venue self-trade rules.
When to use it
Grid market making is most suitable when price repeatedly moves through a range. A strong one-way trend can fill several levels on one side and leave the bot waiting for reversal; soft reset and stop loss limit that risk but cannot make a trending market range-bound.
Use --dry-run to inspect the complete ladder, confirm that its total range makes sense for the market, and compare the expected grid edge with the venue's fees before deploying.
Grid is an execution system, not a profitability claim or trading advice. Fees, adverse selection, trending markets, latency, liquidation risk, and forced inventory unwind can outweigh captured grid spreads.