Python API / native extension

Broker & replay

Complete stock, futures, and option replay APIs: event tuples, order methods, execution rules, account state, and causal visibility.

Broker support by instrument

Execution APIs by family
InstrumentReplay classOrder APIState / policy
StocksSimpleMarketset_desired, buy, sellMarket or middle execution; cash, positions, shared TradeEmulator.
FuturesFuturesMarketbuy, sellMarket orders; execution ledger. No set_desired, shared TradeEmulator, or position book.
OptionsOptionMarketbuy, sellOne contract per replay; market orders and execution ledger. No set_desired or position book.
CryptoNo built-in market/brokerTrade reader and database only.
Currencies / forexNo built-in market/brokerQuote reader and database only.
IndicesNo built-in market/brokerValue reader and database only.

All three market classes read local trade and quote databases, even with quotes=False. They require the native extension and configured MASSIVE_SPEEDUP_DB_PATH or an explicit database_path. They do not connect to a live broker or fetch missing data. Brokers are supplied by the iterator; they have no public constructor.

The event loop contract

for instrument, timestamp, trade, quote, trades, quotes, broker in market:
    ...
Every market iteration yields this 7-tuple
ElementMeaning
instrumentStock/futures symbol string; option contract key string.
timestampCurrent event time as float seconds since epoch. Stock/options use SIP time; futures use the event's timestamp.
tradeThe current typed trade record, or None on a quote event.
quoteThe current typed quote record, or None on a trade event. To get the latest quote on a trade event, consult the quotes dictionary.
tradesDictionary mapping instrument keys to their most recent observed trade. Unseen instruments have no entry.
quotesDictionary mapping instrument keys to their most recent observed quote. Unseen instruments have no entry.
brokerA broker bound to the current event's instrument and integer nanosecond timestamp.

quotes=False emits trade events while still advancing quote state. quotes=True emits both. For a given instrument and equal timestamp, quotes precede trades. Stock/futures ties between instruments are ordered by the input symbol list, so not every other symbol's equal-time event has necessarily been observed yet.

fast=False creates fresh recent-record dictionaries for each yielded event. fast=True reuses and mutates the same dictionaries; copy them if you retain a snapshot. These dictionaries contain observed market records, independent of the simulator's execution quote lookup.

iter(market) returns the market itself. next(market) advances; StopIteration marks exhaustion. It cannot be rewound; create another market to replay again. market.broker provides the current event's broker and raises IndexError before the first event or after exhaustion. Use the newly yielded broker each iteration; retaining an old broker retains its old timestamp.

Read integer timestamps from records or broker properties when nanosecond precision matters. Do not pass the tuple's floating-point seconds directly to database searches, which expect nanoseconds.

SimpleMarket — stocks

ms.SimpleMarket(date, symbols, trade_latency_ns=150000000, *,
    database_path=None, quotes=False, fast=False, trade_emulator=None,
    execution="market", passivity=0.0, unit_shares=1.0)
Stock market parameters
ParameterMeaning
dateYYYY-MM-DD string or datetime.date of the local session.
symbolsSequence of exact stock ticker strings with both trade and quote databases.
trade_latency_ns=150000000Nonnegative integer delay from decision time to simulated execution time (150 ms).
database_path=NoneExplicit database root or environment default.
quotes=FalseWhether to emit quote events as well as trades.
fast=FalseWhether recent-record dictionaries are reused.
trade_emulator=NoneCreate a fresh stock book, or share an existing TradeEmulator across sessions. Execution settings are then owned by the supplied emulator.
execution="market""market" or "middle" for position-target orders.
passivity=0.0Finite nonnegative limit-placement coefficient for middle execution. No upper cap.
unit_shares=1.0Positive finite shares per desired position unit.

Read-only properties: broker, trade_emulator, trade_latency_ns, execution, passivity, unit_shares. market["AAPL"] returns held shares, and market[None] returns cash. A fresh book starts at zero cash and zero positions. market.summary() returns the session's ledger and the current book only after exhaustion.

When supplying trade_emulator, its execution, passivity, and unit size take precedence over the corresponding market arguments. The default latency argument defers to the emulator; an explicitly nondefault, inconsistent latency raises ValueError.

Replay stock updates with a one-share target
import massive_speedup as ms

market = ms.SimpleMarket(
    "2026-09-11", ["AAPL"],
    trade_latency_ns=150_000_000, quotes=True,
)
for symbol, timestamp, trade, quote, trades, quotes, broker in market:
    if trade is not None:
        broker.set_desired(1)

print(market.summary())

SimpleMarketBroker

broker.set_desired(desired: float, symbol=None) -> None
broker.buy(shares: float, symbol=None) -> None
broker.sell(shares: float, symbol=None) -> None

