Real-Time Push

The Rust SDK's PushClient maintains a persistent WebSocket connection to the Tiger OpenAPI server. It supports automatic reconnection, heartbeat keep-alive, and callback-based delivery of market data and account events. Callbacks are thread-safe closures (Box<dyn Fn + Send + Sync>).

Quick Start

use tigeropen::config::ClientConfig;
use tigeropen::push::{PushClient, PushClientOptions, SubjectType};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ClientConfig::from_properties_file("tiger_openapi_config.properties")?;

    let options = PushClientOptions {
        on_connect: Some(Arc::new(|| {
            println!("Connected to push server");
        })),
        on_disconnect: Some(Arc::new(|| {
            println!("Disconnected from push server");
        })),
        on_error: Some(Arc::new(|err| {
            eprintln!("Push error: {}", err);
        })),
        on_kickout: Some(Arc::new(|reason| {
            println!("Kicked out, reason: {}", reason);
        })),
        on_quote: Some(Arc::new(|data| {
            println!("Quote: {}  price={:?}  vol={:?}",
                data.symbol, data.latest_price, data.volume);
        })),
        on_tick: Some(Arc::new(|data| {
            println!("Tick: {}  price={}  size={}", data.symbol, data.price, data.size);
        })),
        on_order: Some(Arc::new(|data| {
            println!("Order update: id={}  status={}", data.id, data.status);
        })),
        on_asset: Some(Arc::new(|_data| {
            println!("Asset change received");
        })),
        on_position: Some(Arc::new(|_data| {
            println!("Position change received");
        })),
        on_transaction: Some(Arc::new(|data| {
            println!("Transaction: {} qty={}", data.symbol, data.quantity);
        })),
        ..Default::default()
    };

    let pc = PushClient::new(config, Some(options));

    // Subscribe to market data
    pc.add_subscription(SubjectType::Quote, &["AAPL".to_string(), "TSLA".to_string()]);
    pc.add_subscription(SubjectType::Tick,  &["AAPL".to_string()]);
    pc.add_subscription(SubjectType::Depth, &["AAPL".to_string()]);
    pc.add_subscription(SubjectType::Kline, &["AAPL".to_string()]);

    // Subscribe to account events
    pc.add_account_sub(SubjectType::Asset);
    pc.add_account_sub(SubjectType::Order);
    pc.add_account_sub(SubjectType::Position);
    pc.add_account_sub(SubjectType::Transaction);

    // Keep running
    tokio::time::sleep(std::time::Duration::from_secs(60)).await;

    Ok(())
}

Client Lifecycle

PushClient::new

pub fn new(config: ClientConfig, options: Option<PushClientOptions>) -> PushClient

Creates a new PushClient. Pass all callbacks inside PushClientOptions. The connection is established automatically when the first subscription is added.

ParameterTypeDescription
configClientConfigLoaded configuration (credentials, server URL)
optionsOption<PushClientOptions>Optional struct carrying all callback closures

connect / disconnect

The connection lifecycle is managed automatically. You can also call these explicitly if needed:

// Force an immediate connection attempt
pc.connect().await?;

// Graceful shutdown
pc.disconnect();

state

pub fn state(&self) -> ConnectionState

Returns the current connection state: Connecting, Connected, or Disconnected.

println!("Current state: {:?}", pc.state());

PushClientOptions (Callbacks)

All fields in PushClientOptions are Option<Arc<dyn Fn(...) + Send + Sync>>. Use Arc::new(|...| { ... }) for each callback.

FieldClosure signatureTriggered when
on_connectFn()Connection established
on_disconnectFn()Connection closed
on_errorFn(String)A transport or protocol error occurs
on_kickoutFn(String)Server forces disconnection
on_quoteFn(QuoteData)Real-time quote update
on_tickFn(TickData)Trade tick received
on_depthFn(DepthData)Order-book depth update
on_optionFn(OptionData)Option quote update
on_futureFn(FutureData)Futures quote update
on_klineFn(KlineData)K-line bar update
on_assetFn(AssetData)Account asset change
on_positionFn(PositionData)Position change
on_orderFn(OrderData)Order status change
on_transactionFn(TransactionData)Fill / execution received
use std::sync::Arc;

let options = PushClientOptions {
    on_quote: Some(Arc::new(|data| {
        let change_pct = data.change_ratio.unwrap_or(0.0) * 100.0;
        println!("{}: ${:.2} ({:+.2}%)",
            data.symbol,
            data.latest_price.unwrap_or(0.0),
            change_pct);
    })),
    on_depth: Some(Arc::new(|data| {
        if let Some(best_bid) = data.bids.first() {
            println!("Best bid for {}: {} @ {}", data.symbol, best_bid.size, best_bid.price);
        }
    })),
    on_kline: Some(Arc::new(|data| {
        println!("Kline {}: O={} H={} L={} C={}",
            data.symbol, data.open, data.high, data.low, data.close);
    })),
    on_error: Some(Arc::new(|err| {
        eprintln!("Push error: {}", err);
    })),
    ..Default::default()
};

