---
title: "Exchange and Symbol Format"
description: "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…"
order: 76
section: "faq"
---

<!-- source: docs/indicators/faq/symbol-format.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Exchange and Symbol Format

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 lone `symbol` or a lone `exchange` is 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 get` and `om metric series` take `--symbol` and `--exchange` for the market the unpinned inputs follow, plus `--interval` in either spelling (`1h` or `HOUR`).
- **Watch conditions**: the `selector` block names `exchange`, `symbol`, and `interval` (`{ "exchange": "BINANCE_FUTURES", "symbol": "BTCUSDT", "interval": "HOUR" }`); an edge operator requires the interval.
- **Charts**: `om open @scope/name` and `om chart indicator add` place 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:

```typescript
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:

```bash
om wrun install ./venue-spreads --replace
om metric series --metric wrun/@you/venue-spreads/basis_pct --symbol BTCUSDT --exchange BINANCE_FUTURES --interval 1h --bars 48
```

## Exchange 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:

```bash
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](../core-concepts/data-sources.md)).