Read-only symbol identifies the bound stock; sip_timestamp is the decision timestamp in integer nanoseconds. symbol=None targets the current instrument. An explicit symbol must belong to the market; a bar-aggregator broker accepts only its own symbol.

Stock orders
MethodMeaning
set_desired(+1)Target +unit_shares shares.
set_desired(0)Target a flat position.
set_desired(-1)Target −unit_shares shares.
buy(shares)Add this quantity by crossing at the ask, regardless of the configured execution mode.
sell(shares)Sell this quantity at the bid, regardless of the configured execution mode.

Only −1, 0, and +1 are accepted as desired values. Repeating the same target does not keep buying shares; the emulator trades the difference from its current holding or maintains an existing working order. buy and sell are quantity commands: repeating them submits another quantity.

Quantity must be finite and nonnegative. Stock quantities at or below the emulator's 1e-12 tolerance are no-ops. Invalid values raise ValueError, unknown symbols raise IndexError, and submissions through a market broker after exhaustion raise RuntimeError. All three methods return None; inspect fills and rejections after replay.

How execution is calculated

For a decision at integer time t, the simulator looks up the last quote whose primary timestamp is at or before t + trade_latency_ns. The recorded execution timestamp is t + latency; the recorded quote timestamp is the timestamp of the actual quote used and may be earlier. This lookup is evaluated internally when the order is processed; it does not advance the strategy's event iterator to that later time.

Stock position-target execution modes
ModePlacement / triggerFill
"market"Trade the target-position difference using the quote at decision time plus latency.Buy at ask; sell at bid.
"middle", passivity=0Use the same marketable path.Buy at ask; sell at bid.
"middle", passivity>0Compute and maintain a limit using the looked-up quote. Poll as trade/quote events advance.Buy when ask ≤ limit; sell when bid ≥ limit. Fill the full remaining quantity at the touch.
buy_limit  = ask - passivity * (ask - bid)
sell_limit = bid + passivity * (ask - bid)

Passivity 0 places at the touch, 0.5 at the midpoint, 1 at the opposite side (buy bid / sell ask), and values above 1 beyond that side. There is no free midpoint fill: the quote must become marketable relative to the stored limit. Limit placement and polling use the quote lookup at the decision/poll time plus latency, so these are simulator operations, not current-event observations.

A changed desired target cancels a previous working order and creates a new one when required. Unchanged targets retain the working limit. SimpleMarket polls automatically on every trade and quote, including quotes that are not emitted. The remaining working limits are cancelled when the last attached stock session ends; positions and cash remain open.

A missing execution quote records reason="no_quote". A non-finite or nonpositive execution-side price records reason="unusable_price". Middle-mode quote validation additionally requires positive finite bid and ask with ask ≥ bid. Market orders validate the execution side; there is no staleness cutoff or displayed-size capacity check.

This is a quote-based execution model. It does not model queue priority, partial fills, fees, borrow availability, margin, auctions, market impact, or instrument-specific contract multipliers. Cash flow is quantity × reported price. In particular, futures and option ledger notionals do not apply a contract multiplier.

TradeEmulator — stock account and execution policy

ms.TradeEmulator(trade_latency_ns=150000000, execution="market",
    passivity=0.0, unit_shares=1.0)

The stock emulator owns execution policy, the order ledger, desired targets, cash, positions, and resting limits. Reuse one across chronological SimpleMarket sessions or attach it to a stock trade aggregator. It is not accepted by FuturesMarket or OptionMarket.

Read-only properties and account lookup
MemberReturns
trade_latency_nsInteger latency in nanoseconds.
execution"market" or "middle".
passivityConfigured nonnegative finite float.
unit_sharesConfigured positive finite float.
cashCurrent simulated cash; starts at 0.
working_order_countNumber of currently resting stock orders.
position(symbol)Held shares as a float; zero for an unseen symbol.
desired_position(symbol)Last desired unit value; zero if never set.
emulator[symbol] / emulator[None]Position / cash respectively.
summary()Full cumulative ledger and account summary, available immediately; unlike market.summary(), this method has no exhaustion gate.
emulator.set_desired(symbol, desired, sip_timestamp, quotes,
                     quote_index_hint=-1) -> int
emulator.poll_working(symbol, sip_timestamp, quotes,
                      quote_index_hint=-1) -> int
emulator.working_order(symbol) -> dict | None
emulator.force_close_at(symbol, price, timestamp_ns=0,
                        style="moc_approx") -> None
Direct emulator methods
Method / argumentContract
set_desiredApply the stock target policy at the supplied integer nanosecond decision time using a StockQuoteDatabase. Returns the updated execution-quote search index.
poll_workingRecheck a resting limit without changing desired position. Returns the updated execution-quote search index.
quote_index_hint=-1Prior execution quote index for a nearby search, or −1 for no hint. Retain per symbol/quote file; never use this later-time index as a strategy observation.
working_order(symbol)None if absent, otherwise a dictionary with instrument, side, remaining, limit_price, target_shares, submitted_timestamp.
force_close_atCancel a resting order, reset desired to zero, and flatten at an explicit positive finite price. Does not need a quote database; style labels the resulting fill.
timestamp_ns=0Timestamp to record for the explicit-price close. Supply the actual observable close time for meaningful accounting.