Market Data Subscriptions

add_subscription / remove_subscription

pub fn add_subscription(&self, subject: SubjectType, symbols: &[String])
pub fn remove_subscription(&self, subject: SubjectType, symbols: Option<&[String]>)

Subscribe to or unsubscribe from real-time market data. Pass None as symbols to remove_subscription to remove all symbols for that subject.

SubjectType variants for market data:

VariantData delivered via
SubjectType::Quoteon_quote
SubjectType::Tickon_tick
SubjectType::Depthon_depth
SubjectType::Optionon_option
SubjectType::Futureon_future
SubjectType::Klineon_kline
// Subscribe to quotes for two symbols
pc.add_subscription(SubjectType::Quote, &[
    "AAPL".to_string(),
    "TSLA".to_string(),
]);

// Subscribe to tick-by-tick trades
pc.add_subscription(SubjectType::Tick, &["AAPL".to_string()]);

// Subscribe to Level 2 order book
pc.add_subscription(SubjectType::Depth, &["AAPL".to_string()]);

// Subscribe to option quotes
pc.add_subscription(SubjectType::Option, &[
    "AAPL  250117C00150000".to_string(),
]);

// Subscribe to futures quotes
pc.add_subscription(SubjectType::Future, &[
    "ES2506".to_string(),
    "NQ2506".to_string(),
]);

// Subscribe to K-line updates
pc.add_subscription(SubjectType::Kline, &["AAPL".to_string()]);
// Unsubscribe one symbol from quotes
pc.remove_subscription(SubjectType::Quote, Some(&["TSLA".to_string()]));

// Unsubscribe all symbols from option quotes
pc.remove_subscription(SubjectType::Option, None);

// Unsubscribe all symbols from futures
pc.remove_subscription(SubjectType::Future, None);

Account Subscriptions

add_account_sub / remove_account_sub

pub fn add_account_sub(&self, subject: SubjectType)
pub fn remove_account_sub(&self, subject: &SubjectType)

Subscribe to or unsubscribe from account-level events. The account is taken from the ClientConfig.

SubjectType variants for account data:

VariantData delivered via
SubjectType::Asseton_asset
SubjectType::Positionon_position
SubjectType::Orderon_order
SubjectType::Transactionon_transaction
// Subscribe to all account event types
pc.add_account_sub(SubjectType::Asset);
pc.add_account_sub(SubjectType::Position);
pc.add_account_sub(SubjectType::Order);
pc.add_account_sub(SubjectType::Transaction);

// Unsubscribe from individual account event types
pc.remove_account_sub(&SubjectType::Asset);
pc.remove_account_sub(&SubjectType::Position);
pc.remove_account_sub(&SubjectType::Order);
pc.remove_account_sub(&SubjectType::Transaction);

Complete Subscription Reference

// Market data subscriptions
pc.add_subscription(SubjectType::Quote,  &["AAPL".into(), "TSLA".into()]);
pc.add_subscription(SubjectType::Tick,   &["AAPL".into()]);
pc.add_subscription(SubjectType::Depth,  &["AAPL".into()]);
pc.add_subscription(SubjectType::Option, &["AAPL  250117C00150000".into()]);
pc.add_subscription(SubjectType::Future, &["ES2506".into()]);
pc.add_subscription(SubjectType::Kline,  &["AAPL".into()]);

// Account subscriptions
pc.add_account_sub(SubjectType::Asset);
pc.add_account_sub(SubjectType::Position);
pc.add_account_sub(SubjectType::Order);
pc.add_account_sub(SubjectType::Transaction);

// Unsubscribe from market data (selective)
pc.remove_subscription(SubjectType::Quote,  Some(&["TSLA".into()]));
pc.remove_subscription(SubjectType::Tick,   Some(&["AAPL".into()]));
pc.remove_subscription(SubjectType::Depth,  None);   // removes all
pc.remove_subscription(SubjectType::Option, None);
pc.remove_subscription(SubjectType::Future, None);
pc.remove_subscription(SubjectType::Kline,  None);

// Unsubscribe from account events
pc.remove_account_sub(&SubjectType::Asset);
pc.remove_account_sub(&SubjectType::Position);
pc.remove_account_sub(&SubjectType::Order);
pc.remove_account_sub(&SubjectType::Transaction);