From 5b679b12c7c0732bdd623c0bc9a2ac08b4c7a8c6 Mon Sep 17 00:00:00 2001 From: SparkStart Date: Thu, 3 Feb 2022 16:23:11 -0500 Subject: [PATCH 1/9] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6952d94..81dade8 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 is currently in progress. Just started, so do not use for trading + +Port of Interactive Broker's trading API written in Rust (API_Version=10.12.01) Please see the latest IB Tws Api documentation here: . From bc2f1616d84ce9048605f156246ae2a9f2a490cd Mon Sep 17 00:00:00 2001 From: SparkStart Date: Thu, 3 Feb 2022 16:27:38 -0500 Subject: [PATCH 2/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81dade8..496a543 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IBKR-API-Rust -## This is currently in progress. Just started, so do not use for trading +## 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) From ebd8f8c4d0a3a27c02bb2ae2ddcd1fc134bd09c4 Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Thu, 3 Feb 2022 16:42:45 -0500 Subject: [PATCH 3/9] test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 496a543..0122d7d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IBKR-API-Rust -## This branch is currently in progress to upgrade to version 10.12.01. Do not use until it is merged to master!!! +## This branch is currently in progress to upgrade to version 10.12.01. Do not use until it is merged to master!!! test Port of Interactive Broker's trading API written in Rust (API_Version=10.12.01) From 09e264a9ae4ac954887ef2b89bf8667e8edd2630 Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Thu, 3 Feb 2022 16:47:38 -0500 Subject: [PATCH 4/9] test 2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0122d7d..496a543 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IBKR-API-Rust -## This branch is currently in progress to upgrade to version 10.12.01. Do not use until it is merged to master!!! test +## 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) From 6968d9a715bed49a73cc20f45401691d70a5ecea Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Sat, 12 Feb 2022 17:35:35 -0500 Subject: [PATCH 5/9] clippy --- src/examples/test_helpers.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/examples/test_helpers.rs b/src/examples/test_helpers.rs index ab8b85f..94b89a5 100644 --- a/src/examples/test_helpers.rs +++ b/src/examples/test_helpers.rs @@ -8,7 +8,7 @@ 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}, @@ -17,12 +17,7 @@ use crate::{ }, 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, + fill_arrival_price_params, }, streamer::Streamer, }, From fe99863def7616043fb75356a37ac0b9e597f361 Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Sat, 12 Feb 2022 17:42:29 -0500 Subject: [PATCH 6/9] clippy --- src/tests/test_eclient.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(), From 271e71d016b901898b862724b362488226843ebe Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Sat, 12 Feb 2022 17:47:11 -0500 Subject: [PATCH 7/9] clippy --- src/examples/test_helpers.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/examples/test_helpers.rs b/src/examples/test_helpers.rs index 94b89a5..ed2f096 100644 --- a/src/examples/test_helpers.rs +++ b/src/examples/test_helpers.rs @@ -8,19 +8,14 @@ use crate::{ }, core::contract::{Contract, ContractDescription, ContractDetails, DeltaNeutralContract}, core::errors::IBKRApiLibError, - core::execution::{Execution}, + core::execution::Execution, core::{ account_summary_tags::AccountSummaryTags, order::{Order, OrderState, SoftDollarTier}, order_condition::TriggerMethod, wrapper::Wrapper, }, - core::{ - algo_params::{ - fill_arrival_price_params, - }, - streamer::Streamer, - }, + core::{algo_params::fill_arrival_price_params, streamer::Streamer}, examples::{ contract_samples, fa_allocation_samples, order_samples, scanner_subscription_samples, }, From 8660ce81adb386210e5df8684290c7c7643708a8 Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Sun, 13 Mar 2022 20:50:29 -0400 Subject: [PATCH 8/9] clippy --- Cargo.toml | 10 +-- src/examples/order_samples.rs | 119 +++++++++++++++++----------------- src/examples/test_helpers.rs | 81 +++++++++++------------ 3 files changed, 103 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a4b76d4..4659429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,18 +15,18 @@ name = "twsapi_client" path = "src/bin/manual_tests.rs" [dependencies] -bzip2 = "0.3.3" +bzip2 = "0.4.3" log = "0.4.8" -log4rs = "0.12.0" +log4rs = "1.0.0" bytebuffer = "0.2.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/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 ed2f096..fc84558 100644 --- a/src/examples/test_helpers.rs +++ b/src/examples/test_helpers.rs @@ -42,6 +42,12 @@ pub struct TestWrapper { account: String, } +impl Default for TestWrapper { + fn default() -> Self { + Self::new() + } +} + impl TestWrapper { pub fn new() -> Self { TestWrapper { @@ -192,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(), )?; } @@ -209,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(), )?; @@ -274,7 +280,7 @@ impl TestWrapper { .expect(CLIENT_POISONED_MUTEX) .place_order( next_id, - &contract_samples::usstock().borrow(), + contract_samples::usstock().borrow(), model_order.borrow(), )?; @@ -364,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(), )?; @@ -389,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(), )?; @@ -401,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(), )?; @@ -413,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(), )?; @@ -425,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(), )?; @@ -437,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(), )?; @@ -449,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(), )?; @@ -461,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(), )?; @@ -486,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(), )?; @@ -498,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(), )?; @@ -510,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), )?; @@ -534,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(), )?; @@ -546,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(), )?; @@ -558,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(), )?; @@ -1850,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 @@ -1876,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( @@ -3287,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; } @@ -3570,10 +3566,7 @@ where .iter() .map(|x| x.as_str()) .collect::>(), - strikes - .iter() - .map(|x| x.clone()) - .collect::>() + strikes.iter().cloned().collect::>() ); } From 9b83326aa59883618dac18c9e73836e152947cb2 Mon Sep 17 00:00:00 2001 From: Brett Miller Date: Wed, 10 May 2023 16:51:07 -0400 Subject: [PATCH 9/9] Redesign to use mock TWS service as broker/order manager. All projects build --- .gitignore | 1 + Cargo.toml | 5 +++-- src/examples/defaults.rs | 5 +---- 3 files changed, 5 insertions(+), 6 deletions(-) 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 4659429..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,10 +15,11 @@ name = "twsapi_client" path = "src/bin/manual_tests.rs" [dependencies] +openssl = { version = "0.10", features = ["vendored"] } bzip2 = "0.4.3" log = "0.4.8" log4rs = "1.0.0" -bytebuffer = "0.2.1" +bytebuffer = "2.1.1" encoding = "0.2" num = "0.4.0" num-derive = "0.3" 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::>() ); }