diff --git a/.gitignore b/.gitignore index 8c2a0ac..5d1bb0b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ Cargo.lock /.vscode/ *.log +log/ diff --git a/Cargo.toml b/Cargo.toml index a4b76d4..421edb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "IBKR-API-Rust" version = "0.1.0" authors = ["brett.miller@sparkstart.com"] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,18 +15,19 @@ name = "twsapi_client" path = "src/bin/manual_tests.rs" [dependencies] -bzip2 = "0.3.3" +openssl = { version = "0.10", features = ["vendored"] } +bzip2 = "0.4.3" log = "0.4.8" -log4rs = "0.12.0" -bytebuffer = "0.2.1" +log4rs = "1.0.0" +bytebuffer = "2.1.1" encoding = "0.2" -num = "0.3.0" +num = "0.4.0" num-derive = "0.3" num-traits = "0.2.12" byteorder = "1.3.4" ascii = "1.0.0" from-ascii = "0.0.1" serde = { version = "1.0", features = ["derive"] } -bigdecimal = "0.1.2" -float-cmp = "0.8.0" +bigdecimal = "0.3.0" +float-cmp = "0.9.0" chrono = "0.4.11" diff --git a/README.md b/README.md index 6952d94..496a543 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # IBKR-API-Rust -Port of Interactive Broker's trading API written in Rust (API_Version=9.76.01) +## This branch is currently in progress to upgrade to version 10.12.01. Do not use until it is merged to master!!! + +Port of Interactive Broker's trading API written in Rust (API_Version=10.12.01) Please see the latest IB Tws Api documentation here: . diff --git a/src/examples/defaults.rs b/src/examples/defaults.rs index 83d5c6e..79b64c7 100644 --- a/src/examples/defaults.rs +++ b/src/examples/defaults.rs @@ -588,10 +588,7 @@ impl Wrapper for DefaultWrapper { .iter() .map(|x| x.as_str()) .collect::>(), - strikes - .iter() - .map(|x| x.clone()) - .collect::>() + strikes.iter().cloned().collect::>() ); } diff --git a/src/examples/order_samples.rs b/src/examples/order_samples.rs index c52a95a..82eef4e 100644 --- a/src/examples/order_samples.rs +++ b/src/examples/order_samples.rs @@ -463,36 +463,42 @@ pub fn bracket_order( stop_loss_price: f64, ) -> (Order, Order, Order) { // This will be our main or "parent" order - let mut parent = Order::default(); - parent.order_id = parent_order_id; - parent.action = action.to_string(); - parent.order_type = "LMT".to_string(); - parent.total_quantity = quantity; - parent.lmt_price = limit_price; - // The parent and children orders will need this attribute set to False to prevent accidental executions. - // The LAST CHILD will have it set to True, - parent.transmit = false; - - let mut take_profit = Order::default(); - take_profit.order_id = parent.order_id + 1; - take_profit.action = (if action == "BUY" { "SELL" } else { "BUY" }).to_string(); - take_profit.order_type = "LMT".to_string(); - take_profit.total_quantity = quantity; - take_profit.lmt_price = take_profit_limit_price; - take_profit.parent_id = parent_order_id; - take_profit.transmit = false; - - let mut stop_loss = Order::default(); - stop_loss.order_id = parent.order_id + 2; - stop_loss.action = (if action == "BUY" { "SELL" } else { "BUY" }).to_string(); - stop_loss.order_type = "STP".to_string(); - // stop trigger price - stop_loss.aux_price = stop_loss_price; - stop_loss.total_quantity = quantity; - stop_loss.parent_id = parent_order_id; - // In this case, the low side order will be the last child being sent. Therefore, it needs to set this attribute to True - // to activate all its predecessors - stop_loss.transmit = true; + let parent = Order { + order_id: parent_order_id, + action: action.to_string(), + order_type: "LMT".to_string(), + total_quantity: quantity, + lmt_price: limit_price, + // The parent and children orders will need this attribute set to False to prevent accidental executions. + // The LAST CHILD will have it set to True, + transmit: false, + ..Order::default() + }; + + let take_profit = Order { + order_id: parent.order_id + 1, + action: (if action == "BUY" { "SELL" } else { "BUY" }).to_string(), + order_type: "LMT".to_string(), + total_quantity: quantity, + lmt_price: take_profit_limit_price, + parent_id: parent_order_id, + transmit: false, + ..Order::default() + }; + + let stop_loss = Order { + order_id: parent.order_id + 2, + action: (if action == "BUY" { "SELL" } else { "BUY" }).to_string(), + order_type: "STP".to_string(), + // stop trigger price + aux_price: stop_loss_price, + total_quantity: quantity, + parent_id: parent_order_id, + // In this case, the low side order will be the last child being sent. Therefore, it needs to set this attribute to True + // to activate all its predecessors + transmit: true, + ..Order::default() + }; (parent, take_profit, stop_loss) } @@ -503,12 +509,12 @@ pub fn bracket_order( /// at which the filled portion of the order executed. //================================================================================================== pub fn market_to_limit(action: &str, quantity: f64) -> Order { - let mut order = Order::default(); - order.action = action.to_string(); - order.order_type = "MTL".to_string(); - order.total_quantity = quantity; - - order + Order { + action: action.to_string(), + order_type: "MTL".to_string(), + total_quantity: quantity, + ..Order::default() + } } /// This order type is useful for futures traders using Globex. A Market with Protection order is a market order that will be cancelled and @@ -517,12 +523,12 @@ pub fn market_to_limit(action: &str, quantity: f64) -> Order { /// Products: FUT, FOP //================================================================================================== pub fn market_with_protection(action: &str, quantity: f64) -> Order { - let mut order = Order::default(); - order.action = action.to_string(); - order.order_type = "MKT PRT".to_string(); - order.total_quantity = quantity; - - order + Order { + action: action.to_string(), + order_type: "MKT PRT".to_string(), + total_quantity: quantity, + ..Order::default() + } } /// A stop order is an instruction to submit a buy or sell market order if and when the user-specified stop trigger price is attained or @@ -533,13 +539,13 @@ pub fn market_with_protection(action: &str, quantity: f64) -> Order { /// Products: CFD, BAG, CASH, FUT, FOP, OPT, STK, WAR //================================================================================================== pub fn stop(action: &str, quantity: f64, stop_price: f64) -> Order { - let mut order = Order::default(); - order.action = action.to_string(); - order.order_type = "STP".to_string(); - order.aux_price = stop_price; - order.total_quantity = quantity; - - order + Order { + action: action.to_string(), + order_type: "STP".to_string(), + aux_price: stop_price, + total_quantity: quantity, + ..Order::default() + } } /// A stop-Limit order is an instruction to submit a buy or sell limit order when the user-specified stop trigger price is attained or @@ -853,12 +859,11 @@ pub fn attach_adjustable_to_stop( ) -> Order { // Attached order is a conventional STP order in opposite direction let mut order = stop( - (if parent.action == "BUY" { + if parent.action == "BUY" { "SELL" } else { "BUY" - }) - .as_ref(), + }, parent.total_quantity, attached_order_stop_price, ); @@ -883,12 +888,11 @@ pub fn attach_adjustable_to_stop_limit( ) -> Order { // Attached order is a conventional STP order let mut order = stop( - (if parent.action == "BUY" { + if parent.action == "BUY" { "SELL" } else { "BUY" - }) - .as_ref(), + }, parent.total_quantity, attached_order_stop_price, ); @@ -916,12 +920,11 @@ pub fn attach_adjustable_to_trail( ) -> Order { // Attached order is a conventional STP order let mut order = stop( - (if parent.action == "BUY" { + if parent.action == "BUY" { "SELL" } else { "BUY" - }) - .as_ref(), + }, parent.total_quantity, attached_order_stop_price, ); diff --git a/src/examples/test_helpers.rs b/src/examples/test_helpers.rs index ab8b85f..fc84558 100644 --- a/src/examples/test_helpers.rs +++ b/src/examples/test_helpers.rs @@ -8,24 +8,14 @@ use crate::{ }, core::contract::{Contract, ContractDescription, ContractDetails, DeltaNeutralContract}, core::errors::IBKRApiLibError, - core::execution::{Execution, ExecutionFilter}, + core::execution::Execution, core::{ account_summary_tags::AccountSummaryTags, order::{Order, OrderState, SoftDollarTier}, order_condition::TriggerMethod, wrapper::Wrapper, }, - core::{ - algo_params::{ - fill_accumulate_distribute_params, fill_adaptive_params, fill_arrival_price_params, - fill_balance_impact_risk_params, fill_close_price_params, fill_csfbinline_params, - fill_dark_ice_params, fill_jefferies_vwapparams, fill_min_impact_params, - fill_pct_vol_params, fill_price_variant_pct_vol_params, fill_qbalgo_in_line_params, - fill_scale_params, fill_size_variant_pct_vol_params, fill_time_variant_pct_vol_params, - fill_twap_params, fill_vwap_params, - }, - streamer::Streamer, - }, + core::{algo_params::fill_arrival_price_params, streamer::Streamer}, examples::{ contract_samples, fa_allocation_samples, order_samples, scanner_subscription_samples, }, @@ -52,6 +42,12 @@ pub struct TestWrapper { account: String, } +impl Default for TestWrapper { + fn default() -> Self { + Self::new() + } +} + impl TestWrapper { pub fn new() -> Self { TestWrapper { @@ -202,7 +198,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + &contract_samples::usstock(), order_samples::limit_order("SELL", 1.0, 50.0).borrow(), )?; } @@ -219,7 +215,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + &contract_samples::usstock(), fa_order_one_account.borrow(), )?; @@ -284,7 +280,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), model_order.borrow(), )?; @@ -374,7 +370,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::discretionary("SELL", 1.0, 45.0, 0.5).borrow(), )?; @@ -399,7 +395,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::limit_on_close("SELL", 1.0, 34.0).borrow(), )?; @@ -411,7 +407,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::limit_on_open("BUY", 1.0, 35.0).borrow(), )?; @@ -423,7 +419,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_if_touched("BUY", 1.0, 30.0).borrow(), )?; @@ -435,7 +431,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_on_close("SELL", 1.0).borrow(), )?; @@ -447,7 +443,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_on_open("BUY", 1.0).borrow(), )?; @@ -459,7 +455,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_order("SELL", 1.0).borrow(), )?; @@ -471,7 +467,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_to_limit("BUY", 1.0).borrow(), )?; @@ -496,7 +492,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::market_to_limit("BUY", 1.0).borrow(), )?; @@ -508,7 +504,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::stop("SELL", 1.0, 34.4).borrow(), )?; @@ -520,7 +516,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), &order_samples::stop_limit("BUY", 1.0, 35.0, 33.0), )?; @@ -544,7 +540,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::sweep_to_fill("BUY", 1.0, 35.0).borrow(), )?; @@ -556,7 +552,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::trailing_stop("SELL", 1.0, 0.5, 30.0).borrow(), )?; @@ -568,7 +564,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), order_samples::trailing_stop_limit("BUY", 1.0, 2.0, 5.0, 50.0).borrow(), )?; @@ -1860,19 +1856,11 @@ impl TestWrapper { )?; // Generic Filters - let mut tagvalues = vec![]; - tagvalues.push(TagValue::new( - "usdMarketCapAbove".to_string(), - "10000".to_string(), - )); - tagvalues.push(TagValue::new( - "optVolumeAbove".to_string(), - "1000".to_string(), - )); - tagvalues.push(TagValue::new( - "avgVolumeAbove".to_string(), - "10000".to_string(), - )); + let tagvalues = vec![ + TagValue::new("usdMarketCapAbove".to_string(), "10000".to_string()), + TagValue::new("optVolumeAbove".to_string(), "1000".to_string()), + TagValue::new("avgVolumeAbove".to_string(), "10000".to_string()), + ]; let result = self .client @@ -1886,15 +1874,13 @@ impl TestWrapper { vec![], tagvalues, ); // requires TWS v973 + - if result.is_err() { - match result.unwrap_err() { - IBKRApiLibError::ApiError(err) => self.error( - err.req_id, - err.code.as_str().parse().unwrap(), - err.description.as_ref(), - ), - _ => {} - } + + if let IBKRApiLibError::ApiError(err) = result.unwrap_err() { + self.error( + err.req_id, + err.code.as_str().parse().unwrap(), + err.description.as_ref(), + ) } let aaplcon_idtag = vec![TagValue::new( @@ -3297,7 +3283,7 @@ where //---------------------------------------------------------------------------------------------- fn managed_accounts(&mut self, accounts_list: &str) { info!("managed_accounts -- accounts_list: {}", accounts_list); - let _split = accounts_list.split(","); + let _split = accounts_list.split(','); //self.account = split; } @@ -3580,10 +3566,7 @@ where .iter() .map(|x| x.as_str()) .collect::>(), - strikes - .iter() - .map(|x| x.clone()) - .collect::>() + strikes.iter().cloned().collect::>() ); } diff --git a/src/tests/test_eclient.rs b/src/tests/test_eclient.rs index 9947521..097fb3e 100644 --- a/src/tests/test_eclient.rs +++ b/src/tests/test_eclient.rs @@ -863,7 +863,7 @@ mod tests { client_id, acct_code.to_string(), time.to_string(), - symbol.to_string().to_string(), + symbol.to_string(), sec_type.to_string(), exchange.to_string(), side.to_string(),