◈   ⌘ api · Intermediate

Bybit Predicted Funding Rate API: A Trader's Guide

Learn to query Bybit's predicted funding rate API, parse live data, and automate perpetual futures strategies before the next settlement window hits.

Uncle Solieditor · voc · 18.05.2026 ·views 2
◈   Contents
  1. → What the Predicted Funding Rate Actually Measures
  2. → Bybit V5 API Endpoints for Funding Rate Data
  3. → Querying the Predicted Funding Rate in Python
  4. → Scanning Multiple Symbols and Historical Rate Lookup
  5. → Adding Authentication for Position-Aware Strategies
  6. → Error Handling, Rate Limits, and Production Hardening
  7. → Frequently Asked Questions
  8. → Conclusion

Funding rates are one of the most exploitable signals in crypto derivatives — and most traders ignore them until settlement has already happened. Bybit exposes a predicted funding rate through its public V5 API, giving you a window into where the rate is heading before the 8-hour settlement fires. If you know how to query that endpoint programmatically, you can automate exits, size positions more carefully, or capture funding arbitrage across platforms like Bybit and Binance. This guide walks through the entire flow: endpoint structure, authentication, live code, response parsing, and error handling.

What the Predicted Funding Rate Actually Measures

Perpetual futures contracts on Bybit, Binance, OKX, and most other major derivatives venues don't have an expiry date — instead, they stay anchored to spot price through a periodic payment called the funding rate. Every 8 hours (on most platforms), longs pay shorts or vice versa, depending on whether the perpetual is trading at a premium or discount to the underlying index.

The predicted funding rate is exactly what the name implies: the rate that will apply at the next settlement, calculated in real-time based on the current premium index. Bybit recalculates it continuously, so querying the API at T-30 minutes before settlement gives you a reasonably accurate picture of what you'll pay or receive. The further out you query, the more it can drift — but within 15 minutes of settlement, the predicted value converges tightly to the final rate.

The predicted funding rate is not guaranteed — it reflects current market conditions and will change if the premium index moves. Always build margin for drift into any strategy that depends on a specific rate value.

Why does this matter strategically? Because a funding rate of +0.1% per 8 hours annualizes to over 100%. At those levels, holding a leveraged long becomes expensive fast. Conversely, being short when funding is deeply positive means passive income on your position. Traders who read the predicted rate before it finalizes can rotate or add positions with a real edge — and that edge comes from fast, programmatic data access.

Bybit V5 API Endpoints for Funding Rate Data

Bybit's V5 API is organized around a category parameter — for perpetual futures (USDT-margined linear contracts), you'll always pass category=linear. There are two endpoints relevant to funding rate work. The first is the tickers endpoint, which returns live market data including the predicted funding rate and the timestamp of the next settlement. The second is the funding history endpoint, which returns past rates useful for backtesting and normalization.

Bybit V5 API Funding Rate Endpoints
EndpointMethodAuth RequiredReturns
/v5/market/tickersGETNoPredicted funding rate + next settlement time
/v5/market/funding/historyGETNoHistorical funding rate records
/v5/market/instruments-infoGETNoFunding interval, settlement schedule
/v5/position/listGETYesYour open positions with funding impact

Both tickers and funding history are public endpoints — no API key needed to read them. Authentication is only required when you move to position data or want to act on what you read. That makes prototyping fast: you can build and test your entire data pipeline before wiring up any credentials.

Querying the Predicted Funding Rate in Python

The simplest way to get the current predicted funding rate for a symbol is a single GET request to the tickers endpoint with a symbol filter. Here's a minimal working example that fetches and prints the predicted rate for BTCUSDT:

import requests

BASE_URL = "https://api.bybit.com"

def get_predicted_funding_rate(symbol: str) -> dict:
    """Fetch predicted funding rate from Bybit V5 tickers endpoint."""
    url = f"{BASE_URL}/v5/market/tickers"
    params = {
        "category": "linear",
        "symbol": symbol
    }
    response = requests.get(url, params=params, timeout=10)
    response.raise_for_status()
    data = response.json()

    if data["retCode"] != 0:
        raise ValueError(f"Bybit API error {data['retCode']}: {data['retMsg']}")

    ticker = data["result"]["list"][0]
    return {
        "symbol": ticker["symbol"],
        "predicted_funding_rate": float(ticker["fundingRate"]),
        "next_funding_time_ms": int(ticker["nextFundingTime"]),
        "mark_price": float(ticker["markPrice"]),
        "index_price": float(ticker["indexPrice"])
    }

