Binance Funding Rate WebSocket: Real-Time Data Guide
Learn to stream Binance funding rates via WebSocket with Python code examples, fee breakdowns, and practical tips for building real-time crypto trading tools.
Learn to stream Binance funding rates via WebSocket with Python code examples, fee breakdowns, and practical tips for building real-time crypto trading tools.
Funding rate is one of the cleanest signals you can get in crypto futures markets. When it spikes — positive or negative — it reveals real information about market positioning: longs are too crowded, or shorts are piling in at unsustainable levels. Traders who can read this in real time, across dozens of symbols simultaneously, have a genuine edge over those checking a dashboard tab manually every few hours.
The Binance funding rate WebSocket stream gives you that data programmatically, with sub-second updates, without polling REST endpoints and burning your rate limits. This guide covers connecting to the stream, parsing the response fields, filtering for actionable signals, and building a monitor robust enough to stay alive in production.
Perpetual futures contracts never expire — but they need a mechanism to keep their price anchored to spot. That mechanism is the funding rate: a recurring payment between long and short holders, settled every 8 hours on Binance, every hour on Bybit, and every 4 or 8 hours on OKX depending on the contract. The rate is calculated from the difference between the perpetual price and the spot index price.
When funding is positive, longs pay shorts. When negative, shorts pay longs. The magnitude tells you how crowded each side is. A sustained positive funding above 0.1% per 8 hours — roughly 136% annualized — is a market screaming that retail is overleveraged long. These conditions have historically preceded sharp corrections as leveraged positions become expensive to hold.
Platforms like VoiceOfChain aggregate funding rate data across multiple assets and surface extremes as real-time trading signals — useful if you want alerts without building the infrastructure. But if you are building a bot, a screener, or a systematic strategy, streaming directly from Binance via WebSocket is the right move.
Binance exposes funding rate data through the mark price stream on the futures WebSocket server (fstream). There are four variants depending on whether you need one symbol or all of them, and how frequently you need updates:
| Stream Type | Endpoint | Update Frequency |
|---|---|---|
| Single symbol | wss://fstream.binance.com/ws/<symbol>@markPrice | Every 3 seconds |
| Single symbol fast | wss://fstream.binance.com/ws/<symbol>@markPrice@1s | Every 1 second |
| All symbols | wss://fstream.binance.com/ws/!markPrice@arr | Every 3 seconds |
| All symbols fast | wss://fstream.binance.com/ws/!markPrice@arr@1s | Every 1 second |
Each message contains the mark price, spot index price, last funding rate, and the Unix timestamp of the next scheduled funding settlement. No authentication required — these are public market data streams. Here is the minimal working example to get live funding rate data from Binance:
import asyncio
import websockets
import json
from datetime import datetime
async def stream_funding_rate(symbol='btcusdt'):
uri = f'wss://fstream.binance.com/ws/{symbol}@markPrice'
async with websockets.connect(uri) as ws:
print(f'Connected — streaming {symbol.upper()} funding rate')
while True:
data = json.loads(await ws.recv())
# Response field reference:
# data['s'] = symbol (e.g. 'BTCUSDT')
# data['p'] = mark price
# data['i'] = index price (spot)
# data['r'] = last funding rate (decimal, e.g. 0.0001 = 0.01%)
# data['T'] = next funding time in milliseconds
funding_rate = float(data['r'])
mark_price = float(data['p'])
next_funding = datetime.fromtimestamp(data['T'] / 1000)
print(
f"{data['s']:10} | "
f"Mark: {mark_price:,.2f} | "
f"Funding: {funding_rate * 100:.4f}% | "
f"Next: {next_funding:%H:%M:%S}"
)
asyncio.run(stream_funding_rate('btcusdt'))
Install dependencies first: pip install websockets. The websockets library version 11+ includes automatic ping/pong handling and improved connection stability. For asyncio-heavy applications, consider using websockets 12.x which adds native timeout support.
The single-symbol stream is useful for focused monitoring, but the real value comes from watching everything at once. The !markPrice@arr stream pushes an array of every active Binance futures symbol every 3 seconds — over 300 pairs. You want to filter that down to the symbols where positioning is extreme and actionable.
The example below connects to the all-symbols stream, filters for funding rates above a configurable threshold, sorts by magnitude, and prints the top 5 most extreme positions in real time. A threshold of 0.0003 (0.03% per 8 hours) equates to roughly 13% annualized — already elevated. At 0.001% the market is in overdrive territory.
import asyncio
import websockets
import json
from datetime import datetime
async def monitor_extreme_funding(threshold=0.0003):
'''
Stream all Binance futures symbols and surface extreme funding rates.
threshold: 0.0003 = 0.03% per 8h settlement (~13% annualized)
'''
uri = 'wss://fstream.binance.com/ws/!markPrice@arr@1s'
async with websockets.connect(uri, max_size=10_000_000) as ws:
print(f'Scanning all Binance futures — threshold: {threshold*100:.4f}%')
while True:
rates = json.loads(await ws.recv())
# Filter and sort by absolute funding magnitude
extremes = sorted(
[r for r in rates if abs(float(r['r'])) >= threshold],
key=lambda x: abs(float(x['r'])),
reverse=True
)
if not extremes:
continue
print()
print(f"{'Symbol':<12} {'Rate':>10} {'Direction':<20} {'Next':>8}")
print('-' * 56)
for r in extremes[:5]:
rate = float(r['r'])
direction = 'LONG pays SHORT' if rate > 0 else 'SHORT pays LONG'
next_time = datetime.fromtimestamp(r['T'] / 1000)
print(
f"{r['s']:<12} "
f"{rate * 100:>+9.4f}% "
f"{direction:<20} "
f"{next_time:%H:%M:%S}"
)
asyncio.run(monitor_extreme_funding(threshold=0.0003))
WebSocket connections drop. This is not a bug — it is a property of long-lived TCP connections on the internet. Servers restart for maintenance, your network hiccups, or Binance pushes a configuration update. A script that exits when the connection closes is fine for a quick check but not for a system running 24/7. The class below implements exponential backoff reconnection, structured logging, and a callback interface so you can plug alert logic — a Telegram message, a database write, a trade signal — without modifying the core monitor.
import asyncio
import websockets
import json
import logging
from datetime import datetime
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s'
)
log = logging.getLogger('funding_monitor')
class BinanceFundingMonitor:
BASE = 'wss://fstream.binance.com'
def __init__(self, symbols, threshold=0.0005, on_alert=None):
self.symbols = [s.lower() for s in symbols]
self.threshold = threshold
self.on_alert = on_alert or self._log_alert
self._delay = 5
def _uri(self):
if len(self.symbols) == 1:
return f'{self.BASE}/ws/{self.symbols[0]}@markPrice'
streams = '/'.join(f'{s}@markPrice' for s in self.symbols)
return f'{self.BASE}/stream?streams={streams}'
async def _log_alert(self, symbol, rate, next_funding):
direction = 'LONG pays SHORT' if rate > 0 else 'SHORT pays LONG'
log.warning(f'EXTREME | {symbol} | {rate*100:.4f}% | {direction} | next: {next_funding:%H:%M}')
async def _process(self, raw):
data = json.loads(raw)
# Combined stream wraps payload in {"data": {...}}
# Single stream sends payload directly
payload = data.get('data', data)
items = payload if isinstance(payload, list) else [payload]
for item in items:
rate = float(item.get('r', 0))
if abs(rate) >= self.threshold:
next_ts = datetime.fromtimestamp(item['T'] / 1000)
await self.on_alert(item['s'], rate, next_ts)
async def run(self):
uri = self._uri()
while True:
try:
async with websockets.connect(uri, ping_interval=20, ping_timeout=10) as ws:
log.info(f'Connected: {uri}')
self._delay = 5 # Reset backoff on successful connection
async for msg in ws:
await self._process(msg)
except websockets.exceptions.ConnectionClosedError as e:
log.warning(f'Connection closed ({e.code}): {e.reason}')
except websockets.exceptions.WebSocketException as e:
log.error(f'WebSocket error: {e}')
except Exception as e:
log.error(f'Unexpected error: {e}', exc_info=True)
log.info(f'Reconnecting in {self._delay}s...')
await asyncio.sleep(self._delay)
self._delay = min(self._delay * 2, 60) # Cap at 60s
async def main():
monitor = BinanceFundingMonitor(
symbols=['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT', 'DOGEUSDT'],
threshold=0.0005 # 0.05% per 8h = ~18% annualized
)
await monitor.run()
asyncio.run(main())
Binance allows up to 200 WebSocket connections per IP and up to 1024 streams per combined connection. For production systems that need to monitor many symbols, use the combined stream endpoint (?streams=s1/s2/s3) rather than opening individual connections per symbol. For all-symbols coverage, use !markPrice@arr instead.
A question that comes up constantly from traders moving to programmatic strategies: does Binance have transaction fees, and if so, how much? The short answer: yes, both spot and futures trading on Binance carry fees, and the structure matters significantly when you are building strategies around funding rate collection or high-frequency signals.
For futures — where funding rate trading lives — the standard rates are 0.02% maker and 0.05% taker at the base VIP 0 tier. Maker orders add liquidity (limit orders that sit in the book); taker orders remove it (market orders, or limits that match immediately). If you are entering a funding arbitrage position — long spot, short perpetual — and you use market orders on both legs, you pay taker fees twice. On a $10,000 position, that is $10 in fees just to enter.
| Product | Maker Fee | Taker Fee | BNB Discount |
|---|---|---|---|
| Spot | 0.100% | 0.100% | 25% off → 0.075% |
| USDT-M Futures | 0.020% | 0.050% | 10% off |
| COIN-M Futures | 0.010% | 0.050% | 10% off |
How much is Binance transaction fee once you scale up? The VIP tier system rewards volume: at VIP 1 (≥ $1M monthly futures volume), maker drops to 0.016% and taker to 0.040%. At VIP 5 and above, maker fees can reach zero or negative — Binance pays you to provide liquidity. Holding BNB and enabling fee deduction gives an additional 10% discount on futures and 25% on spot at all tiers.
For comparison: Bybit charges 0.02% maker / 0.055% taker on perpetuals at base tier, OKX is 0.02% maker / 0.05% taker, and Gate.io runs 0.02% maker / 0.06% taker. Bitget is comparable at 0.02% / 0.06%. The differences between exchanges at the standard tier are narrow — within a few basis points. Liquidity depth, funding rate levels, and execution quality usually matter more than chasing the lowest fee table.
The practical implication for funding arb: if you are targeting a 0.01% funding rate (the Binance base rate when markets are balanced), your round-trip cost on a taker/taker entry and exit eats 0.20% — 20 funding periods to break even. Funding arb only makes sense when funding is elevated (0.05%+) and you plan to hold through multiple settlements. Use limit orders where possible to get maker rates and cut your entry cost by more than half.
The Binance funding rate WebSocket is one of the most underused free data sources in crypto. It requires no API key, provides sub-second updates across every active futures symbol, and gives you direct insight into market positioning that most traders only check manually. With the three code patterns above — basic connection, multi-symbol screener, and production-ready monitor with reconnection — you have everything you need to build a system that runs continuously.
Factor in Binance's fee structure when sizing any funding arbitrage position: 0.02% maker or 0.05% taker per trade means elevated funding rates are required to make the math work after round-trip costs. Track funding across Binance alongside other exchanges like Bybit, OKX, and Gate.io to catch cross-exchange divergences that create additional opportunity. The edge is in the data — and now you know exactly how to stream it.