The SDK provides two standalone WebSocket clients for real-time market data. Both require no wallet or private key — they are read-only data feeds.
KuruFrontendOrderbookClient
The frontend orderbook client (orderbook_ws) streams full L2 snapshots followed by incremental updates. Prices and sizes are pre-normalized to human-readable Decimal values.
Usage
import asyncio
from kuru_sdk_py.configs import ConfigManager
from kuru_sdk_py.feed.orderbook_ws import KuruFrontendOrderbookClient, FrontendOrderbookUpdate
async def main():
toml_config = ConfigManager.load_toml_config()
market_config = ConfigManager.load_market_config(toml_config=toml_config)
connection_config = ConfigManager.load_connection_config(toml_config=toml_config)
update_queue: asyncio.Queue[FrontendOrderbookUpdate] = asyncio.Queue()
client = KuruFrontendOrderbookClient(
ws_url=connection_config.kuru_ws_url,
market_address=market_config.market_address,
update_queue=update_queue,
size_precision=market_config.size_precision,
)
async with client:
while True:
update = await update_queue.get()
if update.b:
best_bid = update.b[0][0] # Already a Decimal
if update.a:
best_ask = update.a[0][0] # Already a Decimal
asyncio.run(main())
FrontendOrderbookUpdate fields
| Field | Type | Description |
|---|
events | list[FrontendEvent] | Events describing what changed (trades, order placements, cancellations) |
b | list[tuple[Decimal, Decimal]] | None | Bid levels — each entry is (price, size) |
a | list[tuple[Decimal, Decimal]] | None | Ask levels — each entry is (price, size) |
v | VaultParams | None | Updated vault params, if any |
You can also subscribe via KuruClient instead of instantiating the client directly:client.set_orderbook_callback(on_orderbook)
await client.subscribe_to_orderbook()
ExchangeWebsocketClient
The exchange WebSocket client (exchange_ws) streams incremental order book deltas in a Binance-compatible format. Unlike the frontend client, it does not send full snapshots — you must maintain a local order book.
Update types
DepthUpdate — standard depth update:
| Field | Type | Description |
|---|
e | str | Event type ("depthUpdate") |
E | int | Event time (milliseconds since epoch) |
s | str | Symbol (market address) |
U | int | First update ID in the event |
u | int | Final update ID in the event |
b | list[tuple[Decimal, Decimal]] | Bid deltas — (price, size) pairs, pre-normalized |
a | list[tuple[Decimal, Decimal]] | Ask deltas — (price, size) pairs, pre-normalized |
MonadDepthUpdate — Monad-specific extension with blockchain state:
| Field | Type | Description |
|---|
e | str | Event type ("monadDepthUpdate") |
E | int | Event time (milliseconds since epoch) |
s | str | Symbol (market address) |
state | str | Blockchain state: "committed" | "proposed" | "finalized" |
blockNumber | int | Block number where this update occurred |
blockId | str | Block hash (hex string with 0x prefix) |
U | int | First update ID |
u | int | Final update ID |
b | list[tuple[Decimal, Decimal]] | Bid deltas |
a | list[tuple[Decimal, Decimal]] | Ask deltas |
Usage
import asyncio
from kuru_sdk_py.configs import ConfigManager
from kuru_sdk_py.feed.exchange_ws import ExchangeWebsocketClient, DepthUpdate, MonadDepthUpdate
async def main():
toml_config = ConfigManager.load_toml_config()
market_config = ConfigManager.load_market_config(toml_config=toml_config)
connection_config = ConfigManager.load_connection_config(toml_config=toml_config)
update_queue = asyncio.Queue()
client = ExchangeWebsocketClient(
ws_url=connection_config.exchange_ws_url,
market_config=market_config,
update_queue=update_queue,
)
# Local orderbook — must be seeded and maintained manually
orderbook = {"bids": {}, "asks": {}}
async with client:
while True:
update = await update_queue.get()
# Apply bid deltas (prices and sizes are pre-normalized Decimals)
for price, size in update.b:
if size == 0:
orderbook["bids"].pop(price, None) # Level removed
else:
orderbook["bids"][price] = size # Level added or updated
# Apply ask deltas
for price, size in update.a:
if size == 0:
orderbook["asks"].pop(price, None) # Level removed
else:
orderbook["asks"][price] = size # Level added or updated
# For MonadDepthUpdate, blockchain state is also available
if isinstance(update, MonadDepthUpdate):
print(f"Block {update.blockNumber} ({update.state})")
asyncio.run(main())
A size of 0 in a delta means the price level should be removed from your local book. Always apply delta updates in sequence using the U/u IDs to detect gaps.
Comparison
| KuruFrontendOrderbookClient | ExchangeWebsocketClient |
|---|
| Initial snapshot | Full L2 book on connect | None (delta-only) |
| Update style | Full levels at changed prices + events | Incremental deltas |
| Local book required | No | Yes |
| Event detail (trades, orders) | Yes (events field) | No |
| Blockchain state | No | Yes (monad variant) |
| Message format | Text JSON | Binary JSON |
| Example | get_orderbook_ws.py | get_exchange_orderbook_ws.py |