Trading

The Rust SDK provides an async TradeClient built on Tokio. Every method returns a typed Result<T, TigerError> (e.g. Vec<Order>, Vec<Position>, Option<PlaceOrderResult>). v0.4.0 migrates 8 query methods to Request struct signatures (breaking) and adds 13 new methods.

Quick Start

use tigeropen::client::http_client::HttpClient;
use tigeropen::config::ClientConfig;
use tigeropen::model::order::limit_order;
use tigeropen::model::trade_requests::{OrdersRequest, PositionsRequest};
use tigeropen::trade::TradeClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ClientConfig::builder().build()?;
    let account = config.account.clone();
    let http = HttpClient::new(config);
    let tc = TradeClient::new(&http, &account);

    // Query positions (v0.4.0: Request struct)
    let positions = tc.get_positions(PositionsRequest::default()).await?;
    println!("positions={}", positions.len());

    // Build a limit order via helper
    let mut order = limit_order(&account, "AAPL", "STK", "BUY", 100, 150.0);
    order.market = Some("US".into());
    order.currency = Some("USD".into());

    // Preview before placing
    if let Some(preview) = tc.preview_order(order.clone()).await? {
        println!("commission={} initMargin={}", preview.commission, preview.init_margin);
    }

    // Place the order
    if let Some(placed) = tc.place_order(order).await? {
        println!("id={} orderId={}", placed.id, placed.order_id);
    }

    Ok(())
}

OrderStatus (v0.4.0 aligned with Java)

v0.4.0 aligns OrderStatus with the Java SDK — 8 values. Numeric codes returned by the server are automatically deserialized to the corresponding string variant:

VariantStringCode
OrderStatus::Invalid"Invalid"-2
OrderStatus::Initial"Initial"-1
OrderStatus::PendingCancel"PendingCancel"3
OrderStatus::Cancelled"Cancelled"4
OrderStatus::Submitted"Submitted"5
OrderStatus::Filled"Filled"6
OrderStatus::Inactive"Inactive"7
OrderStatus::PendingSubmit"PendingSubmit"8

Breaking: Python-derived PendingNew / PartiallyFilled removed (server never returns them). PendingSubmit added.

use tigeropen::model::enums::OrderStatus;

println!("{}", OrderStatus::Filled.code());        // 6
println!("{}", OrderStatus::PendingSubmit.code());  // 8

Order Model

v0.3.0 splits the order model into two types:

  • OrderRequest — request struct for place_order / preview_order / modify_order
  • Order — response struct returned by get_orders / get_active_orders / etc.

Helper factories

HelperOrder typeExtra args
market_orderMKT
limit_orderLMTlimit_price
stop_orderSTPaux_price
stop_limit_orderSTP_LMTlimit_price, aux_price
trail_orderTRAILtrailing_percent
auction_limit_orderALlimit_price
auction_market_orderAM

Contract Query

get_contract

pub async fn get_contract(&self, symbol: &str, sec_type: &str) -> Result<Vec<Contract>, TigerError>
let contracts = tc.get_contract("AAPL", "STK").await?;

get_contracts

pub async fn get_contracts(&self, symbols: &[&str], sec_type: &str) -> Result<Vec<Contract>, TigerError>
let contracts = tc.get_contracts(&["AAPL", "TSLA", "MSFT"], "STK").await?;

get_quote_contract

pub async fn get_quote_contract(&self, symbol: &str, sec_type: &str, expiry: &str) -> Result<Vec<Contract>, TigerError>
let contracts = tc.get_quote_contract("AAPL", "OPT", "20260619").await?;

Order Management

place_order

pub async fn place_order(&self, order: OrderRequest) -> Result<Option<PlaceOrderResult>, TigerError>
if let Some(placed) = tc.place_order(req).await? {
    println!("id={} orderId={}", placed.id, placed.order_id);
}

preview_order

pub async fn preview_order(&self, order: OrderRequest) -> Result<Option<PreviewResult>, TigerError>

modify_order

pub async fn modify_order(&self, id: i64, order: OrderRequest) -> Result<Option<OrderIdResult>, TigerError>

cancel_order

pub async fn cancel_order(&self, id: i64) -> Result<Option<OrderIdResult>, TigerError>

Order Query

OrdersRequest (new in v0.4.0)

All four order-query methods share OrdersRequest. Every field is Optionaccount defaults to the client's configured account.

FieldTypeDescription
accountOption<String>Account ID
sec_typeOption<String>"STK" / "OPT" / "FUT" etc.
marketOption<String>Market, e.g. "US" / "HK"
symbolOption<String>Symbol filter
start_dateOption<i64>Start time (ms timestamp)
end_dateOption<i64>End time (ms timestamp)
limitOption<i32>Max records
is_briefOption<bool>Return brief fields only
statesOption<Vec<String>>State filter — see OrderStatus table
sort_byOption<String>"LATEST_CREATED" / "LATEST_STATUS_UPDATED"
page_tokenOption<String>Pagination token
parent_idOption<i64>Parent order ID (get_active_orders only)

