Skip to main content

Adding External Data — Binance Open Interest

The built-in indicators (RSI, MACD, EMA, Bollinger, …) operate on the candles you're already trading. But sometimes the most useful information is outside the candle data — order book imbalance, options skew, on-chain flows, sentiment scores, and (the example for this tutorial) futures open interest.

This tutorial shows how to plug an external API into BrighterTrading using the External Indicator feature. The same indicator definition serves both backtesting (historical fetch) and live/paper trading (current value), so once you set it up, strategies that reference it just work in either mode.

What you'll learn
  • What futures open interest is and why traders watch it
  • How to configure an External Indicator with both historical and live modes
  • How JSONPath maps an arbitrary API response into a numeric indicator
  • How to validate the configuration with the Test Connection button
  • How to extend the indicator with a second named output (notional value)

What is open interest (in 90 seconds)?

Open interest is the total number of outstanding futures contracts for a market. Every contract has a long side and a short side; OI counts each contract once.

  • OI rising while price rises → new money entering longs. The trend has fresh fuel.
  • OI rising while price falls → aggressive shorting. Bears are pressing.
  • OI falling while price rises → shorts covering. Squeeze in progress.
  • OI falling while price falls → longs liquidating. Capitulation.

Read together with price, OI tells you whether a move is being driven by new positions or by existing positions closing. That distinction often separates trend continuation from reversal.

For Binance's BTCUSDT perp, OI typically sits between 80,000 and 130,000 BTC contracts at the time of writing. The notional value (in USD) is more intuitive for sizing context — usually $5–10 billion.

Why a strategy might care:

  • Regime filter: only trend-follow when OI is climbing (confirming the trend).
  • Mean-reversion signal: rapid OI spikes often precede sharp reversals.
  • Risk gate: cap position size during low-liquidity / low-OI windows.

We're not going to use it for any of those today — that's a future tutorial. For now we're just wiring the data in so a strategy can use it.

The Binance API endpoints

Binance Futures exposes two open interest endpoints, both public, no auth required:

Historical — for backtesting:

https://fapi.binance.com/futures/data/openInterestHist?symbol=BTCUSDT&period=5m&startTime=...&endTime=...&limit=...

Sample response:

[
{"symbol":"BTCUSDT","sumOpenInterest":"96909.25","sumOpenInterestValue":"7657546122.74","timestamp":1745740500000},
{"symbol":"BTCUSDT","sumOpenInterest":"97142.83","sumOpenInterestValue":"7703320196.27","timestamp":1745740800000}
]

Current — for live trading:

https://fapi.binance.com/fapi/v1/openInterest?symbol=BTCUSDT

Sample response:

{"symbol":"BTCUSDT","openInterest":"97202.59","time":1745741914705}

Two things to notice:

  1. The fields have different names between endpoints (sumOpenInterest vs openInterest). That's a real-world API quirk we'll work around using BrighterTrading's Latest from historical live mode — we'll have the live fetcher hit the historical endpoint with &limit=1 so the JSONPath stays the same.
  2. The historical endpoint also returns sumOpenInterestValue — the USD notional value of all those contracts. We'll add that as a second output near the end of the tutorial.

Open the External Indicator dialog

In the right panel, expand Indicators if it's collapsed and click + External Indicator:

External Indicator dialog blank

The dialog is divided into three logical sections:

  1. Historical — for backtesting. URL template, optional auth, and one or more outputs (each with its own JSONPath pair).
  2. Live mode — for paper / live trading. Three options: separate URL, derive latest from historical, or disabled.
  3. Buttons — Test Connection, Save Indicator, Cancel.

The dialog seeds one default output row called value so you don't start from a blank repeater. Most indicators only need this one output — you'd add more (e.g. notional value, mark price, premium) only if your API returns multiple useful fields in the same response.

Fill in the historical config

FieldValue
Indicator NameBinance BTC Open Interest
Historical Data URLhttps://fapi.binance.com/futures/data/openInterestHist?symbol=BTCUSDT&period=5m&startTime={start_date}&endTime={end_date}&limit={limit}
Auth Header / API Key(leave blank — public endpoint, no auth needed)
Output → namevalue
Output → value JSONPath$[*].sumOpenInterest
Output → timestamp JSONPath$[*].timestamp
Response Timestamp FormatUnix (seconds or milliseconds)
URL Param Date FormatUnix Milliseconds (Binance, Bybit, OKX)

The placeholders matter. {start_date}, {end_date}, and {limit} get substituted at fetch time. Without them the platform can't ask the API for a specific window.

The JSONPath syntax: $[*].sumOpenInterest means "for every element in the root array, give me the sumOpenInterest field." If you've never seen JSONPath before, $ is the root, [*] matches every array element, and .field is property access. The JSONPath playground is a useful quick reference.

