#![allow(clippy::uninlined_format_args)]
use std::sync::Arc;
use ibapi::prelude::*;
use time::format_description::well_known::Rfc3339;
use time::{Duration, OffsetDateTime};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let client = Arc::new(Client::connect("127.0.0.1:4002", 100).await?);
println!("Connected to IB Gateway");
let contract = Contract::stock("AAPL").build();
println!("Requesting historical tick data for {}\n", contract.symbol);
println!("=== Historical Trades (last 100) ===");
let mut tick_subscription = client
.historical_ticks_trade(
&contract,
None, None, 100, TradingHours::Regular, )
.await?;
let mut trade_count = 0;
while let Some(tick) = tick_subscription.next().await {
trade_count += 1;
if trade_count <= 5 {
println!(
"Trade {}: {} - ${:.2} x {} on {} [{}]",
trade_count,
tick.timestamp.format(&Rfc3339).unwrap(),
tick.price,
tick.size,
tick.exchange,
tick.special_conditions
);
}
}
println!("Total trades received: {trade_count}");
println!("\n=== Historical Trades (time range) ===");
let end_time = OffsetDateTime::now_utc();
let start_time = end_time - Duration::minutes(30);
let mut tick_subscription = client
.historical_ticks_trade(
&contract,
Some(start_time),
Some(end_time),
0, TradingHours::Regular, )
.await?;
let mut period_trades = 0;
let mut total_volume = 0;
let mut min_price = f64::MAX;
let mut max_price = f64::MIN;
while let Some(tick) = tick_subscription.next().await {
period_trades += 1;
total_volume += tick.size;
min_price = min_price.min(tick.price);
max_price = max_price.max(tick.price);
}
println!(
"Period: {} to {}",
start_time.format(&Rfc3339).unwrap(),
end_time.format(&Rfc3339).unwrap()
);
println!("Trades in period: {period_trades}");
println!("Total volume: {total_volume}");
if period_trades > 0 {
println!("Price range: ${min_price:.2} - ${max_price:.2}");
}
println!("\n=== Historical Bid/Ask Quotes ===");
let mut tick_subscription = client
.historical_ticks_bid_ask(
&contract,
None, None, 50, TradingHours::Regular, false, )
.await?;
let mut quote_count = 0;
let mut total_spread = 0.0;
while let Some(tick) = tick_subscription.next().await {
quote_count += 1;
let spread = tick.price_ask - tick.price_bid;
total_spread += spread;
if quote_count <= 5 {
println!(
"Quote {}: {} - Bid: ${:.2} x {} | Ask: ${:.2} x {} | Spread: ${:.2}",
quote_count,
tick.timestamp.format(&Rfc3339).unwrap(),
tick.price_bid,
tick.size_bid,
tick.price_ask,
tick.size_ask,
spread
);
}
}
println!("Total quotes received: {quote_count}");
if quote_count > 0 {
println!("Average spread: ${:.3}", total_spread / quote_count as f64);
}
println!("\n=== Historical Midpoint Data ===");
let mut tick_subscription = client
.historical_ticks_mid_point(
&contract,
None, None, 30, TradingHours::Regular, )
.await?;
let mut midpoint_count = 0;
while let Some(tick) = tick_subscription.next().await {
midpoint_count += 1;
if midpoint_count <= 5 {
println!(
"Midpoint {}: {} - ${:.2}",
midpoint_count,
tick.timestamp.format(&Rfc3339).unwrap(),
tick.price
);
}
}
println!("Total midpoints received: {midpoint_count}");
println!("\nHistorical ticks example completed!");
Ok(())
}