get_orders

async fn get_orders(&self, req: OrdersRequest) -> Result<Vec<Order>, TigerError>

v0.4.0 Breaking: changed from no-arg to OrdersRequest.

use tigeropen::model::trade_requests::OrdersRequest;

// Simple call
let orders = tc.get_orders(OrdersRequest::default()).await?;

// Filtered: last 100 filled US stock orders
let filtered = tc.get_orders(OrdersRequest {
    market: Some("US".to_string()),
    sec_type: Some("STK".to_string()),
    states: Some(vec!["Filled".to_string()]),
    limit: Some(100),
    ..Default::default()
}).await?;

get_order (new in v0.4.0)

async fn get_order(&self, req: GetOrderRequest) -> Result<Option<Order>, TigerError>

Query a single order by ID. Pass id (global) or order_id (account-level); at least one is required.

use tigeropen::model::trade_requests::GetOrderRequest;

let order = tc.get_order(GetOrderRequest {
    id: Some(123456789),
    ..Default::default()
}).await?;

get_active_orders

async fn get_active_orders(&self, req: OrdersRequest) -> Result<Vec<Order>, TigerError>

v0.4.0 Breaking: changed from no-arg to OrdersRequest.

let active = tc.get_active_orders(OrdersRequest::default()).await?;

get_inactive_orders

async fn get_inactive_orders(&self, req: OrdersRequest) -> Result<Vec<Order>, TigerError>

v0.4.0 Breaking: changed from no-arg to OrdersRequest.

let inactive = tc.get_inactive_orders(OrdersRequest::default()).await?;

get_filled_orders

async fn get_filled_orders(&self, req: OrdersRequest) -> Result<Vec<Order>, TigerError>

v0.4.0 Breaking: was (start_ms: i64, end_ms: i64), now OrdersRequest with start_date / end_date fields.

use std::time::{SystemTime, UNIX_EPOCH};

let now = SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as i64).unwrap_or(0);
let recent = tc.get_filled_orders(OrdersRequest {
    start_date: Some(now - 30 * 24 * 3600 * 1000),
    end_date: Some(now),
    limit: Some(200),
    ..Default::default()
}).await?;

get_order_transactions

async fn get_order_transactions(&self, req: OrderTransactionsRequest) -> Result<Vec<Transaction>, TigerError>

v0.4.0 Breaking: was (order_id, symbol, sec_type), now OrderTransactionsRequest with all fields optional.

use tigeropen::model::trade_requests::OrderTransactionsRequest;

let txs = tc.get_order_transactions(OrderTransactionsRequest {
    order_id: Some(12345),
    symbol: Some("AAPL".to_string()),
    sec_type: Some("STK".to_string()),
    ..Default::default()
}).await?;

Positions and Assets

get_positions

async fn get_positions(&self, req: PositionsRequest) -> Result<Vec<Position>, TigerError>

v0.4.0 Breaking: changed from no-arg to PositionsRequest.

use tigeropen::model::trade_requests::PositionsRequest;

let positions = tc.get_positions(PositionsRequest::default()).await?;

// Filter to US stocks only
let us = tc.get_positions(PositionsRequest {
    market: Some("US".to_string()),
    sec_type: Some("STK".to_string()),
    ..Default::default()
}).await?;

get_assets

async fn get_assets(&self, req: AssetsRequest) -> Result<Vec<Asset>, TigerError>

v0.4.0 Breaking: changed from no-arg to AssetsRequest.

use tigeropen::model::trade_requests::AssetsRequest;

let assets = tc.get_assets(AssetsRequest::default()).await?;

get_prime_assets

async fn get_prime_assets(&self, req: AssetsRequest) -> Result<Option<PrimeAsset>, TigerError>

v0.4.0 Breaking: changed from no-arg to AssetsRequest (shared with get_assets).

if let Some(pa) = tc.get_prime_assets(AssetsRequest::default()).await? {
    println!("account={} segments={}", pa.account_id, pa.segments.len());
}

Account Management (new in v0.4.0)

get_managed_accounts (new in v0.4.0)

async fn get_managed_accounts(&self, req: ManagedAccountsRequest) -> Result<Vec<ManagedAccount>, TigerError>

Query the list of managed sub-accounts under the current master account. Wire method: accounts.

use tigeropen::model::trade_requests::ManagedAccountsRequest;

let subs = tc.get_managed_accounts(ManagedAccountsRequest::default()).await?;
for s in &subs {
    println!("{} type={:?} status={:?}", s.account, s.account_type, s.status);
}

get_derivative_contracts (new in v0.4.0)

async fn get_derivative_contracts(&self, req: DerivativeContractsRequest) -> Result<Vec<Contract>, TigerError>

