Market making in Python
Market making earns the spread by providing liquidity, here is a simplified market-making strategy in Python, backtested on the Rust core.
What is market making?
A market maker continuously quotes both a bid and an ask, earning the spread when both fill while managing the inventory it accumulates. It is fundamentally a mean-reversion-around-fair-value business: buy a touch below fair, sell a touch above, repeat.
True market making is a low-latency, order-book game. On bars a backtest cannot see queue position or live quotes, so this page models the inventory logic, fading small deviations from fair value, which is the strategic core. The quoting itself, a resting order queued behind the book with a latency on every order and cancel, runs on the trade clock of the Researcher plan.
The logic
We approximate micro fair value with a 20-bar moving average and measure the fractional deviation of price from it. Small deviations are the maker's edge.
When price dips a tenth of a percent below fair value we go long (simulating a passive buy fill); when it pops above, we go short; otherwise flat. That captures the inventory-cycling behaviour of a maker at bar resolution.
market making in Python
Here is the full strategy in the Manifold-BT expression DSL. It imports manifoldbt, builds the signal, configures realistic execution, and runs the backtest against Rust.
import manifoldbt as mbt
from manifoldbt.indicators import close
from manifoldbt.helpers import time_range, Slippage, Interval
# Micro fair value and the fractional deviation of price from it
fair = close.rolling_mean(20)
edge = (close - fair) / fair
# Fade small deviations: buy below fair, sell above, capturing the spread
strategy = (
mbt.Strategy.create("market_making")
.signal("edge", edge)
.size(mbt.when(edge < -0.001, 1.0, mbt.when(edge > 0.001, -1.0, 0.0)))
)
start, end = time_range("2024-01-01", "2026-01-01")
config = mbt.BacktestConfig(
universe={"binance": ["BTCUSDT"]},
time_range_start=start,
time_range_end=end,
bar_interval=Interval.minutes(1),
initial_capital=10_000,
fees=mbt.FeeConfig.binance_perps(),
slippage=Slippage.fixed_bps(1),
warmup_bars=20,
)
store = mbt.ingest(provider="binance", symbol="BTCUSDT", symbol_id=1,
interval="1m", start="2024-01-01T00:00:00Z",
end="2026-01-01T00:00:00Z")
result = mbt.run(strategy, config, store)
print(result.summary())
mbt.plot.tearsheet(result, show=True)Run your first backtest
Install Manifold-BT and reproduce the backtest above in seconds. The Rust core runs years of bars sub-second so you can sweep parameters instead of waiting.
Backtest it with Manifold-BT
At one-minute resolution fees are the whole game, and this run shows it. Over 2024 and 2025 on BTCUSDT the bar-level fade makes 21,637 round trips, pays $8,564 in fees on a $10,000 account and ends at -100%: the edge it captures per trade is smaller than the taker fee it pays to get in and out.
That is the honest answer to whether market making can be backtested on bars: the inventory logic can, the economics cannot. A real maker posts passive orders, pays the maker fee or earns a rebate, and is filled only when the size resting ahead of it at its price has traded. To test that, run the quotes on the trade clock in Researcher, where a resting order waits behind the depth of the stored book and each fill is followed by its markout.
| Universe | {"binance": ["BTCUSDT"]} |
| Bar interval | 1m |
| Fees | FeeConfig.binance_perps() |
| Slippage | fixed 1 bps |
| Warmup | 20 bars |
| Total return | -100% |
| Sharpe | -10.5 |
| Max drawdown | -100% |
| Win rate | 10% |
| Trades | 21,637 |
Frequently asked questions
Can you backtest a market making strategy?
On bars, only half of it. A bar backtest can model the inventory logic, fading small deviations from fair value, but not the queue a passive quote waits in or the latency between a maker and its venue, which is where a maker's fills come from. Manifold-BT's Researcher plan runs the quotes on the trade clock: a resting order queued behind the displayed depth, or at its exact place when the market is stored order by order, with a latency on every order and cancel.
Why do fees dominate market making?
A maker earns a thin spread on many trades, so the difference between the spread captured and the costs paid decides everything. On this page's bar-level run, 21,637 round trips cost $8,564 in fees on a $10,000 account. A realistic fee and slippage model is non-negotiable at this trade count.