Candles
Live trade-derived and historical candle behavior for Market Lab scripts.
Candles Source
The candles source provides OHLCVT records. The timeframe value is an integer number of seconds.
--source candles@binancef@mmt:timeframe=60
--source candles@bulk:timeframe=5Live Candles
During live execution, Market Lab subscribes to raw trades for both MMT and BULK and derives candles locally. It does not subscribe to either provider's prebuilt candle stream.
This makes any positive whole-second interval valid during live execution:
--source candles@binancef@mmt:timeframe=1
--source candles@hyperliquid@mmt:timeframe=5
--source candles@bulk:timeframe=30Trade timestamps are placed into Unix/epoch-aligned buckets. For a 60-second timeframe, boundaries are 12:07:00, 12:08:00, 12:09:00, and so on. For 30 seconds, boundaries include 12:07:00, 12:07:30, and 12:08:00.
Only completed candles are sent to the script. Market Lab does not expose an in-progress candle that changes on every trade.
Startup Alignment
The interval containing the script's startup time is discarded unless the script starts exactly on a boundary. This prevents a partial first bar from being treated like a full bar.
For example:
- Start at
12:07:39withtimeframe=60: trades before12:08:00are ignored. The first clean bucket is12:08:00–12:09:00, and its candle becomes available after that bucket closes. - Start at
12:07:14withtimeframe=30: trades before12:07:30are ignored. The first clean bucket is12:07:30–12:08:00. - Start exactly at
12:08:00withtimeframe=60: that boundary begins the first accepted bucket immediately.
A completed candle is emitted when a trade from a later bucket arrives. If a period has no trades, Market Lab does not invent an empty candle or carry a previous close forward. A quiet market can therefore delay emission until the next trade, and gaps can exist between candle timestamps.
Live OHLCVT Construction
For each accepted trade:
ois the first trade price in the bucket.handlare the highest and lowest trade prices.cis the final trade price.vbandvssum buy and sell base quantities.tbandtscount buy and sell trades.volumeisvb + vs.tradesistb + ts.tis the bucket start in Unix milliseconds.close_timeis the exclusive bucket end in Unix milliseconds.
The raw trade side supplied by the provider determines buy versus sell. Late trades older than the active bucket are ignored; batched trades are sorted by timestamp before aggregation.
Backtest Candles
Backtests load stored provider candles rather than reconstructing them from live trades. They cannot request an arbitrary second interval.
A stored candle enters the replay only at its closing boundary, after its final OHLC values would have been known.
MMT historical candle intervals:
60, 300, 900, 1800, 3600, 14400, 86400 secondsThe minimum MMT backtest interval is 60 seconds.
BULK historical candle intervals:
10, 60, 180, 300, 900, 1800, 3600, 7200, 14400,
21600, 28800, 43200, 86400, 259200, 604800, 2592000 secondsThe minimum BULK backtest interval is 10 seconds.
Historical volume fields retain the semantics available from the provider. In particular, older BULK candles do not invent directional vb, vs, tb, or ts values when the stored candle does not contain them.
Commands
Live MMT candles:
mlab script run ./scripts/candle-script.js \
--symbol BTC/USDT \
--source candles@binancef@mmt:timeframe=5Live BULK candles:
mlab script run ./scripts/candle-script.js \
--symbol BTC/USDT \
--source candles@bulk:timeframe=5MMT backtest:
mlab script backtest ./scripts/candle-script.js \
--symbol BTC/USDT \
--from 1780307559000 \
--to 1780523645331 \
--source candles@binancef@mmt:timeframe=60Read the data in live execution and backtests with exact selectors:
const candles = history.source('candles@binancef@mmt')
const current = history.source('candles@binancef@mmt', 0)
const previous = history.source('candles@binancef@mmt', 1)See Candles Data Type for the normalized shape.