Deterministic Replay
The quantpylib replay system is a deterministic replay kernel for institutional-grade backtest simulation. It is designed so live trading and simulation use a unified code interface, reducing the margin for error created by implementation gaps between research and production.
See the market-making tutorial for a tutorial on how to write market making code using the replay's runtime.
Live and replay runtime domains
In replay mode, ReplayRuntime is injected into the OMS. It schedules asynchronous work on the replay kernel's deterministic event heap. The replay clock therefore synchronizes historical market-data delivery and strategy events. This allows the replay and the live strategy to share code.

This architecture preserves several properties required for high-fidelity simulation:
- Avoid last-mile regressions. The same strategy methods, Feed callbacks, OMS wiring, portfolio mirrors, and cancellation paths run in replay and production. A strategy change exercised in replay therefore reaches live execution through the same business-logic path, avoiding implementation drift.
- Determinism and receive-time fidelity. Market events retain and deliver at the timing observed by the actual user's tick-data capture. Bursts, backpressure and jitter are as-was.
- Exchange-specific RX and TX latency simulation. Public data, outbound orders and cancels, responses, and private updates can travel through separately configured latency paths for each exchange.
- Configurable queue and impact policies. Queue placement, cancellations and the relationship between simulated private orders and historical public depth can be modelled.
- Production-grade event journals and artefacts. Replay uses the same performant logging and journaling path to generate trace artefacts for simulation-fidelity review and strategy analysis.
See the component references for the individual replay domains:
replay_exchangeowns authoritative venue, matching, order, fill, and position state.replay_wrapperexposes the simulated venue client through the Gateway-compatible methods and applies RX/TX latency on actions.replay_orderbookprojects public MBP (L2) book into MBO (L3) book with impact and queue policies.replay_streamrestores bounded timestamp disorder into deterministic key order.
Before the API reference - we want to show a simple diagram of how the replay kernel performs scheduling through an order submission and two market data events.
sequenceDiagram
participant QBN as QBNReplay
participant Heap as ReplayRuntime heap
participant Strategy
participant Exchange as ReplayExchange
participant Wrapper as ReplayWrapper
participant OMS as OMS order mirror
QBN->>Heap: Directly schedule QBN data 1 for ts = 1
QBN->>Heap: Directly schedule QBN data 2 for ts = 2
Heap->>Strategy: At ts = 1 deliver QBN data 1 through Feed
Strategy->>Wrapper: limit_order()
Wrapper->>Heap: runtime.sleep_ns(submit_order.TX)
Heap->>Heap: Create Future and schedule wake at ts = 1 + submit_order.TX
Note over Wrapper: submit_order awaits Future<br/>ReplayRuntime continues draining due events
Heap->>Exchange: At ts = 2 deliver QBN data 2
Heap-->>Wrapper: At ts = 1 + submit_order.TX resolve Future
Wrapper->>Exchange: submit_order()
Exchange-->>Wrapper: Emit private order update
Wrapper->>Heap: create_task(deliver_acknowledgement)
Wrapper->>Heap: runtime.sleep_ns(order_ack.RX)
Heap->>Heap: Create Future and schedule wake at ts = submit_ts + order_ack.RX
Note over Wrapper: Acknowledgement task awaits Future<br/>ReplayRuntime continues
Heap-->>Wrapper: At ts = submit_ts + order_ack.RX resolve Future
Wrapper->>OMS: Deliver private order acknowledgement
API reference
Deterministic public market-data replay over QBN archives.
QBNReplay
Stream deterministic exchange-time and receive-time QBN routes.
Each decoded source record may produce an exchange route ordered by
ts_exch_ns and a client route ordered by ts_recv_ns. The global
merge key is (delivery_ns, route, source_id, source_ordinal).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sources
|
iterable[ReplaySource]
|
Non-empty set of uniquely identified QBN sources. Paths and source IDs must both be unique. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
out_of_order_counts |
dict[int, int]
|
Late client-route counts by
source ID from the latest
|
exchange_out_of_order_counts |
dict[int, int]
|
Late exchange-route counts by source ID from the latest iteration. |
__init__(sources)
Validate sources and open the matching QBN readers.
events(*, data_iter_buffer=1000, include_client=True, start_ns=None, end_ns=None, symbols=None)
Yield merged exchange-time and receive-time routes.
Exchange routes use bounded lookahead to repair nearly ordered exchange timestamps. Client routes use zero lookahead and therefore preserve receive-order causality while dropping backward timestamps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_iter_buffer
|
int
|
Records buffer protection against out-of-order. |
1000
|
include_client
|
bool
|
Emit client RX routes in addition to exchange. |
True
|
start_ns
|
int
|
Inclusive route-time lower bound. |
None
|
end_ns
|
int
|
Exclusive route-time upper bound. |
None
|
symbols
|
str or iterable[str]
|
Tickers to retain. |
None
|
Yields:
| Name | Type | Description |
|---|---|---|
tuple |
``(delivery_ns, route, source_id, source_ordinal, |
|
|
ReplayEvent)`` in deterministic order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
from_paths(paths)
classmethod
Build a replay whose source precedence follows path order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
path - like or iterable[path - like]
|
QBN archive paths. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
QBNReplay |
Replay with sequential source IDs beginning at zero. |
source_headers()
Return copied QBN headers keyed by configured source ID.
Returns:
| Type | Description |
|---|---|
|
dict[int, dict]: Source metadata safe for caller mutation. |
ReplayClock
Nanosecond clock domain advanced by the replay kernel.
Strategy code receives this object through ReplayRuntime.
__init__()
Create an unstarted replay clock.
now_ns()
Return current replay time in nanoseconds.
Returns:
| Name | Type | Description |
|---|---|---|
int |
Current deterministic timestamp. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the replay clock has not been primed or started. |
ReplayError
Bases: Exception
Base error for deterministic QBN replay.
ReplayEvent
dataclass
A native QBN event with deterministic replay context.
source_ordinal is the zero-based physical record position within one
source, including records excluded by replay filters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delivery_ns
|
int
|
Timestamp at which this route is delivered. |
required |
source_id
|
int
|
Stable cross-source priority. |
required |
source_ordinal
|
int
|
Physical record position in the source. |
required |
feed_id
|
FeedId
|
Venue, market class, feed type, and ticker identity. |
required |
event
|
object
|
Decoded native QBN market-data event. |
required |
ReplayNode
Compose deterministic QBN tick data backtest through Gateway and Feed.
One ReplayExchange owns
venue truth for each exchange and one
ReplayWrapper exposes that
venue through the standard gateway
boundary. runtime is injected into OMS so strategy,
transport, and portfolio states share the replay clock domain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
replay
|
QBNReplay or iterable[ReplaySource]
|
Configured replay input. |
required |
data_iter_buffer
|
int
|
Records buffer protection against out-of-order. |
1000
|
exchange_kwargs
|
dict
|
Per-venue keyword arguments for
|
None
|
wrapper_kwargs
|
dict
|
Per-venue keyword arguments for
|
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
clock |
ReplayClock
|
Deterministic clock. |
runtime |
ReplayRuntime
|
Strategy and OMS scheduler. |
exchanges |
dict[str, ReplayExchange]
|
Venue truth by alias. |
clients |
dict[str, ReplayWrapper]
|
Gateway transports by alias. |
gateway |
Gateway
|
Normalized gateway over replay clients. |
feed |
Feed
|
Normal production feed over the replay gateway. |
__init__(replay, *, data_iter_buffer=1000, exchange_kwargs=None, wrapper_kwargs=None)
Validate QBN compatibility and build the replay component graph.
cleanup()
async
Close feed sinks and replay gateway clients.
from_qbn(paths, **kwargs)
classmethod
Create a node from QBN paths in precedence order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
path - like or iterable[path - like]
|
QBN inputs. |
required |
**kwargs
|
Additional
|
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
ReplayNode |
Fully composed, uninitialized node. |
init()
async
Initialize clients and prime state timestamps to QBN time.
Raises:
| Type | Description |
|---|---|
ReplayError
|
If the configured replay has no events. |
run(*, start_ns=None, end_ns=None, symbols=None, include_client=True)
async
Run the deterministic replay kernel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_ns
|
int
|
Inclusive route-time lower bound. |
None
|
end_ns
|
int
|
Exclusive route-time upper bound. |
None
|
symbols
|
str or iterable[str]
|
Tickers to retain. |
None
|
include_client
|
bool
|
Deliver client routes to subscribed feeds. |
True
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the node is already running. |
ReplayError
|
If replay scheduling or source ordering fails. |
ReplayOrderError
Bases: ReplayError
Replay input or scheduled work cannot satisfy time ordering.
ReplayRuntime
Schedule asynchronous work on the replay kernel.
Implements the clock and scheduling interface used by OMS and strategy
code. Client code should use the runtime appropriate to its execution mode.
In production,
AsyncioRuntime schedules
gather, create_task, sleeps, and periodic work on the asyncio event
loop. In replay, ReplayRuntime schedules the same work on the
deterministic event heap and advances it using replay time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clock
|
ReplayClock
|
Clock advanced as scheduled callbacks are drained. |
required |
__init__(clock)
Initialize an empty scheduler over clock.
call_at_ns(when_ns, callback)
Schedule a callback at an absolute replay timestamp.
Equal timestamps execute by insertion order. A callback may return an awaitable, a tracked future, or a non-awaitable result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
when_ns
|
int
|
Absolute deterministic timestamp. |
required |
callback
|
callable
|
Zero-argument callback. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
Event identifier used internally for cancellation tracking. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ReplayOrderError
|
If active replay work is scheduled in the past. |
call_later_ns(delay_ns, callback)
Schedule a callback relative to current replay time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delay_ns
|
int
|
Non-negative delay in nanoseconds. |
required |
callback
|
callable
|
Zero-argument callback. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
Scheduled event identifier. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
create_task(coro, *, name=None, daemon=False)
Create and track an asyncio task as replay work.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coro
|
coroutine
|
Coroutine to execute. |
required |
name
|
str
|
Asyncio task name used in diagnostics. |
None
|
daemon
|
bool
|
Whether the task may be abandoned when all non-daemon replay work is complete. |
False
|
Returns:
| Type | Description |
|---|---|
|
asyncio.Task: Registered task. |
every(interval_sec, callback, *, name=None)
Schedule a daemon callback at a fixed replay-time interval.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interval_sec
|
float
|
Non-negative interval in seconds. |
required |
callback
|
callable
|
Awaitable callback invoked after each interval. |
required |
name
|
str
|
Diagnostic task name. |
None
|
Returns:
| Type | Description |
|---|---|
|
asyncio.Task: Daemon loop task. |
gather(*aws, return_exceptions=False)
async
Join awaitables while preserving replay task accounting.
Outside an active run this delegates directly to asyncio.gather.
During replay, coroutine children are converted to tracked tasks and
the tracked parent is marked waiting until they finish.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*aws
|
Awaitables to execute concurrently. |
()
|
|
return_exceptions
|
bool
|
Match |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
list |
Results in input order. |
Raises:
| Type | Description |
|---|---|
ReplayError
|
If called by an untracked active task or passed an untracked future during replay. |
now_ns()
Return the current deterministic timestamp in nanoseconds.
Returns:
| Name | Type | Description |
|---|---|---|
int |
Current replay time. |
reset()
Clear completed scheduler state and unstart the clock.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the runtime is active or still owns tasks. |
run()
async
Advance time and drain deterministic non-daemon work.
The clock advances to each heap timestamp, callbacks run in insertion order, and tracked tasks settle between scheduling boundaries. On any failure, outstanding tasks are cancelled before the error is reraised.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If this runtime is already running. |
ReplayError
|
If work escapes runtime scheduling or waits without a scheduled wake-up. |
BaseException
|
Any unjoined callback or task failure. |
sleep(seconds)
async
Suspend the current replay task for deterministic seconds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
Non-negative duration in seconds. |
required |
sleep_ns(delay_ns)
async
Suspend the current replay task for deterministic nanoseconds.
During an active run, only tasks registered by
create_task() may
sleep. Cancellation removes the pending wake-up from effective work.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delay_ns
|
int
|
Non-negative delay in nanoseconds. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
ReplayError
|
If an untracked task sleeps during an active run. |
ReplaySource
dataclass
One explicitly ordered QBN input source.
source_id is the stable cross-source tie-break priority; lower values
replay first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
path - like
|
QBN archive path. |
required |
source_id
|
int
|
Unique deterministic priority for this source. |
required |
__post_init__()
Validate the source priority and normalize path to Path.