Set the live mode

Scroll down to LIVE MODE. This is the part of the design that the rest of the platform pivots on, so it's worth understanding the three options:

  • Disabled — backtest only. Strategies referencing this indicator can't be deployed live or paper. Useful if the data has no reasonable "current value" representation (e.g., a once-monthly economic release).
  • Separate live URL — the live endpoint is structurally different from the historical one. You provide both.
  • Latest from historical — the live URL is "the historical URL with a tweak" (commonly &limit=1). You give an explicit URL template — no client-side magic. The platform fetches it on the configured interval and uses the most-recent point.

For Binance OI we'll use Latest from historical because it lets us reuse the same JSONPath. The current-value endpoint exists but uses a different field name; sticking with the historical endpoint at &limit=1 keeps the config simpler.

FieldValue
ModeLatest from historical — use a tweaked historical URL...
Latest-from-Historical URLhttps://fapi.binance.com/futures/data/openInterestHist?symbol=BTCUSDT&period=5m&limit=1
Refresh Interval (seconds)300

Why 300 seconds? Binance's OI history has 5-minute granularity, so polling more often than once per 5 minutes just returns the same value. Matching the data cadence avoids wasted requests.

The dialog should now look like this:

External Indicator dialog filled

Click Test Connection

The Test button hits the historical endpoint with a 7-day sample window and parses the response with your JSONPaths. Successful output looks like:

Test connection success

Success! Found 7 data points across 1 output(s) — value: 7 points

That tells you:

  • The URL works (no HTTP error)
  • Your placeholders substituted correctly
  • The JSONPath extracted real numeric values
  • The timestamp parser recognized the format
  • All sample timestamps were inside the requested window

If any of those fails the dialog shows the actual API response in a scrollable preview, so you can see what shape the data really has.

Test only validates historical mode

Test Connection doesn't try the live URL. The live fetch happens on the per-candle refresh loop after Save. If your live URL is broken, you'll see the indicator marked degraded in the right panel within one refresh interval — not at save time.

Save and confirm

Click Save Indicator. The platform creates the indicator and shows it in the right panel under External Indicators:

Indicator listed in panel

Two badges to know:

  • degraded (red) appears when the live fetch has been failing past its refresh interval. Strategies reading the indicator get None rather than a stale value. The badge clears automatically when a fresh fetch succeeds.
  • live disabled (grey) appears for indicators with live_mode='disabled'. Strategies referencing one of these refuse to deploy live with a clear EXTERNAL_INDICATOR_MISSING_LIVE_URL error.

Neither should be present right now — yours is configured for live and the test passed.

Bonus: multi-output (contracts AND notional)

The historical endpoint also returns sumOpenInterestValue — the USD notional. To expose both as outputs from one indicator:

  1. Click the indicator in the panel to edit it (or delete and recreate).
  2. In the Outputs section, click + Add Output.
  3. Add a second row:
    • name: notional
    • value JSONPath: $[*].sumOpenInterestValue
    • timestamp JSONPath: $[*].timestamp
  4. Test and save.

After saving, the Blockly indicator block for "Binance BTC Open Interest" gains a dropdown with two output choices: value (contracts) and notional (USD). Strategies can reference either independently.

This is the multi-output pattern: one config, one fetch, multiple named values. Useful when an API returns several related fields in the same response — saves you from configuring the same endpoint twice.

What you just built

You now have an indicator that:

  • Fetches Binance OI history on demand for any backtest range
  • Polls the latest OI value every 5 minutes for live and paper trading
  • Appears in the Blockly Indicators category as Binance BTC Open Interest Output value — draggable into any strategy
  • Appears in the Signals source dropdown so you can build named conditions like "OI Spike = Binance BTC Open Interest Output value > 100000"

Example: using it in a strategy

Once the indicator exists, dropping it into a strategy is just another block. You can drag Binance BTC Open Interest Output from the Indicators category in the Blockly toolbox and use it like any other indicator value — feed it into a comparison block, combine it with other conditions, store it in a flag, whatever fits the strategy.

Or you can let the AI builder do it. Here's a strategy generated from the prompt "long-only BTC/USDT 1h, enter when RSI crosses up through 50 AND open interest is greater than 95000, exit when RSI crosses below 50, with 2% stop loss and 4% take profit, position size 5% of equity, one position at a time":

Strategy referencing the OI indicator

The OI block sits inline with the RSI condition: RSI Output > 50 AND Binance BTC Open Interest Output value > 95000 AND not has open position → open long. No special wiring, no signal wrapper, just a numeric comparison.