Position Sizing From Live Crowding Data in Python
Standard position sizing divides a risk budget by a stop distance and stops there. That arithmetic quietly assumes the tail risk around your stop is the same from one trade to the next, and on leveraged perpetuals it is not. This playbook wires one public endpoint into a sizing function so that a one-sided book scales your notional down — and never up.
The problem: constant sizing, non-constant tail
A fixed-fractional sizing rule — risk 1% of equity, stop 2% away, therefore notional is half of equity — is the right starting point and it is not up for debate here. The issue is what it leaves out. That rule produces the same size whether the leveraged book is balanced or whether nearly all of it is stacked on the side you are about to join.
Those are not the same trade. When leveraged positioning is one-sided, the forced exits available to the market are all in one direction: liquidations of the crowded side push price the way that triggered them, which reaches the next cluster of liquidation levels, which triggers again. Your stop distance did not change. The probability that price traverses it in a single violent leg did.
Derivatives venues publish enough to measure that one-sidedness directly. This playbook reads those fields from one endpoint and folds them into a sizing function as a haircut. The conceptual background — what each ratio counts and why the balanced-notional objection does not apply to account ratios — is written up in this guide to crowding and open interest if you want the reasoning before the code.
Prerequisites
- Python 3.8+
pip install requests- No API key needed for the public view of this endpoint (the ten largest symbols by open interest). A free key raises your daily call cap; a Trader key returns the full symbol list.
The screener endpoint
One GET returns the cross-venue derivatives state per symbol, aggregated across Bybit, Binance and Hyperliquid:
Without a key the response is capped at the top ten symbols by open interest and
carries "limited": true; total_count still reports how many symbols are
tracked in full (518 at the time of writing). Sending an X-API-Key header on a Trader tier
or above returns the whole list.
Which fields measure what
These are four different measurements and conflating them is the usual source of bad conclusions. Every perpetual has exactly as much long notional open as short notional open, so none of the ratios below can mean “more longs than shorts” in a notional sense — each one is counting something narrower.
| Field | Counts | Read as |
|---|---|---|
| oi_usd | Open notional, USD | How much leveraged capital can be force-closed |
| oi_change_1h_pct | Change in that notional | Large negatives are the footprint of positions being closed en masse |
| long_short_ratio | Accounts, not size | Retail headcount lean; weights a small account like a large one |
| top_trader_lsr | Largest accounts only | Closest public proxy for where size sits; smaller, noisier sample |
| taker_ratio | Aggressive buy vs sell flow | Recent urgency over a window, not standing exposure |
| funding_annualized | Cost of holding, % / year | The market’s own price for sitting on the crowded side |
long_short_ratio 0.95 (headcount essentially balanced) alongside
top_trader_lsr 2.08 (large accounts leaning long). That is an ambiguous book, and a
crowding argument in either direction is weak there. The sizing rule below deliberately requires both
measures to agree before it takes anything off.Python: crowding-adjusted sizing
The structure is: compute the baseline unconditionally, score the book, then apply a haircut that is clamped so it can only reduce. The scoring thresholds are risk-management judgement calls, not fitted parameters — they are there to be edited to your own tolerance.
Expected output
Against a balanced book the script prints a zero score and hands back the baseline unchanged, which is the point — most of the time it should do nothing. Against a one-sided one it prints the reasons alongside the reduction:
Those figures come from feeding the function a real screener row captured at 15:45 UTC on 24 August 2026, in which DOGE carried the hardest long lean of the top ten on both ratios, the highest annualized funding of the group at about 11%, and had shed 16.8% of its open interest in the preceding hour. Three independent reasons stack to a 0.85 score and a 43% reduction. Those are historical observations from one moment, not a forecast, and the numbers will be different when you run it live.
The contrast is the useful part. The same function on the BTC row from that snapshot — account ratio 0.95 against a top-trader ratio of 2.08, funding at 8.0%, open interest down 1.4% — scores 0.0 and returns the baseline untouched, because headcount and size disagreed and the both-ratios gate never opened. Most of the time that is what you want this to do: nothing.
What this does not do
It does not predict direction, and it is built so that it cannot accidentally start to. The haircut is clamped to be non-positive: there is no branch that increases size for being on the uncrowded side. That asymmetry is deliberate. Crowded positioning is a statement about the variance of the trade, not its expected return — it can persist for weeks in a trending market while every contrarian who faded it is stopped out.
Two further limits worth stating plainly. The ratios are venue-specific and aggregation across venues smooths but does not eliminate that — for anything touching your own funding and liquidation, use the venue you are actually trading on. And a smaller position at the same leverage has exactly the same liquidation price, so a haircut does not widen your buffer; it only reduces what you lose if the buffer fails.
What to build next
Sensible extensions once the basic function is wired in:
- Persist each snapshot with your trade log, so that months later you can check whether your own results actually differ between crowded and balanced entries — on your fills, not on a vendor’s backtest.
- Price the carry over your intended holding period before entering; funding on the crowded side is a real drag on break-even, and the funding rate calculator turns a quoted rate into a cost in seconds.
- Re-check the liquidation buffer separately after sizing — the liquidation calculator takes entry, leverage and maintenance margin rate, and the pre-trade liquidation risk check playbook compares that level against where forced closures actually cleared recently.
- Widening beyond the public top ten with a key, then running the same score across a watchlist to see which of your candidates sits on the most one-sided book.
- Adding
taker_ratioas a separate flow term rather than folding it into the same score — it measures urgency over a window, which is a different thing from standing exposure.
See the full API documentation for every field the screener returns, or browse the rest of the code playbooks hub for more integration examples.
Beyond the public top ten
The public view covers the ten largest symbols by open interest. A free key raises your daily call cap on the endpoints it covers; a Trader key returns the full tracked symbol list from the same base URL.
Create a free account