Collecting Long/Short Ratio from Crypto Exchanges: Technical Breakdown
A trader needs a year of Long/Short Ratio history across 50+ instruments for strategy backtesting. Exchanges store at most a month of data — Binance returns only the last 500 records (roughly 30 days with 5-minute granularity), Bybit 200, OKX 100. Manual collection via UI would take hundreds of man-hours, and a single data gap ruins the backtest. We built a system on async Python that continuously pulls data from three exchanges simultaneously, normalizes it, and stores it in TimescaleDB. Now history is available for any period, and adding a new symbol takes 5 minutes — just add it to the config. The trader gets a continuous data stream with less than a minute delay, suitable for real-time indicators and crypto sentiment analysis. Below — architecture, pitfalls, and the ready solution.
Official APIs for L/S Ratio
Start with official endpoints — they are stable and require no browser automation. Here are the available sources:
| Exchange | Endpoint | Data | History Limit | Auth |
|---|---|---|---|---|
| Binance Futures | /futures/data/topLongShortAccountRatio |
Top trader account ratio | 500 records, ~30 days | No (public) |
| Binance Futures | /futures/data/globalLongShortAccountRatio |
All accounts | 500 records | No |
| Bybit | /v5/market/account-ratio |
Account ratio | 200 records | No |
| OKX | /api/v5/rubik/stat/contracts/long-short-account-ratio |
Account ratio | 100 records | No |
| CoinGlass (aggregator) | /api/v1/longShort |
Aggregated from 4+ exchanges | Depends on subscription | API key (paid) |
According to the Binance Futures API documentation, data is only available for the last 30 days. Long-term analysis requires continuous collection.
Binance Futures — the most comprehensive data, multiple endpoints:
# Top trader long/short account ratio GET https://fapi.binance.com/futures/data/topLongShortAccountRatio?symbol=BTCUSDT&period=5m&limit=30 # All accounts ratio (retail sentiment) GET https://fapi.binance.com/futures/data/globalLongShortAccountRatio?symbol=BTCUSDT&period=1h&limit=30 Response: array [{symbol, longShortRatio, longAccount, shortAccount, timestamp}]. Historical data is limited: limit=500 max, period from 5m to 1d. Data older than ~30 days is unavailable via API — you need to collect it yourself.
Bybit — endpoint /v5/market/account-ratio:
GET https://api.bybit.com/v5/market/account-ratio?category=linear&symbol=BTCUSDT&period=1h&limit=50 OKX — /api/v5/rubik/stat/contracts/long-short-account-ratio:
GET https://www.okx.com/api/v5/rubik/stat/contracts/long-short-account-ratio?ccy=BTC&period=1H OKX does not require authentication for public market data endpoints. Rate limit: 20 req/2 sec.
Why You Can't Do Without Your Own Database?
Data needs to be collected regularly — exchanges store limited history, so your own database is essential for analyzing long periods. PostgreSQL with the TimescaleDB extension is optimal for time-series data: automatic time-based partitioning and continuous aggregates speed up range queries by 3x compared to plain PostgreSQL. InfluxDB is faster on writes but lacks JOIN flexibility. Flat CSV files are cheap but lack indexes and duplicate protection. That's why we chose TimescaleDB — uniqueness guarantee via ON CONFLICT and write speeds up to 1000 records/sec on a single node.
import httpx import asyncio from datetime import datetime import asyncpg ENDPOINTS = { "binance_top_account": "https://fapi.binance.com/futures/data/topLongShortAccountRatio", "binance_global": "https://fapi.binance.com/futures/data/globalLongShortAccountRatio", "bybit": "https://api.bybit.com/v5/market/account-ratio", } async def collect_ls_ratio(symbol: str, period: str, db: asyncpg.Connection): async with httpx.AsyncClient() as client: resp = await client.get( ENDPOINTS["binance_global"], params={"symbol": symbol, "period": period, "limit": 1}, timeout=10.0, ) data = resp.json()[0] await db.execute(""" INSERT INTO ls_ratio (exchange, symbol, period, long_ratio, short_ratio, ts) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (exchange, symbol, period, ts) DO NOTHING """, "binance", symbol, period, float(data["longAccount"]), float(data["shortAccount"]), datetime.fromtimestamp(data["timestamp"] / 1000)) ON CONFLICT DO NOTHING — protection against duplicates on repeated collection. Unique index on (exchange, symbol, period, ts).
What If the Exchange Doesn't Provide an API?
Some exchanges (Gate.io, Bitfinex) do not publish L/S ratio via official API but show it on a web page. For such cases, we use a headless browser via Playwright:
from playwright.async_api import async_playwright async def scrape_gateio_ls(symbol: str) -> float: async with async_playwright() as p: browser = await p.chromium.launch(headless=True) page = await browser.new_page() # Intercept XHR requests to internal API ls_data = {} page.on("response", lambda r: capture_ls_response(r, ls_data)) await page.goto(f"https://www.gate.io/futures/{symbol}") await page.wait_for_timeout(3000) await browser.close() return ls_data.get("longShortRatio") Official API is 10x more stable than headless parsing. Browser parsing is unstable: layout changes, anti-bot measures (Cloudflare, PerimeterX). For production, we use it only as a fallback, with monitoring of collection success.
Practical Notes and Common Mistakes
Rate limiting: when collecting data for 20+ symbols from several exchanges, you easily get HTTP 429. Use asyncio.Semaphore to limit concurrent requests and exponential backoff on errors. Binance Futures: 1200 weight per minute, each request = 1 weight for market data.
Data normalization: Binance returns longAccount as a share (0.65 = 65% long), OKX as a ratio (1.86 = 1.86:1 long/short). Normalize to a uniform format before writing to DB.
Time zones: all timestamps convert to UTC. Binance returns Unix milliseconds, Bybit does as well, OKX returns an ISO 8601 string.
How We Build the Collection System
Our process includes:
- Analysis: Identify all required symbols and periods. Determine which exchanges offer L/S ratio via API and which need scraping.
- Architecture design: Choose the stack (async Python, httpx, asyncpg) and storage schema in TimescaleDB.
- Parser development: Write async functions for each exchange with rate limiter.
- Database integration: Create a hypertable with daily partitioning and continuous aggregates for faster queries.
- Monitoring and alerts: Set up alerts when collection success rate drops below 95%.
Each stage is tested on a small dataset, then scaled.
What's Included in Our Turnkey Solution
We offer a ready-made system for collecting and storing L/S data:
- Configuration of parsers for 3+ exchanges (Binance, Bybit, OKX) with ability to add new ones.
- Storage in TimescaleDB with automatic partitioning and retention policy.
- Collection monitoring with alerts if success rate falls below 95%.
- API to access collected data (filter by exchange, symbol, period).
- Documentation and team training.
We'll assess your project in 2 business days — just reach out to us. We guarantee data delivery from the moment of launch. The cost of the solution depends on the number of symbols and exchanges and is determined after analysis. Storage infrastructure savings can reach up to 70%. We have implemented this for 10+ projects with a total storage volume of over 500 million records. Contact us for a consultation — we'll discuss your task with no obligation.
Why Trust Us with Collection?
5 years of experience in blockchain development, dozens of projects in parsing and data analysis. We use a production stack: async Python, httpx, asyncpg, TimescaleDB. All solutions are covered by monitoring and have backup collection channels. Average savings for our clients — $1000–3000 per month. Get a consultation — contact us.







