Open Interest Data Collection from Crypto Exchanges: Complete Guide

Collecting Open Interest Data from Crypto Exchanges: Complete Guide Collecting (scraping) **Open Interest** data from crypto exchanges is a problem that cannot be solved with a simple REST request. Each exchange returns OI in its own units: Binance in contracts (BTC), Bybit in USD, OKX in contrac

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1451
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1011

Collecting Open Interest Data from Crypto Exchanges: Complete Guide

Collecting (scraping) Open Interest data from crypto exchanges is a problem that cannot be solved with a simple REST request. Each exchange returns OI in its own units: Binance in contracts (BTC), Bybit in USD, OKX in contracts with fractional precision. Without normalization, aggregated OI is useless. We help traders and analysts automate this collection in 1–2 weeks, accounting for rate limits, symbol prioritization, and a unified storage schema. Our team’s experience — over 50 DeFi analytics projects — shows that without automated multi-exchange collection, the market picture is distorted.

Open Interest is the total volume of open futures/options positions (Wikipedia). It is a key indicator for derivatives analytics: a sharp rise in OI during a price drop signals new shorts; a rise in OI during a price rise signals longs being added.

Why collecting OI from multiple exchanges is a complex task?

Parsing data from each exchange requires handling different formats, rate limits, and the need to unify everything. After the FTX collapse, it became clear that relying on a single platform skews metrics. Only multi-exchange collection provides an objective picture.

Data sources and their specifics

Centralized derivatives exchanges publish OI via REST and WebSocket APIs:

Exchange Endpoint Specifics
Binance GET /fapi/v1/openInterest (perp), /futures/data/openInterestHist (history) History only for 30 days, granularity 5 min/15 min/1h
Bybit GET /v5/market/open-interest Parameter intervalTime: 5min, 15min, 30min, 1h, 4h, 1d
OKX GET /api/v5/rubric/open-interest Supports futures, swap, options
dYdX v4 GraphQL API or Indexer REST On-chain, data public without keys
GMX v2 On-chain via Reader contract No centralized API

How to bypass rate limits when collecting OI?

Each exchange has API rate limits. Binance fapi: 2400 weight/min, openInterest = 1 weight. Bybit: 600 req/5 sec. With a large number of symbols (50+ pairs), polling every minute easily hits limits.

Strategies:

  • Symbol prioritization: BTC and ETH every minute, top 20 by volume every 5 minutes, others every 15–30 minutes.
  • IP rotation: if data volume requires more than one collector instance, each uses a separate IP. Use residential proxies or different VPS for different exchanges.
  • Exchange WebSocket for price feed: get price from WebSocket (high frequency), OI from REST on schedule. Avoid unnecessary REST requests for prices.
from asyncio import Semaphore class RateLimitedCollector: def __init__(self, max_concurrent: int = 10): self.semaphore = Semaphore(max_concurrent) self.last_request_times = {} # exchange -> deque of timestamps async def throttled_request(self, exchange: str, coro): async with self.semaphore: await self.enforce_rate_limit(exchange) return await coro 

Collector architecture

Key decision: polling vs WebSocket. Most exchanges provide OI only via REST (OI is not a high-frequency signal like price). The optimal approach is scheduled polling every 1–5 minutes.

import asyncio import aiohttp from datetime import datetime from decimal import Decimal class OICollector: def __init__(self, db, symbols: list[str]): self.db = db self.symbols = symbols self.session: aiohttp.ClientSession = None async def collect_binance_oi(self, symbol: str) -> dict: url = f"https://fapi.binance.com/fapi/v1/openInterest" async with self.session.get(url, params={"symbol": symbol}) as resp: data = await resp.json() return { "exchange": "binance", "symbol": symbol, "oi_value": Decimal(data["openInterest"]), "oi_usd": Decimal(data["openInterest"]) * await self.get_price(symbol), "timestamp": datetime.utcfromtimestamp(data["time"] / 1000), } async def collect_bybit_oi(self, symbol: str) -> dict: url = "https://api.bybit.com/v5/market/open-interest" async with self.session.get(url, params={ "category": "linear", "symbol": symbol, "intervalTime": "5min", "limit": 1, }) as resp: data = await resp.json() item = data["result"]["list"][0] return { "exchange": "bybit", "symbol": symbol, "oi_value": Decimal(item["openInterest"]), "timestamp": datetime.utcfromtimestamp(int(item["timestamp"]) / 1000), } async def collect_all(self): tasks = [] for symbol in self.symbols: tasks.extend([ self.collect_binance_oi(symbol), self.collect_bybit_oi(symbol), ]) results = await asyncio.gather(*tasks, return_exceptions=True) valid = [r for r in results if not isinstance(r, Exception)] await self.db.bulk_insert(valid) 

