Code Playbook

Funding Rate Arbitrage Monitor in Python

Poll one API for funding-rate divergence across Bybit, Binance, and Hyperliquid instead of maintaining three separate exchange integrations.

~10 min readPython 3.8+Public endpoint, no key required

The Problem: 3 Exchanges, 1 Spread

Perpetual futures funding rates rarely match across venues. Bybit, Binance, and Hyperliquid each compute funding independently from their own order books, and at any given moment one exchange can be paying longs while another is paying shorts on the same symbol. That divergence is the raw material for a market-neutral funding-rate arbitrage: go long on the exchange with the lower (or negative) funding rate, short an equivalent notional on the exchange with the higher rate, and collect the difference every funding period — while the price exposure on the two legs cancels out.

The mechanical idea is simple. Actually watching for it is not. Doing this by hand means opening three exchange APIs, mapping their symbol lists and funding intervals to each other, normalizing the units (some report per-8h, some per-hour, some annualized), and re-checking all of it every few minutes across however many symbols you care about. Bybit alone lists funding for 500+ perpetuals. Do that across three exchanges and you are maintaining three rate-limited clients, three response schemas, and a symbol-reconciliation layer before you've written a single line of arbitrage logic.

This playbook replaces all of that with one HTTP call. Smart Money API already samples funding rates from Bybit, Binance, and Hyperliquid, normalizes them onto a common per-8h basis, computes the cross-exchange spread and an annualized APR, and hands you a ranked list of opportunities. Your job becomes: poll, filter by a threshold you choose, and act (or just log it and watch).

Prerequisites

You'll need:

No account needed to follow along. GET /v1/derivatives/funding-arb is a public endpoint. It returns the top 10 opportunities by spread size — enough to build and test the monitor below.

The Endpoint

GET https://api.smartmoneyapi.com/v1/derivatives/funding-arb takes no required query parameters. It refreshes roughly every 2 minutes server-side, so polling more often than that just re-fetches the same snapshot. Each opportunity in the response includes which exchange to go long on (the one with the lower funding rate) and which to short (the higher rate), the spread itself, an annualized APR for comparing opportunities at a glance, and a mechanical profit estimate per $10,000 of notional for a single funding period.

Read this before you build anything on top of it: estimated_profit_per_10k_per_8h is a mechanical spread calculation for one 8-hour funding period (see profit_horizon_hours on the same object), assuming the spread holds and ignoring fees, slippage, and withdrawal/transfer time between exchanges. It is not a backtested return and not a promise of profit. Funding rates resettle roughly every 8 hours, and spreads can close — or reverse — before you can actually enter both legs. Treat this as a monitoring signal to investigate, not an executable guarantee.

Python Monitor Script

This script polls the endpoint on a loop, prints a summary each cycle, and raises a console alert for any symbol whose spread crosses your chosen threshold. It uses a persistent requests.Session(), reads an optional API key from the SMARTMONEY_API_KEY environment variable, and handles timeouts and connection errors without crashing the loop.

python
#!/usr/bin/env python3 """ funding_arb_monitor.py — polls Smart Money API for funding-rate divergence between Bybit, Binance, and Hyperliquid and prints a console alert whenever a spread crosses your threshold. Public endpoint, no API key required. Set SMARTMONEY_API_KEY if you have one (optional, doesn't change this endpoint's response, but keeps the habit for endpoints that DO require it). """ import os import time import requests BASE_URL = "https://api.smartmoneyapi.com" ENDPOINT = "/v1/derivatives/funding-arb" POLL_SECONDS = 120 # matches the API's own refresh cycle SPREAD_THRESHOLD_PCT = 0.01 # only alert on spreads above this (%) session = requests.Session() api_key = os.environ.get("SMARTMONEY_API_KEY") headers = {"X-API-Key": api_key} if api_key else {} def poll_once(): try: resp = session.get(BASE_URL + ENDPOINT, headers=headers, timeout=10) resp.raise_for_status() except requests.exceptions.Timeout: print("[warn] request timed out, will retry next cycle") return except requests.exceptions.RequestException as e: print(f"[error] request failed: {e}") return data = resp.json() opportunities = data.get("opportunities", []) scanned = data.get("scanned_symbols", 0) print(f"[{time.strftime('%H:%M:%S')}] scanned {scanned} symbols, " f"{len(opportunities)} opportunities returned") for opp in opportunities: if opp["spread_pct"] < SPREAD_THRESHOLD_PCT: continue print( f" ALERT {opp['symbol']}: spread {opp['spread_pct']:.4f}% " f"({opp['annualized_apr']:.2f}% annualized) — {opp['action']} " f"— est. ${opp['estimated_profit_per_10k_per_8h']:.2f} per $10k/8h " f"— {opp['risk_notes']}" ) def main(): print("Starting funding-rate arbitrage monitor " f"(polling every {POLL_SECONDS}s, threshold {SPREAD_THRESHOLD_PCT}%)") while True: poll_once() time.sleep(POLL_SECONDS) if __name__ == "__main__": main()