if __name__ == "__main__":
    result = get_predicted_funding_rate("BTCUSDT")
    rate_pct = result["predicted_funding_rate"] * 100
    print(f"Symbol: {result['symbol']}")
    print(f"Predicted Funding Rate: {rate_pct:.4f}%")
    print(f"Next Settlement (ms): {result['next_funding_time_ms']}")

The fundingRate field in the response is a decimal — multiply by 100 to get a percentage. A value of 0.0001 means 0.01%, which is the default baseline on most platforms. Positive values mean longs pay shorts; negative values reverse that. The nextFundingTime is a Unix timestamp in milliseconds, which you can convert to a human-readable countdown with a simple datetime subtraction.

This pattern works identically for any linear perpetual on Bybit — ETHUSDT, SOLUSDT, DOGEUSDT. Swap the symbol string and the response structure stays the same. If you want to scan multiple symbols at once, you can call the endpoint without a symbol filter and receive the full list, though the response will be larger and worth paginating.

Scanning Multiple Symbols and Historical Rate Lookup

A single-symbol query is fine for monitoring, but most interesting strategies involve scanning across assets — finding which perpetuals have the most extreme predicted rates right now. Bybit lets you pull all linear tickers in one call and filter client-side. Here's an extended example that scans for outliers and also pulls 10 historical rate records for context:

import requests
from datetime import datetime

BASE_URL = "https://api.bybit.com"

def scan_all_funding_rates(threshold: float = 0.0005) -> list[dict]:
    """Return all symbols where abs(predicted funding rate) >= threshold."""
    url = f"{BASE_URL}/v5/market/tickers"
    params = {"category": "linear"}
    response = requests.get(url, params=params, timeout=15)
    response.raise_for_status()
    data = response.json()

    if data["retCode"] != 0:
        raise ValueError(f"API error: {data['retMsg']}")

    results = []
    for ticker in data["result"]["list"]:
        # Some tickers may not have fundingRate (inverse, spot, etc.)
        rate_str = ticker.get("fundingRate")
        if rate_str is None:
            continue
        rate = float(rate_str)
        if abs(rate) >= threshold:
            next_ts = int(ticker["nextFundingTime"]) / 1000
            minutes_to_settlement = (next_ts - datetime.now().timestamp()) / 60
            results.append({
                "symbol": ticker["symbol"],
                "rate": rate,
                "rate_pct": round(rate * 100, 4),
                "minutes_to_settlement": round(minutes_to_settlement, 1),
                "direction": "longs_pay" if rate > 0 else "shorts_pay"
            })

    return sorted(results, key=lambda x: abs(x["rate"]), reverse=True)

def get_funding_history(symbol: str, limit: int = 10) -> list[dict]:
    """Fetch historical funding rate records for a symbol."""
    url = f"{BASE_URL}/v5/market/funding/history"
    params = {
        "category": "linear",
        "symbol": symbol,
        "limit": limit
    }
    response = requests.get(url, params=params, timeout=10)
    response.raise_for_status()
    data = response.json()

    if data["retCode"] != 0:
        raise ValueError(f"API error: {data['retMsg']}")

    return [
        {
            "symbol": record["symbol"],
            "rate": float(record["fundingRate"]),
            "timestamp_ms": int(record["fundingRateTimestamp"])
        }
        for record in data["result"]["list"]
    ]

if __name__ == "__main__":
    print("=== High Funding Rate Symbols ===")
    outliers = scan_all_funding_rates(threshold=0.0003)
    for item in outliers[:10]:
        print(f"{item['symbol']}: {item['rate_pct']}% ({item['direction']}) "
              f"— {item['minutes_to_settlement']}min to settlement")

    print("\n=== BTCUSDT Funding History ===")
    history = get_funding_history("BTCUSDT", limit=5)
    for h in history:
        ts = datetime.fromtimestamp(h['timestamp_ms'] / 1000)
        print(f"{ts.strftime('%Y-%m-%d %H:%M')} — {h['rate'] * 100:.4f}%")

The scan_all_funding_rates function is particularly useful as an input to a signal layer. Platforms like VoiceOfChain aggregate this kind of cross-market data and surface extreme funding rate divergences as actionable signals — but knowing how to build it yourself means you can customize thresholds, combine with open interest data, and feed results directly into your own execution pipeline.

Adding Authentication for Position-Aware Strategies

