Skip to content

Commit

Permalink
Implements market depth (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
wboayue authored Oct 25, 2024
1 parent 2f47394 commit a9ec64c
Show file tree
Hide file tree
Showing 18 changed files with 1,158 additions and 314 deletions.
26 changes: 26 additions & 0 deletions examples/market_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use ibapi::{contracts::Contract, market_data::realtime::TickTypes, Client};

// This example demonstrates how to request realtime market data for a contract.

fn main() {
env_logger::init();

let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");

let contract = Contract::stock("AAPL");
let generic_ticks = &[];
let snapshot = false;
let regulatory_snapshot = false;

let subscription = client
.market_data(&contract, generic_ticks, snapshot, regulatory_snapshot)
.expect("error requesting market data");

for tick in &subscription {
println!("{tick:?}");

if let TickTypes::SnapshotEnd = tick {
subscription.cancel();
}
}
}
17 changes: 17 additions & 0 deletions examples/market_depth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use ibapi::contracts::Contract;
use ibapi::Client;

// This example demonstrates how to request market depth data.

fn main() {
env_logger::init();

let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");

let contract = Contract::stock("AAPL");

let subscription = client.market_depth(&contract, 5, true).expect("error requesting market depth");
for row in &subscription {
println!("row: {row:?}")
}
}
15 changes: 15 additions & 0 deletions examples/market_depth_exchanges.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use ibapi::Client;

// This example demonstrates how to request market depth exchanges.

fn main() {
env_logger::init();

let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");

let exchanges = client.market_depth_exchanges().expect("error requesting market depth exchanges");

for exchange in &exchanges {
println!("{exchange:?}");
}
}
8 changes: 4 additions & 4 deletions examples/tick_by_tick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
.version("1.0")
.author("Wil Boayue <[email protected]")
.about("Streams tick by tick data")
.arg(arg!(--connection_string <VALUE>).default_value("localhost:4002"))
.arg(arg!(--connection_string <VALUE>).default_value("127.0.0.1:4002"))
.arg(arg!(--last <SYMBOL>))
.arg(arg!(--all_last <SYMBOL>))
.arg(arg!(--bid_ask <SYMBOL>))
Expand Down Expand Up @@ -46,7 +46,7 @@ fn stream_last(client: &mut Client, _symbol: &str) -> anyhow::Result<()> {
let contract = contract_gc();
let ticks = client.tick_by_tick_last(&contract, 0, false)?;

for (i, tick) in ticks.enumerate() {
for (i, tick) in ticks.iter().enumerate() {
println!("{}: {i:?} {tick:?}", contract.symbol);
}

Expand Down Expand Up @@ -80,7 +80,7 @@ fn stream_all_last(client: &Client, _symbol: &str) -> anyhow::Result<()> {
let contract = contract_es();
let ticks = client.tick_by_tick_all_last(&contract, 0, false)?;

for (i, tick) in ticks.enumerate().take(60) {
for (i, tick) in ticks.iter().enumerate().take(60) {
println!("tick: {i:?} {tick:?}");
}

Expand All @@ -91,7 +91,7 @@ fn stream_bid_ask(client: &mut Client, _symbol: &str) -> anyhow::Result<()> {
let contract = contract_es();
let ticks = client.tick_by_tick_bid_ask(&contract, 0, false)?;

for (i, tick) in ticks.enumerate() {
for (i, tick) in ticks.iter().enumerate() {
println!("tick: {i:?} {tick:?}");
}

Expand Down
87 changes: 83 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::accounts::{AccountSummaries, AccountUpdate, AccountUpdateMulti, Famil
use crate::contracts::{Contract, OptionComputation};
use crate::errors::Error;
use crate::market_data::historical::{self, HistogramEntry};
use crate::market_data::realtime::{self, Bar, BarSize, MidPoint, WhatToShow};
use crate::market_data::realtime::{self, Bar, BarSize, DepthMarketDataDescription, MarketDepths, MidPoint, TickTypes, WhatToShow};
use crate::market_data::MarketDataType;
use crate::messages::{IncomingMessages, OutgoingMessages};
use crate::messages::{RequestMessage, ResponseMessage};
Expand Down Expand Up @@ -1009,7 +1009,7 @@ impl Client {
contract: &Contract,
number_of_ticks: i32,
ignore_size: bool,
) -> Result<impl Iterator<Item = realtime::Trade> + 'a, Error> {
) -> Result<Subscription<'a, realtime::Trade>, Error> {
realtime::tick_by_tick_all_last(self, contract, number_of_ticks, ignore_size)
}

Expand All @@ -1024,7 +1024,7 @@ impl Client {
contract: &Contract,
number_of_ticks: i32,
ignore_size: bool,
) -> Result<impl Iterator<Item = realtime::BidAsk> + 'a, Error> {
) -> Result<Subscription<'a, realtime::BidAsk>, Error> {
realtime::tick_by_tick_bid_ask(self, contract, number_of_ticks, ignore_size)
}

Expand All @@ -1039,7 +1039,7 @@ impl Client {
contract: &Contract,
number_of_ticks: i32,
ignore_size: bool,
) -> Result<impl Iterator<Item = realtime::Trade> + 'a, Error> {
) -> Result<Subscription<'a, realtime::Trade>, Error> {
realtime::tick_by_tick_last(self, contract, number_of_ticks, ignore_size)
}

Expand Down Expand Up @@ -1079,6 +1079,85 @@ impl Client {
market_data::switch_market_data_type(self, market_data_type)
}

/// Requests the contract's market depth (order book).
///
/// # Arguments
///
/// * `contract` - The Contract for which the depth is being requested.
/// * `number_of_rows` - The number of rows on each side of the order book.
/// * `is_smart_depth` - Flag indicates that this is smart depth request.
///
/// # Examples
///
/// ```no_run
/// use ibapi::Client;
/// use ibapi::market_data::{MarketDataType};
///
/// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
///
/// let market_data_type = MarketDataType::Live;
/// client.switch_market_data_type(market_data_type).expect("request failed");
/// println!("market data switched: {:?}", market_data_type);
/// ```
pub fn market_depth<'a>(
&'a self,
contract: &Contract,
number_of_rows: i32,
is_smart_depth: bool,
) -> Result<Subscription<'a, MarketDepths>, Error> {
realtime::market_depth(self, contract, number_of_rows, is_smart_depth)
}