How to normalize OI from different exchanges?

Different exchanges return OI in different units. Without converting to a common denominator, aggregation is impossible. We use USD denomination as the standard.

  • Binance BTCUSDT perp — in BTC (number of contracts × 1 BTC per contract)
  • Bybit BTCUSDT — in USD (base currency × price)
  • OKX BTC-USDT-SWAP — in contracts (1 contract = 0.01 BTC)
  • CME Bitcoin Futures — in contracts (1 contract = 5 BTC)

To get a comparable aggregate, we convert everything to USD:

def normalize_to_usd(oi_value: Decimal, unit: str, btc_price: Decimal) -> Decimal: match unit: case "BTC": return oi_value * btc_price case "USD" | "USDT": return oi_value case "contracts_0.01BTC": return oi_value * Decimal("0.01") * btc_price case "contracts_5BTC": # CME return oi_value * Decimal("5") * btc_price case _: raise ValueError(f"Unknown OI unit: {unit}") 

Storage and aggregation in TimescaleDB

TimescaleDB is optimal for time-series OI data. We guarantee that TimescaleDB outperforms regular PostgreSQL by 20x+ in aggregation speed due to hybrid tables and continuous materialized views.

CREATE TABLE open_interest ( time TIMESTAMPTZ NOT NULL, exchange TEXT NOT NULL, symbol TEXT NOT NULL, oi_contracts NUMERIC(30, 8), oi_usd NUMERIC(30, 2), PRIMARY KEY (time, exchange, symbol) ); SELECT create_hypertable('open_interest', 'time'); -- Continuous aggregate: aggregated OI across all exchanges CREATE MATERIALIZED VIEW oi_aggregate_5m WITH (timescaledb.continuous) AS SELECT time_bucket('5 minutes', time) AS bucket, symbol, SUM(oi_usd) AS total_oi_usd, jsonb_object_agg(exchange, oi_usd) AS by_exchange FROM open_interest GROUP BY bucket, symbol; 

Practical signals and metrics

Abrupt changes in OI are trading signals. Standard thresholds: OI rises >5% in 1 hour — significant position opening; OI falls >10% in 1 hour — liquidations or mass closure.

SELECT symbol, total_oi_usd AS current_oi, LAG(total_oi_usd, 12) OVER (PARTITION BY symbol ORDER BY bucket) AS oi_1h_ago, (total_oi_usd - LAG(total_oi_usd, 12) OVER (PARTITION BY symbol ORDER BY bucket)) / LAG(total_oi_usd, 12) OVER (PARTITION BY symbol ORDER BY bucket) * 100 AS change_1h_pct FROM oi_aggregate_5m WHERE bucket = (SELECT MAX(bucket) FROM oi_aggregate_5m) ORDER BY ABS(change_1h_pct) DESC NULLS LAST; 

OI combined with other data gives a fuller picture:

  • Long/Short ratio — available on Binance (/futures/data/globalLongShortAccountRatio), Bybit.
  • Funding rate — cost of holding a perpetual position. High positive funding + high OI = overheated long.
  • OI-weighted funding — average funding across all exchanges weighted by their OI.

Process and what you get

  1. Analytics — we analyze your requirements, select exchanges and symbols.
  2. Design — we develop the collector architecture, storage schema. Development cost is calculated individually based on the number of exchanges and collection frequency.
  3. Implementation — we write code, configure rate limiting and normalization.
  4. Testing — we verify data correctness on historical and real cases.
  5. Deployment — we deploy the solution in your environment, dashboard ready. The time saved on manual data collection quickly offsets the investment.

Development of a collector for 5–7 exchanges with normalization, storage, and basic aggregates: 1–2 weeks. Full analytics pipeline with alerts, API, and dashboard: 3–4 weeks.

The final solution includes:

  • Source code of the async Python collector
  • SQL migrations for TimescaleDB
  • Grafana dashboard with OI, funding rate, long/short ratio visualization
  • Architecture and operation documentation
  • Team training and 1 month of support

Order a custom collector for your needs. Contact us for a preliminary assessment of your project. Get a turnkey solution with guaranteed reliability and proper normalization.

Comparison of approaches: REST polling vs WebSocket

Criterion REST polling WebSocket
Update frequency 1–5 min Real-time
API load High (depends on number of symbols) Low (data arrives via subscription)
OI support All exchanges Not all exchanges provide OI via WebSocket

REST polling is better suited for OI collection, as most exchanges do not broadcast this metric in real time.

Additional resources: Open Interest (Wikipedia), TimescaleDB.