Backtest a Funding-Rate Strategy with Historical Data in Python
"Go long the exchange with lower funding, short the one with higher funding when the spread exceeds X" is a common first idea for a funding-rate strategy. This playbook shows how to pull the historical data you'd need to check it in Python — and, just as importantly, what a backtest like this can and can't tell you.
The problem: did this rule actually pay you funding?
Perpetual futures funding rates are public, but turning "funding on exchange A has been higher than exchange B for the last few weeks" into an actual backtest means pulling a time series of funding rates per exchange, aligning it with price data, and running some rule over it consistently instead of eyeballing a chart. That's a data-wrangling problem before it's a strategy problem — and it's the same wrangling regardless of which funding rule you end up testing.
This playbook pulls historical funding rate data and historical price data from two public endpoints, loads them into pandas, and runs a simple vectorized rule so you have working code for the data-handling part. It does not claim the rule is profitable — see the caveats section below for why that claim would be premature from this alone.
Prerequisites
Both endpoints used here are public per the current routing — no API key required, subject to a shared per-IP rate limit (150 requests/minute). You'll need:
- Python 3.8+,
requests, andpandas(pip install requests pandas)
The endpoints
GET https://api.smartmoneyapi.com/v1/historical/funding?symbol=BTCUSDT&days=30&limit=5000
Query params: symbol (default "BTCUSDT" — note the USDT suffix, unlike some other endpoints in this API that use bare "BTC"), days (clamped 1-365, default 30), limit (clamped 1-5000, default 5000). Response:
Rows include an exchange field (e.g. "binance", "bybit") — if you want to compare exchange A vs exchange B, pull the symbol once and filter/group by exchange client-side, rather than issuing separate calls per exchange.
GET https://api.smartmoneyapi.com/v1/historical/market?coin=bitcoin&days=365&limit=5000
coin is a CoinGecko coin id (e.g. "bitcoin", "ethereum"). Response:
Note this is a price / market-cap / volume time series, not OHLCV candles — there's no open/high/low column, just one price point per row. Fine for aligning against funding timestamps; not a substitute for candlestick data if your rule needs intra-period highs and lows.
Two sibling endpoints exist for extending this: GET /v1/historical/open-interest?symbol=&days=&limit= (rows: timestamp, symbol, exchange, oi, oi_value) and GET /v1/historical/long-short?symbol=&days=&limit= (rows: timestamp, symbol, type, long_ratio, short_ratio). Same public access pattern, same module. Useful for adding OI or positioning context to a backtest — not built into the example below.
Python script: pull data + run a simple backtest
This pulls funding history for one symbol, filters to a single exchange, computes the annualized rate, applies a threshold rule, and sums a simple pre-fee "funding collected" column. It deliberately does not print a win-rate, Sharpe ratio, or profit factor — those numbers invite treating this as proof of an edge, which a 30-day, single-symbol, no-slippage accumulation is not.
Open interest and long/short ratio history live on the same base URL, same free tier — no separate signup for each data type.
Get your free API key →Expected output
That's a data-wrangling result, not a trading result: it tells you the mechanics work (data loads, threshold flags fire, sums accumulate) — it says nothing yet about whether the rule would have been profitable after execution costs, or whether the pattern persists going forward.
Why this is harder than it looks
A few things this simple example glosses over, on purpose, so they don't get buried:
- Curve-fitting on the lookback window. Pick a 30-day window, get one answer; pick 90 days or a different start date, get a different answer. A single backtest window is a single sample, not a robust estimate. If you tune the threshold to whatever number maximizes the result on this window, you've fit to noise in that window, not found a rule.
- Funding data alone doesn't capture execution risk. A cross-exchange funding-arb rule requires opening a position on two venues near-simultaneously, and closing both legs together. Slippage, withdrawal delays, leg-timing risk (one side fills, the other doesn't), and exchange-specific liquidity are all real costs that a funding-rate time series says nothing about.
- In-sample results are not out-of-sample proof. Even a clean-looking accumulation curve over historical data tells you what happened on that data, in that period, under that rule. It does not tell you the rule will keep working — regimes shift, funding dynamics change, and a rule discovered by looking at the past is, by construction, fit to the past.
- This company's own research says so. Across roughly eight internal studies on this kind of data (funding, whale flow, derivatives positioning, combined signals), we did not find a durable, out-of-sample predictive edge. That's published, not hidden — the honest read is that historical funding/price data is useful for understanding market structure and building tools, and a coding exercise like this one is good practice for backtesting methodology, but it is not a trading recommendation and shouldn't be treated as one.
What to build next
- Add open interest context from
/v1/historical/open-interestto see whether funding spikes coincide with OI buildup or unwinding. - Run the same rule across multiple disjoint windows (e.g. 3 separate 30-day periods from different months) instead of one lookback, and compare results — if they disagree wildly, that's the curve-fitting problem showing up directly.
- Pull long/short ratio from
/v1/historical/long-shortalongside funding to see if crowded positioning lines up with the funding extremes you're flagging. - Model fees and slippage explicitly before drawing any conclusion about profitability — a backtest without transaction costs systematically overstates results.
All of this comes from the same API key, alongside derivatives, whale, and on-chain data across 66+ endpoints — instead of separately integrating Binance, Bybit, and Hyperliquid funding feeds plus a CoinGecko price feed yourself.