Reading funding rates is public. Checking whether your open positions are exposed to an upcoming settlement — or placing an order in response — requires authenticated requests. Bybit V5 uses HMAC-SHA256 signatures. Here's a minimal authenticated client that checks your current positions and calculates upcoming funding cost:

import hashlib
import hmac
import time
import requests
import os

API_KEY = os.getenv("BYBIT_API_KEY")
API_SECRET = os.getenv("BYBIT_API_SECRET")
BASE_URL = "https://api.bybit.com"

def bybit_signed_get(path: str, params: dict) -> dict:
    """Make an authenticated GET request to Bybit V5 API."""
    timestamp = str(int(time.time() * 1000))
    recv_window = "5000"

    # Build query string for signing
    query_string = "&".join(f"{k}={v}" for k, v in sorted(params.items()))
    sign_payload = f"{timestamp}{API_KEY}{recv_window}{query_string}"
    signature = hmac.new(
        API_SECRET.encode("utf-8"),
        sign_payload.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    headers = {
        "X-BAPI-API-KEY": API_KEY,
        "X-BAPI-SIGN": signature,
        "X-BAPI-TIMESTAMP": timestamp,
        "X-BAPI-RECV-WINDOW": recv_window
    }
    url = f"{BASE_URL}{path}"
    response = requests.get(url, params=params, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()

def get_open_positions_with_funding_cost():
    """List open linear positions with estimated funding cost at next settlement."""
    pos_data = bybit_signed_get("/v5/position/list", {
        "category": "linear",
        "settleCoin": "USDT"
    })

    if pos_data["retCode"] != 0:
        raise ValueError(f"Error fetching positions: {pos_data['retMsg']}")

    results = []
    for pos in pos_data["result"]["list"]:
        if float(pos["size"]) == 0:
            continue

        # Fetch predicted funding rate for this symbol
        ticker_resp = requests.get(
            f"{BASE_URL}/v5/market/tickers",
            params={"category": "linear", "symbol": pos["symbol"]},
            timeout=5
        ).json()
        ticker = ticker_resp["result"]["list"][0]
        predicted_rate = float(ticker["fundingRate"])
        position_value = float(pos["positionValue"])
        side_multiplier = 1 if pos["side"] == "Buy" else -1
        estimated_pnl = position_value * predicted_rate * side_multiplier * -1

        results.append({
            "symbol": pos["symbol"],
            "side": pos["side"],
            "size": pos["size"],
            "predicted_rate_pct": round(predicted_rate * 100, 4),
            "estimated_funding_pnl": round(estimated_pnl, 4)
        })

    return results

if __name__ == "__main__":
    positions = get_open_positions_with_funding_cost()
    for p in positions:
        sign = "+" if p["estimated_funding_pnl"] >= 0 else ""
        print(f"{p['symbol']} {p['side']} {p['size']} | "
              f"Rate: {p['predicted_rate_pct']}% | "
              f"Est. PnL: {sign}{p['estimated_funding_pnl']} USDT")
Store your BYBIT_API_KEY and BYBIT_API_SECRET in environment variables — never hardcode credentials in scripts. Use read-only API keys when you only need to read position data; only enable trading permissions when the bot actually needs to place orders.

The estimated funding PnL calculation here is approximate. The actual settlement uses the mark price at settlement time, not the current mark price. For monitoring purposes it's accurate enough; for exact accounting, pull the realized funding from your trade history after settlement fires. Comparing Bybit's predicted rates against what you'd see on OKX or Bitget is also useful — when rates diverge significantly between platforms, that gap itself can be a signal.

Error Handling, Rate Limits, and Production Hardening

Production-grade funding rate monitoring needs to handle network failures, API rate limits, and stale data gracefully. Bybit's public endpoints have a rate limit of roughly 120 requests per minute per IP for market data. If you're scanning all symbols every few seconds you'll hit that ceiling. The right architecture is an in-process cache with a TTL aligned to how fast the predicted rate realistically moves.

import time
import requests
import threading
from functools import wraps

BASE_URL = "https://api.bybit.com"

# Thread-safe cache with TTL
_cache: dict = {}
_cache_lock = threading.Lock()

def cached(ttl_seconds: int):
    """Decorator: cache function result by args for ttl_seconds."""
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            key = (fn.__name__, args, tuple(sorted(kwargs.items())))
            with _cache_lock:
                entry = _cache.get(key)
                if entry and time.monotonic() - entry["ts"] < ttl_seconds:
                    return entry["value"]
            result = fn(*args, **kwargs)
            with _cache_lock:
                _cache[key] = {"value": result, "ts": time.monotonic()}
            return result
        return wrapper
    return decorator

def bybit_get_with_retry(url: str, params: dict, retries: int = 3) -> dict:
    """GET with exponential backoff on 429 or transient errors."""
    for attempt in range(retries):
        try:
            response = requests.get(url, params=params, timeout=8)
            if response.status_code == 429:
                wait = 2 ** attempt
                print(f"Rate limited — waiting {wait}s")
                time.sleep(wait)
                continue
            response.raise_for_status()
            data = response.json()
            if data["retCode"] not in (0, 10001):  # 10001 = not modified
                raise ValueError(f"Bybit error {data['retCode']}: {data['retMsg']}")
            return data
        except requests.exceptions.ConnectionError as e:
            if attempt == retries - 1:
                raise
            time.sleep(1.5 ** attempt)
    raise RuntimeError(f"Failed after {retries} attempts: {url}")

@cached(ttl_seconds=30)
def get_funding_rate_cached(symbol: str) -> float:
    """Return predicted funding rate, cached for 30 seconds."""
    url = f"{BASE_URL}/v5/market/tickers"
    data = bybit_get_with_retry(url, {"category": "linear", "symbol": symbol})
    return float(data["result"]["list"][0]["fundingRate"])

# Usage
rate = get_funding_rate_cached("BTCUSDT")
print(f"BTCUSDT predicted rate: {rate * 100:.4f}%")

For a high-frequency monitoring loop — say, watching 20 symbols every 15 seconds — a 30-second cache per symbol means you're making around 40 unique requests per minute, well under the rate limit. If you need fresher data, consider Bybit's WebSocket stream for funding rate updates, which pushes data rather than requiring polling. The REST API is fine for strategy triggers; WebSocket is better for latency-sensitive execution. When comparing approaches across platforms, Binance's linear API follows a nearly identical pattern — making it straightforward to build cross-exchange monitoring that covers both.

Frequently Asked Questions

Does Bybit's predicted funding rate update in real time?
Yes — Bybit recalculates the predicted rate continuously based on the current premium index. The value returned by the /v5/market/tickers endpoint is as fresh as your last API call. For near-settlement precision, query within 15 minutes of the scheduled settlement time.
Do I need an API key to read the predicted funding rate?
No. The /v5/market/tickers and /v5/market/funding/history endpoints are fully public. Authentication is only required if you need to read your own position data or place orders. You can prototype and test your entire data pipeline without credentials.
How often do funding settlements happen on Bybit?
Most linear USDT perpetuals on Bybit settle every 8 hours — at 00:00, 08:00, and 16:00 UTC. Some newer or exotic contracts may have different intervals. Check the /v5/market/instruments-info endpoint for fundingInterval on any specific symbol.
Can I use the same code pattern for Binance or OKX?
The concept is identical, but endpoints and response formats differ. Binance uses /fapi/v1/premiumIndex for predicted funding; OKX uses /api/v5/public/funding-rate. Response fields have different names, so you'll need a thin adapter layer if you're building a cross-exchange scanner.
What happens to my position if I hold through a high funding settlement?
The funding payment is deducted from or added to your unrealized PnL at settlement. If you're long and the rate is positive, your account balance decreases by (position value × rate). Large rates — above 0.1% — can meaningfully erode a leveraged position over multiple 8-hour windows.
How does VoiceOfChain use funding rate data?
VoiceOfChain monitors predicted funding rates across multiple exchanges in real time and surfaces outlier conditions — like extreme positive rates on low-cap perpetuals — as trading signals. The platform aggregates this with open interest and order flow data to give context that a raw API call alone can't provide.

Conclusion

Bybit's predicted funding rate API is one of the more underused edges available to algo traders. The data is public, well-documented, and consistently structured — meaning you can go from zero to a working scanner in under 50 lines of Python. The real leverage comes from what you do with the data: building scanners that surface extreme rates across assets, wiring up position-aware alerts that warn you before a costly settlement, or feeding the signal into VoiceOfChain alongside order flow for richer context. Exchanges like Binance, OKX, and Bitget expose similar endpoints, so the architecture you build here scales to cross-platform arbitrage monitoring with minimal additional work. Start with the public endpoints, prove the signal is useful, then add authentication when you're ready to act on it.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies