The exchange ids and the venue-native symbol spellings an Indicator uses everywhere a market is named: pinned inputs, om metric get and om metric series, watch conditions, and om open. The vocabulary is the same one kScript (legacy) uses, so a symbol that worked in a source(...) call works in an input(...) pin.
Where the vocabulary is used
A market is always the pair exchange + symbol, and the two travel together:
- Pinned inputs in the file:
input("btc", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES" }). A lonesymbolor a loneexchangeis refused at the sheet, because half a pin names a market that does not exist. Pins are honored on your machine; the chart reads its own market for every input. - Evaluation on your machine:
om metric getandom metric seriestake--symboland--exchangefor the market the unpinned inputs follow, plus--intervalin either spelling (1horHOUR). - Watch conditions: the
selectorblock namesexchange,symbol, andinterval({ "exchange": "BINANCE_FUTURES", "symbol": "BTCUSDT", "interval": "HOUR" }); an edge operator requires the interval. - Charts:
om open @scope/nameandom chart indicator addplace a package on the chart's own market.
Example: one market on three venues
Three pinned closes of the same asset, spelled the way each venue spells it, and two spreads between them. The first input stays unpinned so the package follows the market it is evaluated on:
import { input, line, lower, ohlcv, output } from "./sdk/declare";
import { in_binance_perp, in_binance_spot, in_close, in_coinbase } from "./gen/inputs";
import { emitRow, out_basis_pct, out_coinbase_gap_pct } from "./gen/outputs";
input("close", ohlcv.close);
// Every pin names the venue's own spelling of the market, and symbol and exchange always pin together.
input("binance_spot", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE", description: "Binance spot, joined form" });
input("binance_perp", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES", description: "Binance perpetual, joined form" });
input("coinbase", ohlcv.close, { symbol: "BTC-USD", exchange: "COINBASE", description: "Coinbase spot, hyphen form" });
output("basis_pct", line, lower, { unit: "%", description: "Binance perp premium over Binance spot" });
output("coinbase_gap_pct", line, lower, { unit: "%", description: "Coinbase spot over Binance spot" });
let basis: f64 = NaN;
let gap: f64 = NaN;
export function init(): void {}
export function state(): i32 {
const spot = in_binance_spot();
if (isNaN(spot) || spot <= 0.0) return 0;
basis = ((in_binance_perp() - spot) / spot) * 100.0;
gap = ((in_coinbase() - spot) / spot) * 100.0;
return 1;
}
export function finalize(): void {
out_basis_pct(basis);
out_coinbase_gap_pct(gap);
emitRow();
}
export function reset(): void {
basis = NaN;
gap = NaN;
}The unpinned close is never read by the code; it is the grid every pinned input aligns to. Install the package and evaluate it against the market you want the spreads on:
om wrun install ./venue-spreads --replace
om metric series --metric wrun/@you/venue-spreads/basis_pct --symbol BTCUSDT --exchange BINANCE_FUTURES --interval 1h --bars 48Exchange reference table
Exchange ids are the data plane's spelling, always uppercase. Symbols are venue-native: each venue's own separator, or none. The format column shows the venue's convention with an example market; om symbols --exchange <id> lists the exact symbols a venue serves.
| Exchange | Category | Symbol format | Example |
|---|---|---|---|
BINANCE | SPOT | BTCUSDT | Bitcoin to Tether (spot) |
BINANCE_FUTURES | PERPETUAL | BTCUSDT | BTC/USDT perpetual |
BINANCE_DELIVERY | dated futures | venue-native | BTC dated contracts |
BITFINEX | SPOT | BTCUST or BTC:USD | Bitcoin to USD (spot) |
BITFINEX_DERIVATIVES | PERPETUAL | BTCF0:USTF0 | BTC perpetual |
BITGET | PERPETUAL | BTCUSDT | BTC/USDT perpetual |
BITMEX | PERPETUAL | XBTUSD | Bitcoin to USD |
BITSTAMP | SPOT | BTCUSD | Bitcoin to USD (spot) |
BYBIT | PERPETUAL | BTCUSDT | BTC/USDT perpetual |
BYBIT_SPOT | SPOT | BTCUSDT | Bitcoin to USDT (spot) |
COINBASE | SPOT | BTC-USD | Bitcoin to USD (spot) |
DERIBIT | PERPETUAL | BTC-PERPETUAL, BTC_USDC-PERPETUAL | BTC/USD and BTC/USDC perpetuals |
GATE_IO | SPOT | BTC_USDC | Bitcoin to USDC (spot) |
GATE_IO_FUTURES | PERPETUAL | BTC_USDT | BTC/USDT perpetual |
HUOBI | SPOT | venue-native | spot markets |
HUOBI_DM_SWAP, HUOBI_DM_LINEAR_SWAP | PERPETUAL | venue-native | coin- and USDT-margined swaps |
HYPERLIQUID | SPOT | HYPE-USDC | HYPE to USDC (spot) |
HYPERLIQUID_FUTURES | PERPETUAL | BTC | BTC perpetual (the bare base asset) |
HYPERLIQUID_HIP3 | PERPETUAL | venue-native | HIP-3 perpetuals |
OKEX | SPOT | BTC-USDT | Bitcoin to USDT (spot) |
OKEX_FUTURES | dated futures | BTC-USDT-251226 | BTC future (Dec 26, 2025) |
OKEX_SWAP | PERPETUAL | BTC-USDT-SWAP | BTC/USDT perpetual swap |
UPBIT | SPOT | KRW-USDT | Korean won to USDT |
CME | dated futures | venue-native | listed futures |
POLYMARKET | prediction markets | the 66-character conditionId | one outcome market; read through the odds source |
Spot venues that have a derivatives twin pair up in the data plane (BINANCE with BINANCE_FUTURES, BYBIT_SPOT with BYBIT, OKEX with OKEX_SWAP, GATE_IO with GATE_IO_FUTURES, HYPERLIQUID with HYPERLIQUID_FUTURES); the aggregated CVD recipe leans on exactly that pairing.
Discover instead of guess
A guessed id is an input that never gets a row. The CLI lists the live vocabulary:
om exchanges
om symbols --exchange OKEX_SWAP --format json
om markets --exchange HYPERLIQUID_FUTURES
om resolve "btc perp on okx"om exchanges prints every id and its category; om symbols the exact symbols one venue serves; om markets the tradeable markets with their metadata; om resolve turns a phrase into the exchange + symbol pair the other commands take.
Notes
Case sensitivity. Exchange ids are uppercase (BINANCE, never binance), and symbols are matched as the venue spells them. Interval short forms are case-sensitive too: 1m is a minute and 1M is a month, which is why the data plane's own names (MINUTE, HOUR, FOUR_HOURS, DAY, WEEK) are the safe spelling in a sheet or a watch selector.
Separators vary. Hyphens (BTC-USD), underscores (BTC_USDT), colons (BTC:USD), or nothing (BTCUSDT), per venue. The same asset is a different string on every venue, so a package that pins several venues carries one spelling per pin; there is no normalized symbol in a pin.
Data availability. Not every source exists for every venue and symbol: funding, open interest, and liquidations are perpetual-venue feeds, options tenors are Deribit's, and the celled book class needs a block_size the venue serves (om block-sizes --exchange <id> lists them). An input on a market the venue does not serve delivers no rows; on the chart, the chart names the source it cannot serve.
Dated futures and options. Use the format the venue publishes; YYMMDD in an OKX future is the expiry. Dated books are neither spot nor perpetual, so the CLI leaves their category unclassified rather than guessing.
Polymarket. An odds input names one outcome market by its conditionId (0x plus 64 hex characters), never the market slug or the event, with outcome YES or NO; the exchange is implicit and refused if written (Data sources).