Binance Perpetual Funding API: Trader's Complete Guide
Learn how to fetch, parse, and automate Binance perpetual funding rate data via API — with Python code examples, authentication setup, and real trading strategies.
Learn how to fetch, parse, and automate Binance perpetual funding rate data via API — with Python code examples, authentication setup, and real trading strategies.
Funding rates are one of the most overlooked edges in perpetual futures trading. Every 8 hours, longs pay shorts — or shorts pay longs — depending on market sentiment. If you're manually refreshing the Binance interface to check these rates, you're already behind. The Binance perpetual funding API gives you programmatic access to historical and real-time funding data, and building around it can meaningfully improve both your entries and your carry strategies.
Unlike traditional futures, perpetual contracts on Binance, Bybit, and OKX don't have an expiry date. To keep the contract price anchored to the spot price, exchanges use a funding mechanism: traders on the dominant side pay the minority side every 8 hours. When the market is heavily long (bullish sentiment), longs pay shorts. When shorts dominate, shorts pay longs.
Binance calculates the funding rate using a formula that combines the interest rate component (fixed at 0.01% per day) and the premium index — the gap between the perpetual mark price and the spot index price. The resulting rate is applied at 00:00, 08:00, and 16:00 UTC every day.
A consistently positive funding rate (0.05%+ per 8h) signals extreme long crowding — historically a useful contrarian indicator. Platforms like VoiceOfChain aggregate funding data across exchanges and surface these extremes as actionable signals.
| Exchange | Funding Interval | Rate Cap | Historical Data via API |
|---|---|---|---|
| Binance | 8 hours | ±0.75% | Yes, full history |
| Bybit | 8 hours | ±0.75% | Yes, full history |
| OKX | 8 hours | ±2.00% | Yes, limited depth |
| Bitget | 8 hours | ±0.75% | Yes |
| Gate.io | 8 hours | ±0.75% | Partial |
The funding rate endpoints on Binance are split between public and authenticated routes. Historical funding rates are public — no API key needed. If you want to check your own funding payments or positions, you'll need keys. Start by generating an API key in your Binance account under API Management, and restrict it to read-only for safety.
import hmac
import hashlib
import time
import requests
from urllib.parse import urlencode
API_KEY = "your_api_key_here"
SECRET_KEY = "your_secret_key_here"
BASE_URL = "https://fapi.binance.com"
def get_signed_params(params: dict) -> dict:
params["timestamp"] = int(time.time() * 1000)
query_string = urlencode(params)
signature = hmac.new(
SECRET_KEY.encode("utf-8"),
query_string.encode("utf-8"),
hashlib.sha256
).hexdigest()
params["signature"] = signature
return params
def get_headers() -> dict:
return {"X-MBX-APIKEY": API_KEY}
Note the base URL: `fapi.binance.com` is the USDⓈ-M futures endpoint. If you're working with COIN-M perpetuals (BTC-settled), use `dapi.binance.com` instead. This distinction trips up a lot of developers who mix up the two.
The two most useful endpoints are the current funding rate (premium index) and the historical funding rate archive. Here's how to work with both:
import requests
BASE_URL = "https://fapi.binance.com"
def get_current_funding_rate(symbol: str) -> dict:
"""Fetch current funding rate and next funding time."""
url = f"{BASE_URL}/fapi/v1/premiumIndex"
params = {"symbol": symbol}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
return {
"symbol": data["symbol"],
"funding_rate": float(data["lastFundingRate"]),
"next_funding_time": data["nextFundingTime"],
"mark_price": float(data["markPrice"]),
"index_price": float(data["indexPrice"])
}
def get_historical_funding_rates(symbol: str, limit: int = 100) -> list:
"""Fetch last N historical funding rate records."""
url = f"{BASE_URL}/fapi/v1/fundingRate"
params = {"symbol": symbol, "limit": limit}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
records = response.json()
return [
{
"symbol": r["symbol"],
"funding_rate": float(r["fundingRate"]),
"funding_time": r["fundingTime"]
}
for r in records
]
# Example usage
if __name__ == "__main__":
current = get_current_funding_rate("BTCUSDT")
print(f"BTC Funding Rate: {current['funding_rate'] * 100:.4f}%")
print(f"Next Funding: {current['next_funding_time']}")
history = get_historical_funding_rates("ETHUSDT", limit=10)
for record in history:
print(f"{record['funding_time']}: {float(record['funding_rate']) * 100:.4f}%")
The `lastFundingRate` field in the premium index response shows the rate from the most recently settled window — not the predicted next rate. For the predicted rate, monitor the `premiumIndex` field and apply Binance's formula, or poll frequently near funding settlement time.
Raw data is only useful if it triggers action. A common pattern is to poll the API every few minutes and send an alert when rates cross meaningful thresholds — say, above 0.1% per 8h (annualizes to over 100% APR) or below -0.05%. Here's a minimal implementation with error handling:
import requests
import time
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
BASE_URL = "https://fapi.binance.com"
WATCHLIST = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT"]
HIGH_THRESHOLD = 0.001 # 0.1% per 8h
LOW_THRESHOLD = -0.0005 # -0.05% per 8h
def fetch_all_funding_rates(symbols: list) -> dict:
results = {}
for symbol in symbols:
try:
url = f"{BASE_URL}/fapi/v1/premiumIndex"
resp = requests.get(url, params={"symbol": symbol}, timeout=8)
resp.raise_for_status()
data = resp.json()
results[symbol] = float(data["lastFundingRate"])
except requests.exceptions.Timeout:
logger.warning(f"Timeout fetching {symbol} — skipping")
except requests.exceptions.HTTPError as e:
logger.error(f"HTTP error for {symbol}: {e}")
except (KeyError, ValueError) as e:
logger.error(f"Parse error for {symbol}: {e}")
return results
def check_and_alert(rates: dict):
for symbol, rate in rates.items():
if rate >= HIGH_THRESHOLD:
logger.info(f"ALERT: {symbol} funding HIGH at {rate*100:.4f}% — consider shorting or exit longs")
elif rate <= LOW_THRESHOLD:
logger.info(f"ALERT: {symbol} funding LOW at {rate*100:.4f}% — shorts paying, consider longs")
def run_monitor(interval_seconds: int = 300):
logger.info("Starting funding rate monitor...")
while True:
rates = fetch_all_funding_rates(WATCHLIST)
check_and_alert(rates)
logger.info(f"Checked {len(rates)} symbols. Next check in {interval_seconds}s")
time.sleep(interval_seconds)
if __name__ == "__main__":
run_monitor()
This pattern is the foundation of more sophisticated systems. Services like VoiceOfChain take this further — aggregating funding data across Binance, Bybit, and OKX simultaneously to surface cross-exchange arbitrage opportunities and divergence signals that a single-exchange monitor would miss.
Once you have reliable funding data, two strategies become accessible. The first is funding rate arbitrage: when Binance perpetual funding on BTCUSDT runs significantly higher than on Bybit or Bitget, you can short on Binance (collecting funding) and long on Bybit (paying less). Delta-neutral, pure carry. The second is carry trading: go long spot BTC while shorting the perpetual on Binance. You collect funding from longs while hedging your price exposure.
The Binance perpetual funding API is one of the most underutilized data sources in retail algo trading. The endpoints are free, well-documented, and the data is actionable — whether you're building a carry strategy, scanning for crowded trades, or setting up cross-exchange arbitrage between Binance, Bybit, and OKX. Start with the public endpoints, get comfortable with the data structure, then layer in the monitoring and alerting logic. The traders with an edge in perpetuals aren't necessarily faster — they're just reading signals that others are ignoring.