# Sources (/scripting/sources)



The manifest declares base source kinds. Runtime flags bind those kinds to a symbol, provider, and exchange.

```text
<symbol>@<source>@<provider>
<symbol>@<source>@<exchange>@<provider>
```

## Selectors [#selectors]

The symbol is always first. Futures use the base asset, so `btc` means `BTC` and `zec` means `ZEC`. Spot keeps the real pair, such as `hype/usdc` for `HYPE/USDC`.

MMT is a multi-exchange provider, so its selector includes the symbol, source, exchange, and provider:

```bash
--source btc@candles@binancef@mmt:timeframe=60
--source btc@candles@hyperliquidf@mmt:timeframe=30
--source btc@oi@binancef@mmt:timeframe=60
--source btc@trades@binancef@mmt
```

Standalone exchanges remain their own selector even when combined with MMT data:

```bash
--source btc@candles@binance:timeframe=60
--source btc@candles@binancef:timeframe=60
--source btc@volumes@binance:timeframe=60
--source btc@volumes@binancef:timeframe=60
--source btc@orderbook@bulkf:depth=20
--source btc@candles@bulkf:timeframe=5
--source btc@trades@bulkf
--source btc@orderbook@hyperliquidf:depth=20
--source btc@candles@hyperliquidf:timeframe=5
--source btc@trades@hyperliquidf
--source tsla@candles@hyperliquidf-xyz:timeframe=60
--source tsla@orderbook@hyperliquidf-xyz:depth=20
--source tsla@trades@hyperliquidf-xyz
--source tsla@oi@hyperliquidf-xyz
--source sndk@candles@hyperliquidf-io:timeframe=60
--source sndk@orderbook@hyperliquidf-io:depth=20
--source sndk@trades@hyperliquidf-io
--source sndk@oi@hyperliquidf-io
--source hype/usdc@orderbook@hyperliquid:depth=20
--source hype/usdc@candles@hyperliquid:timeframe=5
--source hype/usdc@trades@hyperliquid
--source '1009:0@orderbook@hyperliquid:depth=20'
--source '1009:0@candles@hyperliquid:timeframe=60'
--source '1009:0@trades@hyperliquid'
```

There are no script-level `--symbol`, `--provider`, or `--exchange` flags. The source selector contains that information. This lets one script consume several symbols from standalone Binance, MMT, BULK, Hyperliquid, HIP-3 DEXs, and outcome markets at the same time.

For outcomes, `1009:0` is the complete market symbol. The colon inside the symbol is not a source-option separator. Options are parsed only after the final exchange or provider segment.

Standalone Binance selectors are historical-only. They work with `script backtest`, not live `script run` streams.

```bash
mlab script backtest ./scripts/ema-cross.js \
  --from <UTC_DATETIME> \
  --to <UTC_DATETIME> \
  --source btc@candles@binancef:timeframe=60 \
  --param fast=20 \
  --param slow=50
```

Example:

```bash
mlab script run ./scripts/cross-market.js \
  --source btc@candles@binancef@mmt:timeframe=5 \
  --source btc@candles@hyperliquidf@mmt:timeframe=5 \
  --source btc@orderbook@bulkf:depth=20 \
  --source btc@orderbook@hyperliquidf:depth=20
```

The symbols do not need to match:

```bash
mlab script backtest ./scripts/pairs.js \
  --from 2024-01-01 \
  --to 2024-01-02 \
  --source btc@candles@binancef:timeframe=900 \
  --source zec@candles@binancef:timeframe=900
```

The manifest still lists each required base kind once:

```js
export const script = {
  name: 'cross-market',
  version: '1',
  sources: ['candles', 'orderbook'],
  params: {},
}
```

Market Lab validates that every configured kind appears in `script.sources` and that every manifest kind has at least one concrete selector.

## Runtime Access [#runtime-access]

Use the same exact selector with `history.source`:

```js
const binanceDirect = history.source('btc@candles@binancef')
const binance = history.source('btc@candles@binancef@mmt')
const hyperliquid = history.source('btc@candles@hyperliquidf@mmt')
const bulkBook = history.source('btc@orderbook@bulkf', 0)
const hyperliquidBook = history.source('btc@orderbook@hyperliquidf', 0)
const xyzBook = history.source('tsla@orderbook@hyperliquidf-xyz', 0)
const entropyBook = history.source('sndk@orderbook@hyperliquidf-io', 0)
const bulkTrades = history.source('btc@trades@bulkf')
const latestBulkTrade = history.source('btc@trades@bulkf', 0)
const hypeSpotBook = history.source('hype/usdc@orderbook@hyperliquid', 0)
const outcomeBook = history.source('1009:0@orderbook@hyperliquid', 0)
```

Use the complete selector. `history.source('candles')` and `history.source('btc@candles')` do not identify a concrete configured source.

Market records are not duplicated under `input.candles`, `input.sources`, or `input.data`. `input` carries metadata:

```js
input.source // exact selector that triggered this hook
input.source_type // base source kind
input.symbol // normalized source symbol
input.source_configs['btc@candles@binancef@mmt'].timeframe_sec
```

Available sources:

| Source      | Binance backtest    | Binance live | MMT backtest | MMT live | BULK backtest | BULK live          | Hyperliquid backtest | Hyperliquid live   |
| ----------- | ------------------- | ------------ | ------------ | -------- | ------------- | ------------------ | -------------------- | ------------------ |
| `candles`   | Yes                 | No           | Yes          | Yes      | Yes           | Yes                | Yes                  | Yes                |
| `orderbook` | No                  | No           | Yes          | Yes      | No            | Yes                | No                   | Yes, depth 1-20    |
| `vd`        | No                  | No           | Yes          | Yes      | No            | Yes, trade-derived | No                   | Yes, trade-derived |
| `oi`        | No                  | No           | Yes          | Yes      | No            | Yes, snapshots     | No                   | Yes, snapshots     |
| `volumes`   | Yes, candle-derived | No           | Yes          | Yes      | Yes           | Yes                | Yes                  | Yes                |
| `trades`    | No                  | No           | No           | Yes      | No            | Yes                | No                   | Yes                |

Config keys:

| Source      | Config                                                          |
| ----------- | --------------------------------------------------------------- |
| `candles`   | `timeframe`                                                     |
| `orderbook` | backtest: `timeframe`, optional `depth`; live: optional `depth` |
| `vd`        | MMT: `timeframe`, `bucket`; standalone live: neither            |
| `oi`        | MMT: `timeframe`; standalone live: no timeframe                 |
| `volumes`   | `timeframe`                                                     |
| `trades`    | none                                                            |

The `timeframe` value is always an integer number of seconds. Support for arbitrary intervals is specific to live `candles`; other time-series sources and historical data retain provider-supported intervals.

`trades` is live-only. It delivers raw WebSocket trades to scripts and cannot be used in a backtest. See [Trades Source](/scripting/sources/trades) for its record shape and runtime behavior.

Hyperliquid outcomes support `orderbook`, `trades`, and `candles`. They do not support perpetual-only `oi` or `funding` data. Add `--testnet` to `script run` when both the outcome sources and execution should use testnet. Outcome metadata is discovered live rather than loaded from a static market snapshot.

See [Source History](/scripting/history) for list/index semantics and [Candles Source](/scripting/sources/candles) for live aggregation details.
