Skip to main content

Streaming funding rates

Perpetual-futures funding rates update on each exchange's settlement cycle (typically every 1, 4, or 8 hours). Polling REST works, but for live dashboards or alerts you want a push stream. DataMaxi+ exposes a single multiplexed WebSocket that emits a normalised funding-rate message every time any subscribed venue settles or republishes.

By the end of this tutorial you'll have a Python script that subscribes to multiple (symbol, exchange) pairs and prints an alert when the rate crosses a threshold.

Prerequisites​

pip install websockets

1. Inspect the endpoint​

The funding-rate stream lives at:

wss://api.datamaxiplus.com/ws/v1/funding-rate

Auth is the same X-DTMX-APIKEY header you use for REST, passed during the WS upgrade.

Full payload schema and field descriptions are in the Funding Rate WS reference. The compact payload format optimises bandwidth — every field is a single letter:

KeyMeaningExample
fFunding rate0.0001
iSettlement interval (h)8
eExchangebinance
sSymbolBTC-USDT
bBaseBTC
qQuoteUSDT
dSettlement timestamp ms1733616000000
pProcessed-at ms1733616060000

2. Connect and subscribe​

import asyncio
import json
import os

import websockets

DTMX_KEY = os.environ["DTMX_API_KEY"]
URL = "wss://api.datamaxiplus.com/ws/v1/funding-rate"

SUBSCRIPTIONS = [
"BTC-USDT@binance",
"BTC-USDT@bybit",
"ETH-USDT@binance",
]

async def main():
async with websockets.connect(
URL,
additional_headers={"X-DTMX-APIKEY": DTMX_KEY},
) as ws:
await ws.send(json.dumps({
"method": "SUBSCRIBE",
"params": SUBSCRIPTIONS,
"id": 1,
}))

async for raw in ws:
msg = json.loads(raw)
handle(msg)

def handle(msg):
print(msg)

asyncio.run(main())

The subscribe message identifies symbols with a {base}-{quote}@{exchange} format. The id is echoed back in the ack so you can correlate responses to requests.

3. Decode and alert​

Now expand handle() to filter out subscription acks (which lack the f field) and fire an alert when funding crosses a threshold — say, |funding rate| > 0.05% (5 basis points).

THRESHOLD = 0.0005 # 0.05%

def handle(msg):
if "f" not in msg:
# subscription ack, error, or non-data frame
return

rate = msg["f"]
if abs(rate) < THRESHOLD:
return

direction = "LONGS PAY" if rate > 0 else "SHORTS PAY"
print(
f"[{msg['e']:>10}] {msg['s']:<12} "
f"{rate * 100:+.4f}% ({direction}, every {msg['i']}h)"
)

Sample output:

[ binance] BTC-USDT +0.0100% (LONGS PAY, every 8h)
[ bybit] BTC-USDT -0.0080% (SHORTS PAY, every 8h)
[ binance] ETH-USDT +0.0125% (LONGS PAY, every 8h)

4. Hand off to a real sink​

Printing is the demo. In production you'd send the alert somewhere durable — Slack, Telegram, PagerDuty, your own queue. Drop a function call into handle():

import httpx

SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]

def send_slack(text):
httpx.post(SLACK_WEBHOOK, json={"text": text})

Or, if you're building a strategy, push the message onto a queue and consume from your strategy worker.

Operational notes​

▸ Reconnect. WebSocket connections drop — network blips, server restarts, deploys. Wrap the connect() call in a backoff loop and re-send your SUBSCRIBE after every reconnect.

▸ Backpressure. If your handler is slow, the OS receive buffer fills and the server may drop you. Push messages onto an asyncio.Queue and process in a separate task if your handler does network I/O.

▸ One stream, many symbols. A single connection can carry many subscriptions. Don't open one socket per symbol — you'll hit connection limits and waste resources.

▸ Symbol discovery. Available (symbol, exchange) pairs are listed at /api/v1/funding-rate/symbols. Hit it on startup to validate your subscription list.

Next steps​