Skip to content

RTDS (Real-Time Data Streaming)

RTDS delivers streaming price updates for assets such as BTC, ETH, SOL, and more. You specify which assets to track by symbol, and the server pushes new prices as they arrive from upstream data sources. No authentication is needed.

wss://api.openfish.fun/ws/rtds

Once connected, send a JSON message listing the asset symbols you want to receive:

{
"channel": "price",
"assets": ["BTC", "ETH", "SOL"]
}
FieldTypeDescription
channelstringMust be "price" for price subscriptions
assetsstring[]List of asset symbols (case-insensitive)

The server replies with a confirmation that includes every symbol you are currently tracking:

{
"type": "subscribed",
"assets": ["BTC", "ETH", "SOL"]
}

You can expand your subscription at any time by sending another message. New symbols are merged into the existing set rather than replacing it:

{
"channel": "price",
"assets": ["XRP", "DOGE"]
}

Response:

{
"type": "subscribed",
"assets": ["BTC", "ETH", "SOL", "XRP", "DOGE"]
}

After subscribing, price updates arrive as they are ingested from external feeds:

{
"asset": "BTC",
"price": "67123.45",
"source": "binance",
"timestamp": 1700000000
}
FieldTypeDescription
assetstringAsset symbol (uppercase)
pricestringCurrent price as a string for precision
sourcestringData source identifier (e.g., "binance")
timestampnumberUnix timestamp in seconds

WebSocket PING frames are sent by the server every 10 seconds. Reply with PONG frames to hold the connection open. Most WebSocket libraries handle this transparently.

use openfish_client_sdk::ws::RtdsSocket;
use futures_util::StreamExt;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut ws = RtdsSocket::connect("wss://api.openfish.fun/ws/rtds").await?;
// Subscribe to BTC and ETH price feeds
ws.subscribe_assets(&["BTC", "ETH"]).await?;
while let Some(tick) = ws.next().await {
println!(
"[{}] {} = {} (source: {})",
tick.timestamp, tick.asset, tick.price, tick.source
);
}
Ok(())
}

Trading bots that need instant access to the most recent price can maintain an in-memory map fed by the RTDS stream:

use openfish_client_sdk::ws::RtdsSocket;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use futures_util::StreamExt;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let prices: Arc<RwLock<HashMap<String, f64>>> = Arc::new(RwLock::new(HashMap::new()));
let prices_clone = prices.clone();
tokio::spawn(async move {
let mut ws = RtdsSocket::connect("wss://api.openfish.fun/ws/rtds")
.await
.expect("Failed to connect");
ws.subscribe_assets(&["BTC", "ETH", "SOL"]).await.expect("subscribe failed");
while let Some(tick) = ws.next().await {
if let Ok(val) = tick.price.parse::<f64>() {
prices_clone.write().unwrap().insert(tick.asset.clone(), val);
}
}
});
// Elsewhere in your application:
// let btc_price = prices.read().unwrap().get("BTC").copied();
Ok(())
}

Symbols are normalized to uppercase on the server side. Commonly available symbols include:

SymbolAsset
BTCBitcoin
ETHEthereum
SOLSolana
XRPXRP

The full set of available symbols depends on which upstream data feeds are active. Subscribing to an unrecognized symbol does not produce an error — the server silently includes it in your subscription set and will begin delivering ticks if the feed becomes available later.