Direct calls are advanced APIs. Drive them in chronological order, pass the matching quote database for each symbol, and serialize mutations of a shared book. There is no public method to reset an emulator or seed a starting balance; construct a fresh emulator to start again.

Carry a one-share stock book across two sessions
import massive_speedup as ms

emulator = ms.TradeEmulator(unit_shares=1)
for day in ("2026-09-10", "2026-09-11"):
    market = ms.SimpleMarket(day, ["AAPL"], trade_emulator=emulator)
    for symbol, timestamp, trade, quote, trades, quotes, broker in market:
        broker.set_desired(1)

print(emulator.summary())

Exhaust each session before moving to the next date. Cash, holdings, desired targets, and the ledger carry over; working limits do not carry past the end of the last active session. Session market.summary() reports that session's orders alongside the cumulative stock account, while emulator.summary() includes all orders.

Broker access from stock trade bars

ms.StockTradeAggregator(rows, interval_seconds, *,
    start_timestamp=None, quotes=None, trade_emulator=None)

Provide both a StockQuoteDatabase and a TradeEmulator to attach execution to stock trade aggregation. Both omitted gives ordinary aggregation; only one supplied raises ValueError. A matching stock trade database or typed stock trade iterable supplies the bars.

bars.broker is a SimpleMarketBroker for the current bar's instrument, with decision time bar.window_start + interval_ns. It becomes available after a bar is yielded and is unavailable before iteration, after StopIteration, or without the two execution arguments. bars.trade_emulator exposes the attached emulator or None.

Make a decision only after each minute bar closes
import massive_speedup as ms

trades = ms.StockTradeDatabase("2026-09-11", "AAPL")
quotes = ms.StockQuoteDatabase("2026-09-11", "AAPL")
emulator = ms.TradeEmulator()
bars = ms.StockTradeAggregator(
    trades, 60, start_timestamp=trades.market_open,
    quotes=quotes, trade_emulator=emulator,
)
for bar in bars:
    bars.broker.set_desired(1 if bar.close > bar.open else 0)

del bars  # Release the aggregator's attached session.
print(emulator.summary())

The aggregator keeps its attached session alive until the aggregator is destroyed, even after bar iteration is exhausted. Releasing it lets the emulator end the session and cancel working limits when no other sessions remain. A saved broker must not outlive its aggregator, because it references that aggregator's quote-search state. No other instrument's aggregator exposes a broker.

FuturesMarket and FuturesMarketBroker

ms.FuturesMarket(date, symbols, trade_latency_ns=150000000, *,
    exchange="", database_path=None, quotes=False, fast=False)

date is the session end date (ISO string or datetime.date); symbols contains the exact stored contract tickers. exchange selects "" for generic futures directories or one of "cbot", "cme", "comex", "nymex" for the corresponding exchange directories. The other parameters have the event-loop meanings described above.

Yields FuturesTrade / FuturesQuote records ordered by timestamp. Both record types can carry a session_end_date that includes the prior evening's observations. The first tuple field and recent-record dictionary keys are contract ticker strings. Market members are broker, summary(), __iter__, and __next__.

broker.buy(contracts: float, symbol=None) -> None
broker.sell(contracts: float, symbol=None) -> None

The broker exposes symbol, timestamp, and sip_timestamp read-only; the latter is an alias of the futures timestamp for interface compatibility, not a separate SIP field. The optional symbol must be in the market's symbol list. Quantities must be finite and nonnegative; futures calls record zero-quantity orders rather than applying the stock emulator's near-zero no-op rule.

Futures execution crosses the spread using the last quote at or before event time plus latency. There is no set_desired, limit mode, shared stock emulator, market[symbol], or account book. summary() is gated until exhaustion and reports orders and raw cash flow; it does not return cash or positions.

Submit one futures market order during replay
import massive_speedup as ms

market = ms.FuturesMarket("2026-09-11", ["0BTZ9"], exchange="cme")
sent = False
for symbol, timestamp, trade, quote, trades, quotes, broker in market:
    if not sent:
        broker.buy(1)
        sent = True

print(market.summary())

OptionMarket and OptionMarketBroker

ms.OptionMarket(date, root, expiration, right, strike,
    trade_latency_ns=150000000, *, database_path=None,
    quotes=False, fast=False)

Replays one option contract. date is the observation session, root the underlying, expiration its YYYY-MM-DD expiration string, right is C or P, and strike is rounded to thousandths as in the option database constructors. It reads both contract trade and quote files.