/// Requests venues for which market data is returned to market_depth (those with market makers)
///
/// # Examples
///
/// ```no_run
/// ```
pub fn market_depth_exchanges(&self) -> Result<Vec<DepthMarketDataDescription>, Error> {
realtime::market_depth_exchanges(self)
}

/// Requests real time market data.
///
/// Returns market data for an instrument either in real time or 10-15 minutes delayed data.
///
/// # Arguments
///
/// * `contract` - Contract for which the data is being requested.
/// * `generic_ticks` - IDs of the available generic ticks:
/// - 100 Option Volume (currently for stocks)
/// - 101 Option Open Interest (currently for stocks)
/// - 104 Historical Volatility (currently for stocks)
/// - 105 Average Option Volume (currently for stocks)
/// - 106 Option Implied Volatility (currently for stocks)
/// - 162 Index Future Premium
/// - 165 Miscellaneous Stats
/// - 221 Mark Price (used in TWS P&L computations)
/// - 225 Auction values (volume, price and imbalance)
/// - 233 RTVolume - contains the last trade price, last trade size, last trade time, total volume, VWAP, and single trade flag.
/// - 236 Shortable
/// - 256 Inventory
/// - 258 Fundamental Ratios
/// - 411 Realtime Historical Volatility
/// - 456 IBDividends
/// * `snapshot` - for users with corresponding real time market data subscriptions. A true value will return a one-time snapshot, while a false value will provide streaming data.
/// * `regulatory_snapshot` - snapshot for US stocks requests NBBO snapshots for users which have "US Securities Snapshot Bundle" subscription but not corresponding Network A, B, or C subscription necessary for streaming market data. One-time snapshot of current market price that will incur a fee of 1 cent to the account per snapshot.
///
/// # Examples
///
/// ```no_run
/// ```
pub fn market_data(
&self,
contract: &Contract,
generic_ticks: &[&str],
snapshot: bool,
regulatory_snapshot: bool,
) -> Result<Subscription<TickTypes>, Error> {
realtime::market_data(self, contract, generic_ticks, snapshot, regulatory_snapshot)
}

// == Internal Use ==

#[cfg(test)]
Expand Down
6 changes: 3 additions & 3 deletions src/contracts/decoders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{contracts::tick_types::TickType, contracts::SecurityType, messages::

use super::{Contract, ContractDescription, ContractDetails, MarketRule, OptionComputation, PriceIncrement};

pub(crate) fn decode_contract_details(server_version: i32, message: &mut ResponseMessage) -> Result<ContractDetails, Error> {
pub(super) fn decode_contract_details(server_version: i32, message: &mut ResponseMessage) -> Result<ContractDetails, Error> {
message.skip(); // message type

let mut message_version = 8;
Expand Down Expand Up @@ -124,7 +124,7 @@ fn read_last_trade_date(contract: &mut ContractDetails, last_trade_date_or_contr
Ok(())
}

pub(crate) fn decode_contract_descriptions(server_version: i32, message: &mut ResponseMessage) -> Result<Vec<ContractDescription>, Error> {
pub(super) fn decode_contract_descriptions(server_version: i32, message: &mut ResponseMessage) -> Result<Vec<ContractDescription>, Error> {
message.skip(); // message type

let _request_id = message.next_int()?;
Expand Down Expand Up @@ -166,7 +166,7 @@ pub(crate) fn decode_contract_descriptions(server_version: i32, message: &mut Re
Ok(contract_descriptions)
}

pub(crate) fn decode_market_rule(message: &mut ResponseMessage) -> Result<MarketRule, Error> {
pub(super) fn decode_market_rule(message: &mut ResponseMessage) -> Result<MarketRule, Error> {
message.skip(); // message type

let mut market_rule = MarketRule {
Expand Down
Loading

0 comments on commit a9ec64c

Please sign in to comment.