Batch query derivative contracts (options / warrants / IOPT). Wire method: quote_contract.

use tigeropen::model::trade_requests::DerivativeContractsRequest;

let cs = tc.get_derivative_contracts(DerivativeContractsRequest {
    symbols: vec!["AAPL".to_string()],
    sec_type: "OPT".to_string(),
    expiry: Some("20260619".to_string()),
    ..Default::default()
}).await?;

Asset Analytics (new in v0.4.0)

get_analytics_asset (new in v0.4.0)

async fn get_analytics_asset(&self, req: AnalyticsAssetRequest) -> Result<Vec<AnalyticsAsset>, TigerError>

Daily account asset analytics (holding value, cash balance, P&L, net value index). Wire method: analytics_asset.

use tigeropen::model::trade_requests::AnalyticsAssetRequest;

let rows = tc.get_analytics_asset(AnalyticsAssetRequest {
    start_date: Some("2025-01-01".to_string()),
    end_date: Some("2025-12-31".to_string()),
    ..Default::default()
}).await?;

get_aggregate_assets (new in v0.4.0)

async fn get_aggregate_assets(&self, req: AggregateAssetsRequest) -> Result<Option<AggregateAssets>, TigerError>

Aggregate multi-currency assets in a single base currency view. Wire method: aggregate_assets.

use tigeropen::model::trade_requests::AggregateAssetsRequest;

if let Some(agg) = tc.get_aggregate_assets(AggregateAssetsRequest {
    base_currency: Some("USD".to_string()),
    ..Default::default()
}).await? {
    println!("netLiq={:?} currencies={}", agg.net_liquidation, agg.currency_assets.len());
}

get_estimate_tradable_quantity (new in v0.4.0)

async fn get_estimate_tradable_quantity(&self, req: EstimateTradableQuantityRequest) -> Result<Option<EstimateTradableQuantity>, TigerError>

Estimate max tradable quantity based on available margin and current price. Wire method: estimate_tradable_quantity.

use tigeropen::model::trade_requests::EstimateTradableQuantityRequest;

if let Some(est) = tc.get_estimate_tradable_quantity(EstimateTradableQuantityRequest {
    symbol: "AAPL".to_string(),
    sec_type: "STK".to_string(),
    action: "BUY".to_string(),
    order_type: Some("LMT".to_string()),
    limit_price: Some(150.0),
    ..Default::default()
}).await? {
    println!("tradable={:?}", est.tradable_quantity);
}

Fund Details and Transfers (new in v0.4.0)

get_fund_details (new in v0.4.0)

async fn get_fund_details(&self, req: FundDetailsRequest) -> Result<Vec<FundDetails>, TigerError>

Query fund flow records (deposits, withdrawals, fees, interest, dividends). Wire method: fund_details.

use tigeropen::model::trade_requests::FundDetailsRequest;

let rows = tc.get_fund_details(FundDetailsRequest {
    currency: Some("USD".to_string()),
    limit: Some(100),
    ..Default::default()
}).await?;

get_funding_history (new in v0.4.0)

async fn get_funding_history(&self, req: FundingHistoryRequest) -> Result<Vec<FundingHistoryItem>, TigerError>

Query transfer fund history. Wire method: transfer_fund.

use tigeropen::model::trade_requests::FundingHistoryRequest;

let rows = tc.get_funding_history(FundingHistoryRequest::default()).await?;

place_forex_order (new in v0.4.0)

async fn place_forex_order(&self, req: ForexOrderRequest) -> Result<Option<ForexOrderResult>, TigerError>

Submit a forex conversion order. Wire method: place_forex_order.

use tigeropen::model::trade_requests::ForexOrderRequest;

if let Some(res) = tc.place_forex_order(ForexOrderRequest {
    source_currency: "USD".to_string(),
    source_amount: Some(10000.0),
    target_currency: "HKD".to_string(),
    ..Default::default()
}).await? {
    println!("rate={:?} target={:?}", res.rate, res.target_amount);
}

get_segment_fund_available (new in v0.4.0)

async fn get_segment_fund_available(&self, req: SegmentFundRequest) -> Result<Vec<SegmentFund>, TigerError>

Query available transfer amount between sub-account segments. Wire method: segment_fund_available.


get_segment_fund_history (new in v0.4.0)

async fn get_segment_fund_history(&self, req: SegmentFundRequest) -> Result<Vec<SegmentFundHistoryItem>, TigerError>


transfer_segment_fund (new in v0.4.0)

async fn transfer_segment_fund(&self, req: SegmentFundRequest) -> Result<Option<SegmentFund>, TigerError>

Transfer funds between sub-account segments. Wire method: transfer_segment_fund.


cancel_segment_fund (new in v0.4.0)

async fn cancel_segment_fund(&self, req: SegmentFundRequest) -> Result<Option<SegmentFund>, TigerError>

Cancel a pending segment fund transfer. Wire method: cancel_segment_fund.