Yields OptionTrade / OptionQuote in SIP order. Instrument and recent-record dictionary keys use ROOT/EXPIRATION/RIGHT/SSSSSSSS, for example AAPL/2026-09-18/C/00150000. Market members are broker, summary(), __iter__, and __next__.

broker.buy(contracts: float) -> None
broker.sell(contracts: float) -> None

Read-only broker.contract is the contract key string and broker.sip_timestamp is integer nanoseconds. There is no symbol override because a market holds one contract. Quantities must be finite and nonnegative; zero-quantity calls still produce an order record. Orders use the same latency-adjusted ask/bid lookup as futures.

Options have no set_desired, resting-limit policy, shared TradeEmulator, or position book. summary() requires exhaustion and provides the ledger and raw quantity × quote-price cash flow; no 100-share multiplier, exercise, assignment, or expiration settlement is applied.

Submit one option market order during replay
import massive_speedup as ms

market = ms.OptionMarket("2026-09-11", "AAPL", "2026-09-18", "C", 150.0)
sent = False
for contract, timestamp, trade, quote, trades, quotes, broker in market:
    if not sent:
        broker.buy(1)
        sent = True

print(market.summary())

Summary and order record fields

All market summary() methods raise RuntimeError until the iterator is exhausted. Stock TradeEmulator.summary() is the lower-level exception: it can be read at any time. The following fields describe dictionaries, not record classes.

Summary keys
KeyTypeMeaning
session_datestrDate for market summaries; absent from the emulator's undated cumulative summary.
trade_latency_nsintConfigured latency.
executionstrmarket or middle. Futures/options compatibility summaries report market.
passivityfloatStock setting; futures/options compatibility value is 0.
unit_sharesfloatStock setting; futures/options compatibility value is 1, not a contract multiplier.
order_countintNumber of ledger entries in the reported scope.
fill_countintNumber of filled entries.
cancel_countintNumber of cancelled entries.
rejection_countintorder_count − fill_count − cancel_count.
working_order_countintCurrently resting stock limits; zero for futures/options.
cash_flowfloatNet signed quantity × price over this summary's fills; buy negative, sell positive.
orderslist[dict]Ledger entries described below.
cashfloatStock-only cumulative simulated cash, initially zero.
positionsdict[str, float]Stock-only cumulative holdings.
desired_positionsdict[str, float]Stock-only last unit targets per symbol.
Order-entry fields
KeyPresence / typeMeaning
instrumentAlways · strSymbol or expanded option contract key.
sideAlways · strbuy or sell.
quantityAlways · floatSubmitted or remaining filled/cancelled quantity.
submitted_timestampAlways · intDecision/submission time in nanoseconds.
execution_timestampAlways · intSimulated execution or cancellation time. Session-end stock cancellations currently use 0 as a sentinel.
statusAlways · strfilled, rejected, or cancelled.
styleWhen set · strStock market/limit order style, or force_close_at's supplied label; legacy futures/options orders omit it.
limit_priceLimit entries · floatResting limit level.
quote_timestampFilled entries · intTimestamp of the quote used; explicit-price closes use their supplied timestamp.
priceFilled entries · floatAsk for a buy or bid for a sell, or the explicitly supplied force-close price.
notionalFilled entries · floatquantity × price, with no contract multiplier.
reasonRejected/cancelled entries · strno_quote, unusable_price, or cancelled. Specific cancellation causes are not preserved in this string.

Rejections and cancellations omit price, notional, and quote_timestamp. The presence of a submitted order never guarantees a fill. Stocks retain open holdings at session end unless strategy code flattens them; the market does not automatically liquidate. Raw cash and cash_flow alone are not mark-to-market portfolio profit.

Causal visibility and the low-level boundary

The replay iterator is the intended strategy input: it exposes the current trade/quote and the latest already-observed records. Broker submissions return None instead of an execution price, and market summaries are withheld until replay completes. This makes the usual event loop harder to turn into an accidental crystal ball.

The package does not isolate all future data. The stock emulator updates its internal cash, holdings, and ledger immediately using the quote found at decision time plus latency. market[None], market.trade_emulator, emulator.cash, emulator.summary(), working-order prices, and direct emulator search hints can therefore expose state derived from later quotes while replay is still at the decision event.

Keep decisions based on the observed event stream and incremental state. Treat execution summaries as post-replay analysis. If using the advanced account or database APIs inside a strategy, enforce your own as-of-time visibility. Never use force_close_at with an eventual close price before that close is observable, and never feed a completed future bar into an earlier event.

This event-by-event pattern is intended to work with RTTA: update the indicator or model with one newly observed value, read its current signal, then submit a desired position. The quick-start broker example demonstrates the high-level path; the timestamp-search documentation explains how participant and receipt time can differ.