Bybit Funding Rate History Endpoint: A Trader's Guide
Learn to use Bybit's funding rate history API endpoint to retrieve perpetual contract data, parse responses with Python, and build smarter trading strategies.
Learn to use Bybit's funding rate history API endpoint to retrieve perpetual contract data, parse responses with Python, and build smarter trading strategies.
Funding rates are the heartbeat of perpetual futures markets. Every 8 hours on Bybit — and at comparable intervals on Binance and OKX — long traders pay short traders (or vice versa), creating a timestamped record of market bias. The Bybit funding rate history endpoint gives you programmatic access to that entire record: who was paying, how much, and when. Whether you are backtesting a cash-and-carry strategy, building a sentiment indicator, or hunting for crowded-position reversals, this data is one of the most underused edges available to systematic traders.
Perpetual futures contracts replicate the economics of a leveraged spot position without an expiry date. To keep the contract price from drifting too far from spot, exchanges use a funding mechanism: when the perpetual trades above the spot index, longs pay shorts. When it trades below, shorts pay longs. The size of each payment is the funding rate — a small percentage of the notional position, settled periodically.
Bybit calculates the rate from two components: a fixed interest rate (usually 0.01% per day) and a premium index that reflects the gap between the perpetual mid-price and the spot index. Most USDT-margined pairs settle every 8 hours at 00:00, 08:00, and 16:00 UTC, though some high-activity tokens settle every 4 or even 1 hour. OKX and Binance use similar mechanics — compare funding histories across exchanges and you will often find the same sentiment extremes playing out with slightly different timing.
The history matters because trends in funding are more meaningful than any single data point. When BTCUSDT funding on Bybit sustained rates above 0.05% per 8-hour period — equivalent to roughly 55% annualized — for several consecutive days, those periods reliably preceded sharp long liquidation cascades. Platforms like VoiceOfChain aggregate and surface these signals in real time, but pulling the raw data yourself lets you define custom thresholds and backtest exactly where the edge is.
Bybit's V5 API is the current standard — the older V3 and V2 endpoints are deprecated. The funding rate history endpoint is completely public, meaning no API key is required to access it. Authentication only becomes necessary if you want account-level data like your own personal funding settlement history.
The base endpoint is: GET https://api.bybit.com/v5/market/funding/history
| Parameter | Required | Type | Description |
|---|---|---|---|
| category | Yes | string | Always 'linear' for USDT perpetuals |
| symbol | Yes | string | e.g. 'BTCUSDT', 'ETHUSDT', 'SOLUSDT' |
| startTime | No | integer | Start of range, Unix milliseconds |
| endTime | No | integer | End of range, Unix milliseconds |
| limit | No | integer | Records per page, 1–200 (default 200) |
Results come back newest-first. Each record contains three fields: symbol, fundingRate (a decimal string — '0.0001' means 0.01%), and fundingRateTimestamp (Unix milliseconds). When you need more than 200 records, paginate using the nextPageCursor value from the response result object.
A fundingRate of 0.0001 means positions pay 0.01% every 8 hours. At 3 settlements per day, that annualizes to roughly 10.95%. During bull market extremes this can spike above 0.1% per period — over 100% annualized. Those spikes are where the interesting signals live.
The simplest starting point is a single request for the most recent records. The requests library handles everything cleanly — pass category and symbol, check the retCode in the response body, and return the list.
import requests
BASE_URL = 'https://api.bybit.com'
def get_funding_history(symbol, limit=200):
endpoint = '/v5/market/funding/history'
params = {
'category': 'linear',
'symbol': symbol,
'limit': limit
}
response = requests.get(BASE_URL + endpoint, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['retCode'] != 0:
raise ValueError('API error: ' + data['retMsg'])
return data['result']['list']
# Fetch last 200 funding events for BTCUSDT
records = get_funding_history('BTCUSDT')
print('Fetched', len(records), 'records')
for r in records[:3]:
print(r['fundingRateTimestamp'], r['fundingRate'])
To cover longer time windows — say, 90 days of historical data — you need to paginate. Bybit returns a nextPageCursor token in the response; pass it on the next request to continue retrieving records without overlap or gaps.
import requests
import time
BASE_URL = 'https://api.bybit.com'
def get_full_funding_history(symbol, start_ms, end_ms):
endpoint = '/v5/market/funding/history'
all_records = []
cursor = None
while True:
params = {
'category': 'linear',
'symbol': symbol,
'startTime': start_ms,
'endTime': end_ms,
'limit': 200,
}
if cursor:
params['cursor'] = cursor
resp = requests.get(BASE_URL + endpoint, params=params, timeout=10)
resp.raise_for_status()
body = resp.json()
if body['retCode'] != 0:
raise ValueError('API error: ' + body['retMsg'])
result = body['result']
batch = result.get('list', [])
all_records.extend(batch)
cursor = result.get('nextPageCursor', '')
if not cursor or not batch:
break
time.sleep(0.05) # stay within rate limits
return all_records
# Fetch 90 days of BTCUSDT funding history
now_ms = int(time.time() * 1000)
start_ms = now_ms - (90 * 24 * 60 * 60 * 1000)
records = get_full_funding_history('BTCUSDT', start_ms, now_ms)
print('Total records retrieved:', len(records))
Raw API records arrive as strings — fundingRate comes back as '0.0001', not a float. Converting to a proper DataFrame unlocks rolling averages, percentile analysis, and clean export to CSV or a time-series database.
import pandas as pd
def build_funding_df(records):
df = pd.DataFrame(records)
df['fundingRate'] = pd.to_numeric(df['fundingRate'])
df['timestamp'] = pd.to_datetime(
pd.to_numeric(df['fundingRateTimestamp']), unit='ms', utc=True
)
df = df.sort_values('timestamp').reset_index(drop=True)
# Annualized rate: 3 settlements per day x 365 days
df['annual_pct'] = df['fundingRate'] * 3 * 365 * 100
# 7-day rolling mean (21 periods at 8-hour settlement intervals)
df['rolling_7d'] = df['fundingRate'].rolling(21, min_periods=1).mean()
# Flag extreme funding: >0.05% per period is roughly 55% annualized
df['is_extreme'] = df['fundingRate'].abs() > 0.0005
return df
df = build_funding_df(records)
print(df[['timestamp', 'fundingRate', 'annual_pct', 'is_extreme']].tail(10))
print('Summary stats:')
print(' Mean rate :', round(df['fundingRate'].mean(), 6))
print(' Max rate :', round(df['fundingRate'].max(), 6))
print(' Min rate :', round(df['fundingRate'].min(), 6))
print(' Extreme periods:', df['is_extreme'].sum())
# Export for further analysis or database ingestion
df.to_csv('btcusdt_funding_history.csv', index=False)
The market funding history endpoint is public, but if you want to retrieve your own funding settlements — what Bybit actually charged or credited your account at each interval — you need a signed request. Bybit V5 uses HMAC-SHA256 with a specific payload construction. Generate API keys in the Bybit dashboard under Account → API Management, and restrict them to read-only scope for safety.
import hashlib
import hmac
import os
import time
import requests
API_KEY = os.environ.get('BYBIT_API_KEY', '')
API_SECRET = os.environ.get('BYBIT_API_SECRET', '')
BASE_URL = 'https://api.bybit.com'
def signed_get(endpoint, params):
timestamp = str(int(time.time() * 1000))
recv_window = '5000'
# Build deterministic query string for signature
query = '&'.join(k + '=' + str(v) for k, v in sorted(params.items()))
sign_payload = timestamp + API_KEY + recv_window + query
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-TIMESTAMP': timestamp,
'X-BAPI-SIGN': signature,
'X-BAPI-RECV-WINDOW': recv_window,
}
resp = requests.get(
BASE_URL + endpoint, params=params, headers=headers, timeout=10
)
resp.raise_for_status()
data = resp.json()
if data['retCode'] != 0:
raise ValueError('Signed API error: ' + data['retMsg'])
return data
# Retrieve personal funding settlement history
result = signed_get('/v5/account/transaction-log', {
'accountType': 'UNIFIED',
'type': 'SETTLEMENT',
'limit': 50
})
for entry in result['result']['list']:
print(entry['symbol'], entry['funding'], entry['transactionTime'])
Never hardcode API credentials in source files. Load them from environment variables or a secrets manager. For read-only data access, create a key with no withdrawal or trading permissions — it reduces blast radius if the key is ever leaked.
Raw funding data only becomes useful when you attach a specific thesis to it. These are the most common applications among systematic traders who work with this data set regularly.
The most durable applications combine funding history with complementary data — open interest, liquidation heatmaps, or spot-to-perp basis. VoiceOfChain does exactly this, pulling funding metrics alongside order flow data to generate composite signals that funding rate analysis alone cannot produce. Pull the raw endpoint yourself and you have full control over the signal construction and threshold calibration.
The Bybit funding rate history endpoint is a clean, well-documented API that unlocks a surprisingly deep layer of market intelligence. Start with a basic fetch, add pagination for extended time windows, and run the data through Pandas to calibrate your own signal thresholds. The edge comes from what you build on top — whether that is a cash-and-carry arb engine, a regime filter layered over your existing strategy, or a real-time alert dashboard. Tools like VoiceOfChain handle the aggregation layer; pull the raw data yourself and you retain full control over the analysis.