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