From d0248a5f379bc3917daa8ed744553eb45132c5fb Mon Sep 17 00:00:00 2001 From: mati Date: Mon, 7 Aug 2023 15:57:45 +0200 Subject: [PATCH 1/4] feat: Refactor trade modification functionality - Added a new `modify-target` command to modify the target order of a filled trade - Renamed and refactored various files and methods for consistency and clarity - Implemented the `modify_target` method in the `TradeCommandBuilder` and `TrustFacade` - Updated the `ModifyDialogBuilder` method in the `dispatcher.rs` file to include the option to modify the target price of a trade --- cli/src/commands/trade_command.rs | 7 +++ cli/src/dialogs.rs | 4 +- ...modify_stop_dialog.rs => modify_dialog.rs} | 55 +++++++++++++------ cli/src/dispatcher.rs | 18 ++++-- cli/src/main.rs | 1 + core/src/lib.rs | 9 +++ 6 files changed, 71 insertions(+), 23 deletions(-) rename cli/src/dialogs/{modify_stop_dialog.rs => modify_dialog.rs} (67%) diff --git a/cli/src/commands/trade_command.rs b/cli/src/commands/trade_command.rs index c0067cb..487e739 100644 --- a/cli/src/commands/trade_command.rs +++ b/cli/src/commands/trade_command.rs @@ -74,6 +74,13 @@ impl TradeCommandBuilder { self } + pub fn modify_target(mut self) -> Self { + self.subcommands.push( + Command::new("modify-target").about("Modify the target order of a filled trade."), + ); + self + } + pub fn manually_target(mut self) -> Self { self.subcommands .push(Command::new("manually-target").about("Execute manually the target of a trade")); diff --git a/cli/src/dialogs.rs b/cli/src/dialogs.rs index 52e39ed..4705e46 100644 --- a/cli/src/dialogs.rs +++ b/cli/src/dialogs.rs @@ -1,6 +1,6 @@ mod account_dialog; mod keys_dialog; -mod modify_stop_dialog; +mod modify_dialog; mod rule_dialog; mod trade_cancel_dialog; mod trade_close_dialog; @@ -19,7 +19,7 @@ pub use account_dialog::AccountSearchDialog; pub use keys_dialog::KeysDeleteDialogBuilder; pub use keys_dialog::KeysReadDialogBuilder; pub use keys_dialog::KeysWriteDialogBuilder; -pub use modify_stop_dialog::ModifyStopDialogBuilder; +pub use modify_dialog::ModifyDialogBuilder; pub use rule_dialog::RuleDialogBuilder; pub use rule_dialog::RuleRemoveDialogBuilder; pub use trade_cancel_dialog::CancelDialogBuilder; diff --git a/cli/src/dialogs/modify_stop_dialog.rs b/cli/src/dialogs/modify_dialog.rs similarity index 67% rename from cli/src/dialogs/modify_stop_dialog.rs rename to cli/src/dialogs/modify_dialog.rs index 0c4076e..c00e75a 100644 --- a/cli/src/dialogs/modify_stop_dialog.rs +++ b/cli/src/dialogs/modify_dialog.rs @@ -6,26 +6,26 @@ use model::{Account, BrokerLog, Status, Trade}; use rust_decimal::Decimal; use std::error::Error; -type ModifyStopDialogBuilderResult = Option>>; +type ModifyDialogBuilderResult = Option>>; -pub struct ModifyStopDialogBuilder { +pub struct ModifyDialogBuilder { account: Option, trade: Option, - new_stop_price: Option, - result: ModifyStopDialogBuilderResult, + new_price: Option, + result: ModifyDialogBuilderResult, } -impl ModifyStopDialogBuilder { +impl ModifyDialogBuilder { pub fn new() -> Self { - ModifyStopDialogBuilder { + ModifyDialogBuilder { account: None, trade: None, - new_stop_price: None, + new_price: None, result: None, } } - pub fn build(mut self, trust: &mut TrustFacade) -> ModifyStopDialogBuilder { + pub fn build_stop(mut self, trust: &mut TrustFacade) -> ModifyDialogBuilder { let trade = self .trade .clone() @@ -36,7 +36,7 @@ impl ModifyStopDialogBuilder { .clone() .expect("No account found, did you forget to call account?"); let stop_price = self - .new_stop_price + .new_price .expect("No stop price found, did you forget to call stop_price?"); match trust.modify_stop(&trade, &account, stop_price) { @@ -46,20 +46,44 @@ impl ModifyStopDialogBuilder { self } + pub fn build_target(mut self, trust: &mut TrustFacade) -> ModifyDialogBuilder { + let trade = self + .trade + .clone() + .expect("No trade found, did you forget to call search?"); + + let account = self + .account + .clone() + .expect("No account found, did you forget to call account?"); + let target_price = self + .new_price + .expect("No target price found, did you forget to call stop_price?"); + + match trust.modify_target(&trade, &account, target_price) { + Ok((trade, log)) => self.result = Some(Ok((trade, log))), + Err(error) => self.result = Some(Err(error)), + } + self + } + pub fn display(self) { match self .result .expect("No result found, did you forget to call search?") { Ok((trade, log)) => { - println!("Trade stop updated:"); + println!("Trade updated:"); TradeView::display(&trade, &self.account.unwrap().name); TradeOverviewView::display(&trade.overview); - println!("Stop updated:"); + println!("Stop:"); OrderView::display(trade.safety_stop); + println!("Target:"); + OrderView::display(trade.target); + LogView::display(&log); } Err(error) => println!("Error submitting trade: {:?}", error), @@ -101,12 +125,9 @@ impl ModifyStopDialogBuilder { self } - pub fn stop_price(mut self) -> Self { - let stop_price = Input::new() - .with_prompt("New stop price") - .interact() - .unwrap(); - self.new_stop_price = Some(stop_price); + pub fn new_price(mut self) -> Self { + let stop_price = Input::new().with_prompt("New price").interact().unwrap(); + self.new_price = Some(stop_price); self } } diff --git a/cli/src/dispatcher.rs b/cli/src/dispatcher.rs index c66d45c..eda9646 100644 --- a/cli/src/dispatcher.rs +++ b/cli/src/dispatcher.rs @@ -1,7 +1,7 @@ use crate::dialogs::{ AccountDialogBuilder, AccountSearchDialog, CancelDialogBuilder, CloseDialogBuilder, ExitDialogBuilder, FillTradeDialogBuilder, FundingDialogBuilder, KeysDeleteDialogBuilder, - KeysReadDialogBuilder, KeysWriteDialogBuilder, ModifyStopDialogBuilder, SubmitDialogBuilder, + KeysReadDialogBuilder, KeysWriteDialogBuilder, ModifyDialogBuilder, SubmitDialogBuilder, SyncTradeDialogBuilder, TradeDialogBuilder, TradeSearchDialogBuilder, TradingVehicleDialogBuilder, TradingVehicleSearchDialogBuilder, TransactionDialogBuilder, }; @@ -79,6 +79,7 @@ impl ArgDispatcher { Some(("sync", _)) => self.create_sync(), Some(("search", _)) => self.search_trade(), Some(("modify-stop", _)) => self.modify_stop(), + Some(("modify-target", _)) => self.modify_target(), _ => unreachable!("No subcommand provided"), }, Some((ext, sub_matches)) => { @@ -269,11 +270,20 @@ impl ArgDispatcher { } fn modify_stop(&mut self) { - ModifyStopDialogBuilder::new() + ModifyDialogBuilder::new() .account(&mut self.trust) .search(&mut self.trust) - .stop_price() - .build(&mut self.trust) + .new_price() + .build_stop(&mut self.trust) + .display(); + } + + fn modify_target(&mut self) { + ModifyDialogBuilder::new() + .account(&mut self.trust) + .search(&mut self.trust) + .new_price() + .build_target(&mut self.trust) .display(); } } diff --git a/cli/src/main.rs b/cli/src/main.rs index 865ab08..5622854 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -59,6 +59,7 @@ fn main() { .manually_target() .manually_close() .modify_stop() + .modify_target() .build(), ) .get_matches(); diff --git a/core/src/lib.rs b/core/src/lib.rs index 8ab4ffb..bf7572c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -257,6 +257,15 @@ impl TrustFacade { &mut *self.factory, ) } + + pub fn modify_target( + &mut self, + trade: &Trade, + account: &Account, + new_stop_price: Decimal, + ) -> Result<(Trade, BrokerLog), Box> { + unimplemented!("Not implemented yet") + } } mod account_calculators; From 7b77e6c6a2e2720de2dd9ab19464d6f54aab007f Mon Sep 17 00:00:00 2001 From: mati Date: Mon, 7 Aug 2023 16:04:19 +0200 Subject: [PATCH 2/4] feat: Implement `modify_target` function in brokers and workers - Added a new function `can_modify_target` for validating modifications to the trade target in `trade.rs` - Implemented validation for `can_modify_target` based on the trade's status - Modified the `modify_target` function in the `MockBroker` implementation and added a new parameter `new_target_price` - Created assertions to check if the `account_id`, `trade.target.unit_price`, and `new_target_price` are equal in the `modify_target` function - Added a `modify_target` function to the `AlpacaBroker` struct in `lib.rs` - Modified the `modify_stop` function to take a `new_stop_price` parameter in `lib.rs` - Added a new method `modify_target` to the `Broker` trait interface in `broker.rs` - Added a new method `modify_target` to the `MockBroker` struct in `integration_test_account.rs` - Added a `modify_target` function to the `Broker` trait implementation in `integration_test_cancel_trade.rs` - Modified the `modify_stop` function to the more general `modify` function in `order_worker.rs` - Updated the parameter names in the `modify` function to be more descriptive and fixed the return type in `order_worker.rs` - Added a new method `modify_target` to the `TradeAction` struct and modified the `modify_stop` method to call the `OrderWorker` method `modify` in `trade_action.rs` - Added import statements for `BrokerLog`, `can_modify_target` and `can_modify_stop` in `trade_action.rs` - Added a `modify_target` function to the `TrustFacade` struct in `lib.rs` --- alpaca-broker/src/lib.rs | 9 ++++++ cli/tests/integration_test_account.rs | 14 +++++++++ cli/tests/integration_test_cancel_trade.rs | 14 +++++++++ cli/tests/integration_test_trade.rs | 17 +++++++++++ core/src/lib.rs | 10 +++++-- core/src/validators/trade.rs | 33 ++++++++++++++++++++++ core/src/workers/order_worker.rs | 8 +++--- core/src/workers/trade_action.rs | 24 +++++++++++++++- model/src/broker.rs | 7 +++++ 9 files changed, 129 insertions(+), 7 deletions(-) diff --git a/alpaca-broker/src/lib.rs b/alpaca-broker/src/lib.rs index e0a26d9..f69a803 100644 --- a/alpaca-broker/src/lib.rs +++ b/alpaca-broker/src/lib.rs @@ -52,6 +52,15 @@ impl Broker for AlpacaBroker { ) -> Result> { modify_trade::modify_stop(trade, account, new_stop_price) } + + fn modify_target( + &self, + trade: &Trade, + account: &Account, + new_target_price: rust_decimal::Decimal, + ) -> Result> { + unimplemented!("Alpaca does not support modifying target prices") + } } /// Alpaca-specific Broker API diff --git a/cli/tests/integration_test_account.rs b/cli/tests/integration_test_account.rs index 8e13c85..66058ae 100644 --- a/cli/tests/integration_test_account.rs +++ b/cli/tests/integration_test_account.rs @@ -237,4 +237,18 @@ impl Broker for MockBroker { new_stop_price ) } + + fn modify_target( + &self, + trade: &Trade, + account: &Account, + new_target_price: rust_decimal::Decimal, + ) -> Result> { + unimplemented!( + "Modify target: {:?} {:?} {:?}", + trade, + account, + new_target_price + ) + } } diff --git a/cli/tests/integration_test_cancel_trade.rs b/cli/tests/integration_test_cancel_trade.rs index 089209f..d045de9 100644 --- a/cli/tests/integration_test_cancel_trade.rs +++ b/cli/tests/integration_test_cancel_trade.rs @@ -142,4 +142,18 @@ impl Broker for MockBroker { new_stop_price ) } + + fn modify_target( + &self, + trade: &Trade, + account: &Account, + new_target_price: rust_decimal::Decimal, + ) -> Result> { + unimplemented!( + "Modify target: {:?} {:?} {:?}", + trade, + account, + new_target_price + ) + } } diff --git a/cli/tests/integration_test_trade.rs b/cli/tests/integration_test_trade.rs index b057c69..e920ed6 100644 --- a/cli/tests/integration_test_trade.rs +++ b/cli/tests/integration_test_trade.rs @@ -804,4 +804,21 @@ impl Broker for MockBroker { ..Default::default() }) } + + fn modify_target( + &self, + trade: &Trade, + account: &Account, + new_target_price: rust_decimal::Decimal, + ) -> Result> { + assert_eq!(trade.account_id, account.id); + assert_eq!(trade.target.unit_price, dec!(38)); + assert_eq!(new_target_price, dec!(39)); + + Ok(BrokerLog { + trade_id: trade.id, + log: "".to_string(), + ..Default::default() + }) + } } diff --git a/core/src/lib.rs b/core/src/lib.rs index bf7572c..ea6f1f0 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -262,9 +262,15 @@ impl TrustFacade { &mut self, trade: &Trade, account: &Account, - new_stop_price: Decimal, + new_target_price: Decimal, ) -> Result<(Trade, BrokerLog), Box> { - unimplemented!("Not implemented yet") + TradeAction::modify_target( + trade, + account, + new_target_price, + &mut *self.broker, + &mut *self.factory, + ) } } diff --git a/core/src/validators/trade.rs b/core/src/validators/trade.rs index 4b2bcbb..57779a7 100644 --- a/core/src/validators/trade.rs +++ b/core/src/validators/trade.rs @@ -78,6 +78,19 @@ pub fn can_modify_stop(trade: &Trade, new_price_stop: Decimal) -> TradeValidatio } } +pub fn can_modify_target(trade: &Trade, new_price: Decimal) -> TradeValidationResult { + match trade.status { + Status::Filled => Ok(()), + _ => Err(Box::new(TradeValidationError { + code: TradeValidationErrorCode::TradeNotFilled, + message: format!( + "Trade with id {} is not filled, cannot be modified", + trade.id + ), + })), + } +} + #[derive(Debug, PartialEq)] pub enum TradeValidationErrorCode { @@ -294,4 +307,24 @@ mod tests { let result = can_modify_stop(&trade, dec!(10)); assert!(result.is_ok()); } + + #[test] + fn test_validate_modify_target() { + let trade = Trade { + status: Status::Filled, + ..Default::default() + }; + let result = can_modify_target(&trade, dec!(10)); + assert!(result.is_ok()); + } + + #[test] + fn test_validate_modify_target_not_filled() { + let trade = Trade { + status: Status::Canceled, + ..Default::default() + }; + let result = can_modify_target(&trade, dec!(10)); + assert!(result.is_err()); + } } diff --git a/core/src/workers/order_worker.rs b/core/src/workers/order_worker.rs index 0f86b4a..ff632bd 100644 --- a/core/src/workers/order_worker.rs +++ b/core/src/workers/order_worker.rs @@ -108,12 +108,12 @@ impl OrderWorker { read_database.read_trade(trade.id) } - pub fn modify_stop( - stop: &Order, - new_stop_price: Decimal, + pub fn modify( + order: &Order, + new_price: Decimal, write_database: &mut dyn OrderWrite, ) -> Result> { - let stop = write_database.update_price(stop, new_stop_price)?; + let stop = write_database.update_price(order, new_price)?; Ok(stop) } } diff --git a/core/src/workers/trade_action.rs b/core/src/workers/trade_action.rs index f6e7ef5..4d9a140 100644 --- a/core/src/workers/trade_action.rs +++ b/core/src/workers/trade_action.rs @@ -290,7 +290,7 @@ impl TradeAction { let log = broker.modify_stop(trade, account, new_stop_price)?; // 3. Modify stop order - OrderWorker::modify_stop( + OrderWorker::modify( &trade.safety_stop, new_stop_price, &mut *database.order_write(), @@ -301,4 +301,26 @@ impl TradeAction { Ok((trade, log)) } + + pub fn modify_target( + trade: &Trade, + account: &Account, + new_price: Decimal, + broker: &mut dyn Broker, + database: &mut dyn DatabaseFactory, + ) -> Result<(Trade, BrokerLog), Box> { + // 1. Verify trade can be modified + crate::validators::trade::can_modify_target(trade, new_price)?; + + // 2. Update Trade on the broker + let log = broker.modify_target(trade, account, new_price)?; + + // 3. Modify stop order + OrderWorker::modify(&trade.target, new_price, &mut *database.order_write())?; + + // 4. Refresh Trade + let trade = database.trade_read().read_trade(trade.id)?; + + Ok((trade, log)) + } } diff --git a/model/src/broker.rs b/model/src/broker.rs index 5f9a1a7..c648e37 100644 --- a/model/src/broker.rs +++ b/model/src/broker.rs @@ -70,4 +70,11 @@ pub trait Broker { account: &Account, new_stop_price: Decimal, ) -> Result>; + + fn modify_target( + &self, + trade: &Trade, + account: &Account, + new_price: Decimal, + ) -> Result>; } From d3eefde0ac51ecb6d8ea6b1c75bd052ba8333a8a Mon Sep 17 00:00:00 2001 From: mati Date: Mon, 7 Aug 2023 16:14:27 +0200 Subject: [PATCH 3/4] feat: Refactor trade modification and validation logic - Added new modules for modifying stop price and target price in a trade - Replaced old modules with new ones for modifying stop price and target price - Removed code related to modifying target prices - Modified the TradeAction struct and its methods for handling trade status updates, fee payments, fund transfers, and order creation - Renamed and modified functions and parameters in the modify_trade.rs file - Updated the function signatures and removed unused code in the trade.rs file's validators and tests --- alpaca-broker/src/lib.rs | 7 +-- .../src/{modify_trade.rs => modify_stop.rs} | 10 ++-- alpaca-broker/src/modify_target.rs | 54 +++++++++++++++++++ core/src/validators/trade.rs | 6 +-- core/src/workers/trade_action.rs | 2 +- 5 files changed, 65 insertions(+), 14 deletions(-) rename alpaca-broker/src/{modify_trade.rs => modify_stop.rs} (86%) create mode 100644 alpaca-broker/src/modify_target.rs diff --git a/alpaca-broker/src/lib.rs b/alpaca-broker/src/lib.rs index f69a803..e221175 100644 --- a/alpaca-broker/src/lib.rs +++ b/alpaca-broker/src/lib.rs @@ -4,7 +4,8 @@ use std::error::Error; mod cancel_trade; mod close_trade; mod keys; -mod modify_trade; +mod modify_stop; +mod modify_target; mod order_mapper; mod submit_trade; mod sync_trade; @@ -50,7 +51,7 @@ impl Broker for AlpacaBroker { account: &Account, new_stop_price: rust_decimal::Decimal, ) -> Result> { - modify_trade::modify_stop(trade, account, new_stop_price) + modify_stop::modify(trade, account, new_stop_price) } fn modify_target( @@ -59,7 +60,7 @@ impl Broker for AlpacaBroker { account: &Account, new_target_price: rust_decimal::Decimal, ) -> Result> { - unimplemented!("Alpaca does not support modifying target prices") + modify_target::modify(trade, account, new_target_price) } } diff --git a/alpaca-broker/src/modify_trade.rs b/alpaca-broker/src/modify_stop.rs similarity index 86% rename from alpaca-broker/src/modify_trade.rs rename to alpaca-broker/src/modify_stop.rs index ec86b6b..0245424 100644 --- a/alpaca-broker/src/modify_trade.rs +++ b/alpaca-broker/src/modify_stop.rs @@ -9,7 +9,7 @@ use std::{error::Error, str::FromStr}; use tokio::runtime::Runtime; use uuid::Uuid; -pub fn modify_stop( +pub fn modify( trade: &Trade, account: &Account, price: Decimal, @@ -20,7 +20,7 @@ pub fn modify_stop( let client = Client::new(api_info); // Modify the stop order. - let alpaca_order = Runtime::new().unwrap().block_on(modify_entry( + let alpaca_order = Runtime::new().unwrap().block_on(submit( &client, trade.safety_stop.broker_order_id.unwrap(), price, @@ -36,11 +36,7 @@ pub fn modify_stop( Ok(log) } -async fn modify_entry( - client: &Client, - order_id: Uuid, - price: Decimal, -) -> Result> { +async fn submit(client: &Client, order_id: Uuid, price: Decimal) -> Result> { let request = ChangeReqInit { stop_price: Some(Num::from_str(price.to_string().as_str()).unwrap()), ..Default::default() diff --git a/alpaca-broker/src/modify_target.rs b/alpaca-broker/src/modify_target.rs new file mode 100644 index 0000000..8f7dafa --- /dev/null +++ b/alpaca-broker/src/modify_target.rs @@ -0,0 +1,54 @@ +use crate::keys; +use apca::api::v2::order::{ChangeReqInit, Id, Order, Patch}; +use apca::Client; +use model::BrokerLog; +use model::{Account, Trade}; +use num_decimal::Num; +use rust_decimal::Decimal; +use std::{error::Error, str::FromStr}; +use tokio::runtime::Runtime; +use uuid::Uuid; + +pub fn modify( + trade: &Trade, + account: &Account, + price: Decimal, +) -> Result> { + assert!(trade.account_id == account.id); // Verify that the trade is for the account + + let api_info = keys::read_api_key(&account.environment, account)?; + let client = Client::new(api_info); + + // Modify the stop order. + let alpaca_order = Runtime::new().unwrap().block_on(submit( + &client, + trade.target.broker_order_id.unwrap(), + price, + ))?; + + // 3. Log the Alpaca order. + let log = BrokerLog { + trade_id: trade.id, + log: serde_json::to_string(&alpaca_order)?, + ..Default::default() + }; + + Ok(log) +} + +async fn submit(client: &Client, order_id: Uuid, price: Decimal) -> Result> { + let request = ChangeReqInit { + limit_price: Some(Num::from_str(price.to_string().as_str()).unwrap()), + ..Default::default() + } + .init(); + + let result = client.issue::(&(Id(order_id), request)).await; + match result { + Ok(log) => Ok(log), + Err(e) => { + eprintln!("Error modify stop: {:?}", e); + Err(Box::new(e)) + } + } +} diff --git a/core/src/validators/trade.rs b/core/src/validators/trade.rs index 57779a7..b764700 100644 --- a/core/src/validators/trade.rs +++ b/core/src/validators/trade.rs @@ -78,7 +78,7 @@ pub fn can_modify_stop(trade: &Trade, new_price_stop: Decimal) -> TradeValidatio } } -pub fn can_modify_target(trade: &Trade, new_price: Decimal) -> TradeValidationResult { +pub fn can_modify_target(trade: &Trade) -> TradeValidationResult { match trade.status { Status::Filled => Ok(()), _ => Err(Box::new(TradeValidationError { @@ -314,7 +314,7 @@ mod tests { status: Status::Filled, ..Default::default() }; - let result = can_modify_target(&trade, dec!(10)); + let result = can_modify_target(&trade); assert!(result.is_ok()); } @@ -324,7 +324,7 @@ mod tests { status: Status::Canceled, ..Default::default() }; - let result = can_modify_target(&trade, dec!(10)); + let result = can_modify_target(&trade); assert!(result.is_err()); } } diff --git a/core/src/workers/trade_action.rs b/core/src/workers/trade_action.rs index 4d9a140..e86979a 100644 --- a/core/src/workers/trade_action.rs +++ b/core/src/workers/trade_action.rs @@ -310,7 +310,7 @@ impl TradeAction { database: &mut dyn DatabaseFactory, ) -> Result<(Trade, BrokerLog), Box> { // 1. Verify trade can be modified - crate::validators::trade::can_modify_target(trade, new_price)?; + crate::validators::trade::can_modify_target(trade)?; // 2. Update Trade on the broker let log = broker.modify_target(trade, account, new_price)?; From 8a8d575d57463b3929b6138aa2c856c780164619 Mon Sep 17 00:00:00 2001 From: mati Date: Mon, 7 Aug 2023 16:33:17 +0200 Subject: [PATCH 4/4] feat: Implement new integration test and modify `modify_target` function - Added a new integration test for modifying the target price of a trade - Modified the `modify_target` function in the `MockBroker` implementation - Changed the initial target price of the trade in the `modify_target` function test --- cli/tests/integration_test_trade.rs | 42 +++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/cli/tests/integration_test_trade.rs b/cli/tests/integration_test_trade.rs index e920ed6..f5c6da9 100644 --- a/cli/tests/integration_test_trade.rs +++ b/cli/tests/integration_test_trade.rs @@ -527,6 +527,44 @@ fn test_trade_modify_stop_long() { assert_eq!(log.trade_id, trade.id); } +#[test] +fn test_trade_modify_target() { + let (trust, account, trade) = create_trade( + BrokerResponse::orders_entry_filled, + Some(BrokerResponse::closed_order), + ); + let mut trust = trust; + + // 1. Sync trade with the Broker - Entry is filled + trust + .sync_trade(&trade, &account) + .expect("Failed to sync trade with broker when entry is filled"); + + let trade = trust + .search_trades(account.id, Status::Filled) + .expect("Failed to find trade with status submitted 2") + .first() + .unwrap() + .clone(); + + // 7. Modify stop + let (_, log) = trust + .modify_target(&trade, &account, dec!(100.1)) + .expect("Failed to modify stop"); + + let trade = trust + .search_trades(account.id, Status::Filled) + .expect("Failed to find trade with status filled") + .first() + .unwrap() + .clone(); + + // Assert Trade Overview + assert_eq!(trade.status, Status::Filled); // The trade is still filled, but the stop was changed + assert_eq!(trade.target.unit_price, dec!(100.1)); + assert_eq!(log.trade_id, trade.id); +} + struct BrokerResponse; impl BrokerResponse { @@ -812,8 +850,8 @@ impl Broker for MockBroker { new_target_price: rust_decimal::Decimal, ) -> Result> { assert_eq!(trade.account_id, account.id); - assert_eq!(trade.target.unit_price, dec!(38)); - assert_eq!(new_target_price, dec!(39)); + assert_eq!(trade.target.unit_price, dec!(50)); + assert_eq!(new_target_price, dec!(100.1)); Ok(BrokerLog { trade_id: trade.id,