polynode 0.12.0

Rust SDK for the PolyNode API — real-time Polymarket data
Documentation
use serde::{Deserialize, Serialize};

/// A single price level in the orderbook.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderbookLevel {
    pub price: String,
    pub size: String,
}

/// Full orderbook snapshot for an asset.
#[derive(Debug, Clone, Deserialize)]
pub struct BookSnapshot {
    pub asset_id: String,
    pub market: String,
    #[serde(default)]
    pub event_title: Option<String>,
    #[serde(default)]
    pub question: Option<String>,
    #[serde(default)]
    pub outcome: Option<String>,
    #[serde(default)]
    pub slug: Option<String>,
    pub bids: Vec<OrderbookLevel>,
    pub asks: Vec<OrderbookLevel>,
}

/// Incremental orderbook delta. A level with size "0" means removal.
#[derive(Debug, Clone, Deserialize)]
pub struct BookUpdate {
    pub asset_id: String,
    pub market: String,
    #[serde(default)]
    pub event_title: Option<String>,
    #[serde(default)]
    pub question: Option<String>,
    #[serde(default)]
    pub outcome: Option<String>,
    #[serde(default)]
    pub slug: Option<String>,
    pub bids: Vec<OrderbookLevel>,
    pub asks: Vec<OrderbookLevel>,
}

/// A single asset's price in a price change event.
/// Extended in v0.11.0 to carry PM's full wire payload so clients can maintain
/// tick-accurate local books. `size`, `side`, `best_bid`, `best_ask` are
/// optional for backward compatibility with older server versions.
#[derive(Debug, Clone, Deserialize)]
pub struct PriceChangeAsset {
    pub asset_id: String,
    pub price: String,
    #[serde(default)]
    pub outcome: String,
    /// Absolute size at this level after the change. "0" means the level was removed.
    #[serde(default)]
    pub size: Option<String>,
    /// Side this level belongs to: "BUY" (bids) or "SELL" (asks).
    #[serde(default)]
    pub side: Option<String>,
    /// Best bid on the asset after this change.
    #[serde(default)]
    pub best_bid: Option<String>,
    /// Best ask on the asset after this change.
    #[serde(default)]
    pub best_ask: Option<String>,
}

/// Summary of price movement across assets in a market.
#[derive(Debug, Clone, Deserialize)]
pub struct PriceChange {
    pub market: String,
    #[serde(default)]
    pub event_title: Option<String>,
    #[serde(default)]
    pub question: Option<String>,
    #[serde(default)]
    pub slug: Option<String>,
    pub assets: Vec<PriceChangeAsset>,
}

/// A single executed trade ("last trade price" event).
#[derive(Debug, Clone, Deserialize)]
pub struct BookTrade {
    pub asset_id: String,
    pub market: String,
    pub price: String,
    pub size: String,
    pub side: String,
    pub fee_rate_bps: String,
    pub timestamp: String,
    #[serde(default)]
    pub outcome: Option<String>,
    #[serde(default)]
    pub slug: Option<String>,
}

/// Individual orderbook update, discriminated by `type` field.
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type")]
pub enum OrderbookUpdate {
    #[serde(rename = "book_snapshot")]
    Snapshot(BookSnapshot),
    #[serde(rename = "book_update")]
    Update(BookUpdate),
    #[serde(rename = "price_change")]
    PriceChange(PriceChange),
    #[serde(rename = "last_trade_price")]
    LastTradePrice(BookTrade),
}

/// Messages yielded to the user from the orderbook stream.
#[derive(Debug)]
pub enum ObMessage {
    /// An individual orderbook update (snapshot, delta, or price change).
    Update(OrderbookUpdate),
    /// All initial snapshots have been delivered.
    SnapshotsDone { total: u64 },
    /// Subscription acknowledged.
    Subscribed { markets: u64 },
    /// Unsubscribed.
    Unsubscribed,
    /// Error from the server.
    Error { error: String, message: String },
}

// ── Wire message types for deserialization ──

#[derive(Debug, Deserialize)]
pub(crate) struct RawObMessage {
    #[serde(rename = "type", default)]
    pub msg_type: Option<String>,
    #[serde(default)]
    pub error: Option<String>,
    #[serde(default)]
    pub message: Option<String>,
    #[serde(default)]
    pub markets: Option<u64>,
    #[serde(default)]
    pub total: Option<u64>,
    #[serde(default)]
    pub snapshots: Option<Vec<serde_json::Value>>,
    #[serde(default)]
    pub updates: Option<Vec<serde_json::Value>>,
}