Crypto has no CUSIP, no ISIN in practice and no central body handing out tickers. Every venue invented its own scheme, so the BTC/USDT linear perpetual has a different name on each of them, and the same string can mean two different instruments on a single venue: on Bybit, BTCUSDT is both a spot pair and a perpetual.
btcusdtBTCUSDTBTC-USDT-SWAPperpetual-BTC-USDT:USDTJoin the three by hand and the code works until it silently doesn't: a spot pair merged into a perp, an inverse contract read as linear, a listing that disappears from a backtest because it was renamed. Atlas does the mapping once, in the open, for everyone.
Exchange APIs only list what trades today. A 2022 study of 3,904 cryptocurrencies found 39.5% were eventually delisted, and that dropping them biased equal-weighted portfolio returns by 62% a year and overstated the size premium by half (Ammann et al.). Atlas keeps every delisted instrument with the day it stopped trading, so you can rebuild the universe as it was on any date.
Different tokens share tickers, and tickers get renamed and reused (CoinDesk on USDP, BCH and BSV). Atlas keys every instrument on the venue and its native ID, and tags Binance assets with a CoinMarketCap ID, so 1000PEPE on one venue and PEPE on another resolve to the same asset.
One OKX PEPE-USDT-SWAP contract is 10,000,000 PEPE. Bybit's BTCUSD is margined in BTC, not dollars. Get either wrong and position sizes and PnL are off by orders of magnitude. Atlas records contract size, margin asset and delivery date next to the ID.
Funding arbitrage, basis, lead-lag and liquidity routing all start with the same question: where else does this contract trade? With a shared ID it is a lookup, not a weekend of regular expressions.
Every quant team, data vendor and exchange aggregator rebuilds this map, usually privately and usually with the same bugs. A shared, reviewable one means fixes land once and help everyone, and research written against it is reproducible by anyone.
The snapshots are plain JSON in git. Every listing, delisting and correction is a commit you can diff, blame and pin, so a backtest can name the exact version of the universe it ran on.
<type>-<symbol>-<denominator>[:<margin>][-<delivery_yyyymmdd>]
| Venue | Native ID | Atlas ID |
|---|---|---|
| Binance spot | BTCUSDT | spot-BTC-USDT |
| Bybit inverse | BTCUSD | perpetual-BTC-USD:BTC |
| Bybit futures | BTCUSDT-27MAR26 | future-BTC-USDT:USDT-20260327 |
| Binance COIN-M | BTCUSD_PERP | perpetual-BTC-USD:BTC |
| Hyperliquid HIP-3 | flx:TSLA | perpetual-FLX:TSLA-USDH:USDH |
The native ID, the normalized parts, contract size, underlying (crypto, equity, index, commodity or pre-market for tokenized and HIP-3 markets), CoinMarketCap ID and category where known, and the listing window: first_capture and, once it stops trading, end_date.
{
"id": "btcusdt",
"type": "perpetual",
"internal_id": "perpetual-BTC-USDT:USDT",
"symbol": "BTC",
"denominator": "USDT",
"margin": "USDT",
"contract_size": 1.0,
"underlying": "crypto",
"cmc_id": 1,
"category": ["Layer 1"],
"first_capture": "2019-11-17T00:00:00.000Z"
}Python 3.12 or later. The snapshots are bundled, so lookups are local dictionary reads with no network calls and no key.
pip install git+https://github.com/aperiodic-io/atlasfrom datetime import datetime
from atlas import SecurityMaster
sm = SecurityMaster.load() # ships with the snapshots, no network needed
# Three venues, three names, one contract
sm.by_exchange_and_original_id("binance-futures", "btcusdt")
sm.by_exchange_and_original_id("bybit-perps", "BTCUSDT")
sm.by_exchange_and_original_id("okx-perps", "BTC-USDT-SWAP")
# -> 'perpetual-BTC-USDT:USDT' each time
# Every perpetual that traded at any point in 2022,
# including the ones delisted since
universe = sm.symbol_ids(
exchange="binance-futures",
first_capture=datetime(2022, 1, 1),
end_date=datetime(2022, 12, 31),
)
# The full record: contract size, margin asset, CMC ID, listing window
sm.instrument_metadata("okx-perps", "PEPE-USDT-SWAP")Every day at 02:00 UTC, a GitHub Action pulls instrument lists from the Binance and OKX APIs directly and from Tardis for the rest.
New listings are parsed into Atlas IDs, delistings get an end date, and fields a source stops sending are kept rather than wiped.
New Binance listings are matched to CoinMarketCap IDs. Only matches with name evidence are written; ambiguous ones open a pull request for review.
The updated snapshots are committed to the repository, with tests guarding every parser.
binance-spotbinance-futuresbinance-futures-cmbybit-spotbybit-perpsbybit-futuresokx-spotokx-perpsokx-futureshyperliquid-spothyperliquid-perpsSpot, perpetuals and dated futures. Beta parsers for 20+ more venues are in the repository and join the daily refresh once they are stable.