Manifold-BT vs hftbacktest
hftbacktest is the open-source reference for backtesting a market maker on tick data: a Rust core, strategies written in Python and compiled with Numba, level-2 and level-3 books, queue position and latency models, and live bots for Binance Futures and Bybit. Manifold-BT added the same kind of simulation to its research library in 0.27.0, on the Researcher plan. Both say they model the queue, so instead of arguing about it we gave them the same quotes and counted how often they agree. If you are weighing an hftbacktest alternative in Python, those counts are the place to start.
The same quotes, two engines
Tick backtests disagree most about the queue, since a level-2 book shows a level shrinking but never whose order left. Manifold-BT's three level-2 queues are hftbacktest's own formulas, reproduced rather than approximated so the two can be compared fill by fill: risk_adverse is its RiskAdverseQueueModel, power its PowerProbQueueModel, log its LogProbQueueModel. On three BTCUSDT perpetual days, the same quotes went to both engines, each living one bar. hftbacktest read Bybit's archives through its own converter and Manifold-BT through its own reader; neither touched the other's files. Agreement is per quote, at zero latency:
| Day | Queue model | Agreement | Quotes | Filled, Manifold-BT | Filled, hftbacktest |
|---|---|---|---|---|---|
| 2025-08-13 | risk_adverse | 99.994% | 15,415 | 1,653 | 1,654 |
| 2025-08-13 | power, n=3 | 99.974% | 15,415 | 1,654 | 1,656 |
| 2025-08-13 | log | 99.955% | 15,415 | 1,657 | 1,658 |
| 2025-08-23 | risk_adverse | 99.994% | 16,745 | 733 | 732 |
| 2025-08-23 | power, n=3 | 99.970% | 16,745 | 736 | 735 |
| 2025-08-23 | log | 99.964% | 16,745 | 738 | 736 |
| 2025-08-30 | risk_adverse | 100% | 17,232 | 740 | 740 |
| 2025-08-30 | power, n=3 | 99.983% | 17,232 | 740 | 741 |
| 2025-08-30 | log | 99.994% | 17,232 | 740 | 741 |
Latency does not pull them apart either. A maker quoting both sides every second, written for Manifold-BT's simulator (bt.sim) and for hftbacktest 2.4.4 with partial fills and the risk-averse queue, agrees on 99.990% to 99.998% of 518,382 quotes, at every latency tested from 0 to 500 ms.
On order-by-order data
Level 3 is the harder test. A day of Nasdaq TotalView-ITCH for AAPL and QQQ (2025-12-09) went to hftbacktest as its own order-by-order events, run with l3_fifo_queue_model and no_partial_fill_exchange. Every 100 ms, both engines cancel their quotes and post two new post-only ones at the best bid and ask, so the quotes depend only on the book and each one gets a verdict in each engine. At zero latency:
| Symbol | Quotes | Only in hftbacktest | Filled, same instant | Filled earlier in Manifold-BT | Only in Manifold-BT |
|---|---|---|---|---|---|
| AAPL | 467,998 | 0 | 7,659 | 1,330 | 464 |
| QQQ | 467,998 | 0 | 69,995 | 799 | 55 |
hftbacktest never fills a quote that Manifold-BT leaves unfilled. Every difference runs the other way and comes from one rule, the third one below. With 50 µs of feed latency and 100 µs on orders, the counts barely move: 7,662 and 70,017 quotes filled at the same instant. The full tables and the traced disagreements are in the public strategy authoring guide.
Where they disagree, and why
The risk-averse disagreements and those of the two makers were traced quote by quote on the raw event stream. Apart from one print stamped at the very instant a quote left the book, which the harness driving hftbacktest counted, each comes from a rule the two engines state differently. The three to six a day left on the probabilistic queues have not been traced yet.
- A print on your own side. When a buyer trades below your bid, the level you rest on has been emptied, so Manifold-BT fills your bid. hftbacktest reads only the prints of the other side against a bid, and does not.
- A book update filed before its print. When the book state that already shows a trade comes before the trade itself, hftbacktest counts that trade twice in its queue. Manifold-BT puts the prints of an instant before the state that shows them.
- An order alone at a better price (L3). Once the orders ahead of yours have executed, yours can be the only one left at its price, better than the rest of the market. hftbacktest fills an order through its price only if that price lies between the market's best price, your own orders left out, and the traded price. A lone order at a better price lies outside that range, so an execution one tick further does not reach it. The quote fills later, when an order entering the other side crosses it (a median of 58 µs later on AAPL, 47 µs on QQQ), or not at all if none does before the quote is cancelled. Manifold-BT fills it at that execution, because the aggressor who paid a worse price met your order first.
- Partial fills (L3). hftbacktest's level-3 exchange fills the whole order or nothing. Manifold-BT fills as much as an execution takes: at 100 shares a quote, 1,704 quotes on AAPL and 5,425 on QQQ fill for a different size.
How far does a whole strategy drift because of them? Take a maker whose quotes depend on its inventory: at the best bid and ask every 100 ms, a side withdrawn at five lots of inventory or when the best level's imbalance runs against it by more than 0.6. Written with Strategy.quote in Manifold-BT and in Numba for hftbacktest, one share a quote, zero latency and no fee, the two runs part at their first different fill and end here:
| Symbol | P&L, Manifold-BT | P&L, hftbacktest | Fills, Manifold-BT | Fills, hftbacktest |
|---|---|---|---|---|
| AAPL | -47.32 | -46.55 | 7,146 | 6,952 |
| QQQ | -77.74 | -78.08 | 43,077 | 43,041 |
Both lose money, which a maker this simple does on these days. They lose it to within a dollar of each other, and both finish the day with the same position (-4 shares on AAPL, -5 on QQQ).
Side by side
| Manifold-BT | hftbacktest | |
|---|---|---|
| Licence | Community is free on PyPI (Apache 2.0 with Commons Clause); the tick layer is on the Researcher plan | MIT, free and open source |
| Strategy code | A few DSL expressions per quote, compiled once by the Rust engine, or a Python function per wake-up with bt.sim | Your own event loop, in Python compiled with Numba, or in Rust |
| Market data | Reads the Binance and Bybit archives and Nasdaq ITCH 5.0 days straight into its store | Converters for Binance, Bybit, Hyperliquid, MEXC, Tardis and Databento into its own event arrays |
| L2 queue models | risk_adverse, power and log: hftbacktest's formulas, reproduced | RiskAdverse, PowerProb and LogProb, with a few variants |
| L3 (market by order) | Exact FIFO queue, with partial fills | FIFO queue, whole fills only |
| Latency | Four delays: order, cancel, response and feed | Constant, or interpolated from a recorded order-latency log; feed latency from the data's timestamps |
| Beyond the tick run | Bar backtests, parameter sweeps across every core and GPU, walk-forward and Monte Carlo in the same library | Tick simulation; sweeps and validation are your own code |
| Live trading | No, research only | Yes, Binance Futures and Bybit, from Rust |
| Latest release | 0.27.0, October 2026 | 2.4.4 on PyPI, December 2025 |
A queue-aware maker in a few expressions
In hftbacktest you write the event loop: wait for the next event, read the depth, cancel and post, all inside a Numba function. In Manifold-BT a quote is three expressions, where to stand, how much, and whether to stand at all. The engine compiles them once and runs the day without calling back into Python, and a strategy written this way sweeps like any other. The queue below is hftbacktest's PowerProbQueueModel with n = 3, under the name Manifold-BT gives it:
import manifoldbt as bt
from manifoldbt import book
from manifoldbt.helpers import Interval, time_range
# One day of Bybit's free BTCUSDT perpetual archives: the tape and the book
store = bt.ingest_trades("bybit", "BTCUSDT", symbol_id=1,
start="2025-08-13", end="2025-08-13", category="linear")
bt.ingest_book("bybit", "BTCUSDT", symbol_id=1,
start="2025-08-13", end="2025-08-13", category="linear")
CLIP, MAX_INVENTORY = 0.01, 0.05
inventory = bt.position()
book_ok = (book.bid_levels() > 0) & (book.ask_levels() > 0)
# Join the best bid and ask, post-only, within an inventory limit
strategy = (
bt.Strategy.create("maker")
.quote("buy", bt.when(book_ok, book.bid_price_at(1)), CLIP, tif="GTX",
enabled=inventory < MAX_INVENTORY - 1e-12)
.quote("sell", bt.when(book_ok, book.ask_price_at(1)), CLIP, tif="GTX",
enabled=inventory > -MAX_INVENTORY + 1e-12)
)
start, end = time_range("2025-08-13", "2025-08-14")
config = bt.BacktestConfig(
universe=[1], time_range_start=start, time_range_end=end,
bar_interval=Interval.millis(100), # the wake-up clock
initial_capital=100_000.0,
fees=bt.FeeConfig(maker_fee_bps=2.0, taker_fee_bps=5.5),
execution=bt.ExecutionConfig(
latency={"order": Interval.millis(5), "cancel": Interval.millis(5),
"response": Interval.millis(5), "feed": Interval.millis(2)},
# hftbacktest's PowerProbQueueModel with n = 3, under its name here
fill_model={"queue": {"model": "power", "n": 3.0, "depth_source": "book"}},
),
)
result = bt.run(strategy, config, store)
result.fills_df()When the decision does not fit in expressions, bt.sim hands the venue to a Python function instead, closer to the hftbacktest way of working, and on the same days the two give the same order journal, fill for fill. Where the data comes from, and what each archive holds, is in free crypto tick data and MBO, MBP and BBO order book data.
When hftbacktest is the right call
When the backtest is a step toward a live bot on Binance Futures or Bybit, and you want the simulator and the bot to share their code, hftbacktest does that and Manifold-BT does not, on purpose. It is also the answer if you need an MIT licence, want to change the simulator itself in Rust, or already have strategies written in Numba. And it is free, while the tick layer of Manifold-BT is a paid plan.
Which should you pick?
Pick Manifold-BT if the market maker is one strategy among the ones you research. The tick run sits in the same library as your bar backtests, sweeps and walk-forward; it reads the free crypto archives and the ITCH days itself; and on level 3 it fills orders partially, at the execution that reached them. You give up nothing on the queue, since the models are hftbacktest's and the verdicts agree on more than 99.95% of quotes. Pick hftbacktest if the goal is a live bot on the venues it connects to, or if the budget is zero. The tick layer is described on the Researcher plan page.
Frequently asked questions
Does Manifold-BT give the same results as hftbacktest?
Close to it, and measured. With the same queue model on the same BTCUSDT quotes, the two engines agree on 99.955% to 100% of quotes, and a two-sided maker agrees on 99.990% to 99.998% of 518,382 quotes at latencies from 0 to 500 ms. On a Nasdaq level-3 day, hftbacktest never fills a quote that Manifold-BT leaves unfilled. What is left comes from rules each engine states, such as how a print on your own side or a partial fill is handled.
Is hftbacktest free? Is Manifold-BT?
hftbacktest is MIT-licensed and free. Manifold-BT's Community edition is free on PyPI, but the tick layer it is compared on here (trades, order book, queue models, level-3 data) is part of the paid Researcher plan.
Can Manifold-BT trade live like hftbacktest?
No. Manifold-BT is a research library and places no orders. hftbacktest has live connectors for Binance Futures and Bybit, written in Rust. If the goal is a live bot on one of those venues that shares its code with the backtest, that is a good reason to choose hftbacktest.
Does Manifold-BT support level-3 (MBO) data like hftbacktest?
Yes. It reads Nasdaq TotalView-ITCH 5.0 days order by order with ingest_mbo, and the place of an order in its queue is then read from the data instead of estimated. Unlike hftbacktest's level-3 exchange, it fills an order partially when an execution takes only part of it.
Keep reading
- The Researcher plan: the tape, the book, the trade clock →
- MBO, MBP and BBO: order book data, level by level →
- Free crypto tick data, and how to backtest it →
- Market making strategy in Python →
- Execution Realism →
- Manifold-BT vs RaptorBT →
- Manifold-BT vs Freqtrade →
- Manifold-BT vs vectorbt →
- Manifold-BT vs Backtrader →
- Manifold-BT vs NautilusTrader →
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.