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>) -> PushClientCreates a new PushClient. Pass all callbacks inside PushClientOptions. The connection is established automatically when the first subscription is added.
| Parameter | Type | Description |
|---|---|---|
config | ClientConfig | Loaded configuration (credentials, server URL) |
options | Option<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) -> ConnectionStateReturns 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.
| Field | Closure signature | Triggered when |
|---|---|---|
on_connect | Fn() | Connection established |
on_disconnect | Fn() | Connection closed |
on_error | Fn(String) | A transport or protocol error occurs |
on_kickout | Fn(String) | Server forces disconnection |
on_quote | Fn(QuoteData) | Real-time quote update |
on_tick | Fn(TickData) | Trade tick received |
on_depth | Fn(DepthData) | Order-book depth update |
on_option | Fn(OptionData) | Option quote update |
on_future | Fn(FutureData) | Futures quote update |
on_kline | Fn(KlineData) | K-line bar update |
on_asset | Fn(AssetData) | Account asset change |
on_position | Fn(PositionData) | Position change |
on_order | Fn(OrderData) | Order status change |
on_transaction | Fn(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:
| Variant | Data delivered via |
|---|---|
SubjectType::Quote | on_quote |
SubjectType::Tick | on_tick |
SubjectType::Depth | on_depth |
SubjectType::Option | on_option |
SubjectType::Future | on_future |
SubjectType::Kline | on_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:
| Variant | Data delivered via |
|---|---|
SubjectType::Asset | on_asset |
SubjectType::Position | on_position |
SubjectType::Order | on_order |
SubjectType::Transaction | on_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);Updated 6 days ago