JavaScript / Node.js Variant

The same single-poll logic in Node.js (18+) using the built-in fetch — no npm dependencies. Wrap the pollOnce() call in a setInterval if you want the same 120-second loop as the Python version.

javascript
// funding_arb_monitor.js — Node.js, no external dependencies // (uses the global fetch available in Node 18+) const BASE_URL = "https://api.smartmoneyapi.com"; const ENDPOINT = "/v1/derivatives/funding-arb"; const SPREAD_THRESHOLD_PCT = 0.01; async function pollOnce() { const headers = {}; if (process.env.SMARTMONEY_API_KEY) { headers["X-API-Key"] = process.env.SMARTMONEY_API_KEY; } let resp; try { resp = await fetch(BASE_URL + ENDPOINT, { headers, signal: AbortSignal.timeout(10000) }); } catch (err) { console.error("[error] request failed:", err.message); return; } if (!resp.ok) { console.error(`[error] HTTP ${resp.status}`); return; } const data = await resp.json(); const opportunities = data.opportunities || []; console.log(`[${new Date().toTimeString().slice(0, 8)}] scanned ${data.scanned_symbols} symbols, ${opportunities.length} opportunities`); for (const opp of opportunities) { if (opp.spread_pct < SPREAD_THRESHOLD_PCT) continue; console.log( ` ALERT ${opp.symbol}: spread ${opp.spread_pct.toFixed(4)}% ` + `(${opp.annualized_apr.toFixed(2)}% annualized) — ${opp.action} ` + `— est. $${opp.estimated_profit_per_10k_per_8h.toFixed(2)} per $10k/8h — ${opp.risk_notes}` ); } } pollOnce();
Want the full opportunity list, not just the top 10?

The public endpoint caps results at the 10 largest spreads. A free account still gets you 200 calls/day on this endpoint plus the rest of the public data surface — upgrade later if you need more.

Create a free account →

Expected Output

A single poll of the public endpoint returns JSON shaped like this (fields trimmed to one opportunity for readability — the live response can include up to 10):

json
{ "opportunities": [ { "symbol": "BTC", "spread_pct": 0.0142, "annualized_apr": 15.55, "long_exchange": "bybit", "long_funding": -0.00003, "short_exchange": "binance", "short_funding": 0.00011, "action": "Long BTC on bybit / Short on binance", "estimated_profit_per_10k_per_8h": 1.42, "profit_horizon_hours": 8, "risk_notes": "Low spread — ensure fees do not consume the arbitrage margin.", "exchanges_sampled": 3 } ], "scanned_symbols": 42, "ts": 1753300000, "public": true, "limited": true }

The Python script above would turn that BTC row into a console line reading something like: ALERT BTC: spread 0.0142% (15.55% annualized) — Long BTC on bybit / Short on binance — est. $1.42 per $10k/period — Low spread — ensure fees do not consume the arbitrage margin.

What to Build Next

Once the monitor loop above is running reliably, a few natural next steps:

Full field reference and every other derivatives endpoint (heatmap, screener, historical funding/OI/LSR) is documented at /docs. More playbooks like this one are collected at /resources/playbooks.

Skip the three exchange integrations

One API key gets you normalized funding, open interest, and long/short ratio data across Bybit, Binance, and Hyperliquid — plus on-chain, options, and whale-flow data on the same key.

See plans and limits
Start free — 200 calls/day, no card

Get live whale flow, funding, open interest and on-chain data across 3 exchanges from one API. Free tier, no credit card, upgrade any time.

Start free →
Try the live API console → (no account needed)