Sources
Declare Python V2 market-data selectors and access them at runtime.
In Python V2, history.source(...) both declares a source and reads its history. There is no separate --source, TOML [sources], or script.sources declaration.
Selectors
<symbol>@<source>@<exchange>
<symbol>@<source>@<exchange>@<provider>Add source options after the final segment:
candles = history.source("btc@candles@binancef:timeframe=60")
book = history.source("btc@orderbook@bulkf:depth=20", 0)
oi = history.source("btc@oi@hyperliquidf@mmt:timeframe=30")Core futures use the base asset, such as btc. Hyperliquid HIP-3 uses {dex}:{coin}, such as xyz:tsla. Spot uses the exact pair, such as hype/usdc. Outcome symbols keep their side, such as 1009:0.
xyz_direct = history.source("xyz:tsla@candles@hyperliquidf:timeframe=60")
xyz_mmt = history.source("xyz:tsla@candles@hyperliquidf@mmt:timeframe=60")Selector lookup is ASCII case-insensitive, so XYZ:TSLA and xyz:tsla resolve to the same declared feed. Market Lab keeps hyperliquidf as the canonical exchange and handles the provider-specific DEX route internally.
MMT selectors include both the indexed exchange and mmt:
candles = history.source("btc@candles@binancef@mmt:timeframe=60")
trades = history.source("btc@trades@binancef@mmt")Declare selectors with literal strings or module-level string constants. Market Lab inspects them before the job starts so every subscription is deterministic. F-strings and other dynamic lookups may read only feeds declared elsewhere in the script.
Runtime access
With no index, history.source returns the retained list. Index 0 returns the newest record:
CANDLES = "btc@candles@binancef:timeframe=60"
def on_data(ctx, history):
records = history.source(CANDLES)
latest = history.source(CANDLES, 0)Source options are part of the declaration, but Market Lab exposes a normalized identity on ctx:
ctx.source # btc@candles@binancef
ctx.source_type # candles
ctx.provider
ctx.exchange
ctx.symbol
ctx.source_configsThe market record remains in history; it is not copied onto ctx.
Availability
| Source | Standalone Binance | MMT | BULK | Hyperliquid |
|---|---|---|---|---|
candles | Backtest | Live and backtest | Live and backtest | Live and backtest |
orderbook | No | Live and backtest | Live | Live |
trades | No | Live | Live | Live |
vd | No | Live and backtest | Live | Live |
oi | No | Live and backtest | Live | Live |
volumes | Backtest | Live and backtest | Live and backtest | Live and backtest |
Provider and market type determine whether a source is valid. Spot and outcome markets do not provide perpetual-only OI.
Multiple sources
Declare each feed where it is read:
def on_data(ctx, history):
btc = history.source("btc@candles@binancef:timeframe=900", 0)
zec = history.source("zec@candles@binancef:timeframe=900", 0)
if btc is None or zec is None:
returnThen backtest without repeating the selectors:
mlab script backtest pairs.py \
--from 2026-07-15 \
--to 2026-07-16Each selector gets an independent history buffer. See History.
Source references: