1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#![allow(clippy::uninlined_format_args)]
//! Async market depth (Level II) example
//!
//! This example demonstrates how to subscribe to market depth data using the async API.
//! Market depth shows the order book with multiple price levels.
//!
//! # Usage
//!
//! Make sure IB Gateway or TWS is running with API connections enabled, then run:
//!
//! ```bash
//! cargo run --features async --example async_market_depth
//! ```
//!
//! # Configuration
//!
//! - Adjust the connection address if needed (default: 127.0.0.1:4002)
//! - Change the stock symbol if desired (default: AAPL)
//! - Modify number_of_rows to see more/fewer price levels (default: 5)
use std::sync::Arc;
use ibapi::{contracts::Contract, market_data::realtime::MarketDepths, Client};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
// Connect to IB Gateway
let client = Arc::new(Client::connect("127.0.0.1:4002", 100).await?);
println!("Connected to IB Gateway");
// Create a stock contract
let contract = Contract::stock("AAPL").build();
println!("Subscribing to market depth for {}", contract.symbol);
// First, get available market depth exchanges
println!("\nAvailable market depth exchanges:");
let exchanges = client.market_depth_exchanges().await?;
for exchange in exchanges.iter().take(5) {
println!(
" {} - {} ({})",
exchange.exchange_name, exchange.security_type, exchange.service_data_type
);
}
// Request market depth
let market_depth = client
.market_depth(
&contract, 5, // Number of rows (price levels)
false, // Not smart depth
)
.await?;
println!("\nMarket depth subscription created");
println!("Showing order book updates...\n");
// Track the order book
let mut bid_book = [None; 5];
let mut ask_book = [None; 5];
// Process market depth stream
let mut market_depth = market_depth;
let mut update_count = 0;
while let Some(depth_update) = market_depth.next().await {
update_count += 1;
if update_count > 30 {
break;
} // Take first 30 updates for demo
match depth_update? {
MarketDepths::MarketDepth(depth) => {
let side = if depth.side == 1 { "Bid" } else { "Ask" };
let operation = match depth.operation {
0 => "Insert",
1 => "Update",
2 => "Delete",
_ => "Unknown",
};
println!("Update #{}: {} {} at position {}", update_count, operation, side, depth.position);
// Update our order book
if depth.side == 1 {
// Bid
match depth.operation {
0 | 1 => {
// Insert or Update
if depth.position < bid_book.len() as i32 {
bid_book[depth.position as usize] = Some((depth.price, depth.size));
}
}
2 => {
// Delete
if depth.position < bid_book.len() as i32 {
bid_book[depth.position as usize] = None;
}
}
_ => {}
}
} else {
// Ask
match depth.operation {
0 | 1 => {
// Insert or Update
if depth.position < ask_book.len() as i32 {
ask_book[depth.position as usize] = Some((depth.price, depth.size));
}
}
2 => {
// Delete
if depth.position < ask_book.len() as i32 {
ask_book[depth.position as usize] = None;
}
}
_ => {}
}
}
// Display current order book
println!("\nOrder Book:");
println!(" {:>10} {:>10} | {:>10} {:>10}", "Bid Size", "Bid", "Ask", "Ask Size");
println!(" {:-<10} {:-<10} | {:-<10} {:-<10}", "", "", "", "");
for i in 0..5 {
let bid = bid_book.get(i).and_then(|&x| x);
let ask = ask_book.get(i).and_then(|&x| x);
match (bid, ask) {
(Some((bid_price, bid_size)), Some((ask_price, ask_size))) => {
println!(" {bid_size:>10.0} {bid_price:>10.2} | {ask_price:>10.2} {ask_size:>10.0}");
}
(Some((bid_price, bid_size)), None) => {
println!(" {:>10.0} {:>10.2} | {:>10} {:>10}", bid_size, bid_price, "", "");
}
(None, Some((ask_price, ask_size))) => {
println!(" {:>10} {:>10} | {:>10.2} {:>10.0}", "", "", ask_price, ask_size);
}
(None, None) => {
println!(" {:>10} {:>10} | {:>10} {:>10}", "", "", "", "");
}
}
}
println!();
}
MarketDepths::MarketDepthL2(depth) => {
println!(
"L2 Update: {} {} at {} - ${:.2} x {:.0}",
depth.market_maker,
if depth.side == 1 { "Bid" } else { "Ask" },
depth.position,
depth.price,
depth.size
);
}
MarketDepths::Notice(notice) => {
println!("Notice ({}): {}", notice.code, notice.message);
}
}
}
println!("\nReceived {update_count} updates. Example completed!");
Ok(())
}