From ac1fd3669ff8ed9219f4f06a6a741ba700c16595 Mon Sep 17 00:00:00 2001 From: Giulio De Pasquale Date: Tue, 26 Jan 2021 17:01:58 +0000 Subject: [PATCH] removed extra function for orderstrategy (for now). order manager update is now working --- rustybot/src/managers.rs | 151 +++++++++++++++++---------------------- rustybot/src/strategy.rs | 85 +++++++++++++++------- 2 files changed, 125 insertions(+), 111 deletions(-) diff --git a/rustybot/src/managers.rs b/rustybot/src/managers.rs index b0e02c8..cba7211 100644 --- a/rustybot/src/managers.rs +++ b/rustybot/src/managers.rs @@ -404,104 +404,52 @@ impl OrderManager { info!("Closing position #{}", position_id); debug!("Retrieving open orders, positions and current prices..."); - let (open_orders, order_book, open_positions) = tokio::join!( + let (res_open_orders, res_order_book, res_open_positions) = tokio::join!( self.client.active_orders(&self.pair), self.client.order_book(&self.pair), self.client.active_positions(&self.pair) ); - let open_orders = match open_orders { - Ok(open_orders) => open_orders, - Err(e) => { - error!("Could not retrieve open orders: {}", e); - return Err(e); - } - }; + let (open_orders, order_book, open_positions) = + (res_open_orders?, res_order_book?, res_open_positions?); - let order_book = match order_book { - Ok(order_book) => order_book, - Err(e) => { - error!("Could not retrieve order book: {}", e); - return Err(e); - } - }; - - let position = match open_positions { - Ok(opt_positions) => { - let positions = opt_positions.ok_or::("No open positions".into())?; - - positions - .into_iter() - .find(|x| x.id() == position_id) - .ok_or::("Position #{} not found in open positions".into())? - } - - Err(e) => { - error!("Could not retrieve open positions: {}", e); - return Err(e); - } - }; + let position = open_positions + .ok_or("No open positions!")? + .into_iter() + .find(|x| x.id() == position_id) + .ok_or("Position #{} not found in open positions.")?; let opt_position_order = open_orders .iter() .find(|x| x.current_form.amount().neg() == position.amount()); // checking if the position has an open order. - // If so, the strategy method is called, otherwise we open - // an undercut limit order at the best current price. - match opt_position_order { + // If so, don't do anything since the order is taken care of + // in the update phase. + // If no order is open, send an undercut limit order at the best current price. + if let None = opt_position_order { // No open order, undercutting best price with limit order - None => { - let closing_price = self.best_closing_price(&position, &order_book); + let closing_price = self.best_closing_price(&position, &order_book); - // TODO: hardocoded platform to Margin! - let order_form = OrderForm::new( - self.pair.clone(), - OrderKind::Limit { - price: closing_price, - amount: position.amount().neg(), - }, - TradingPlatform::Margin, + // TODO: hardcoded platform to Margin! + let order_form = OrderForm::new( + self.pair.clone(), + OrderKind::Limit { + price: closing_price, + amount: position.amount().neg(), + }, + TradingPlatform::Margin, + ); + + info!("Submitting {} order", order_form.kind()); + if let Err(e) = self.client.submit_order(&order_form).await { + error!( + "Could not submit {} to close position #{}: {}", + order_form.kind(), + position.id(), + e ); - - info!("Submitting {} order", order_form.kind()); - if let Err(e) = self.client.submit_order(&order_form).await { - error!( - "Could not submit {} to close position #{}: {}", - order_form.kind(), - position.id(), - e - ); - return Err(e); - } - } - Some(active_order) => { - debug!( - "Found open order, calling \"{}\" strategy.", - self.strategy.name() - ); - - let (_, strat_messages) = - self.strategy - .on_position_order(active_order, &position, &order_book)?; - - if let Some(messages) = strat_messages { - for m in messages { - match m { - Message::SubmitOrder { order } => { - info!("Closing open order."); - info!("Cancelling open order #{}", active_order.id); - self.client.cancel_order(active_order).await?; - - info!("Submitting {}...", order.kind()); - self.client.submit_order(&order).await?; - } - _ => { - debug!("Received unsupported message from order strategy. Unimplemented.") - } - } - } - } + return Err(e); } } @@ -512,11 +460,42 @@ impl OrderManager { pub async fn update(&self) -> Result { trace!("\t[OrderManager] Updating {}", self.pair); - let (open_orders, opt_open_positions) = tokio::join!( + let (res_open_orders, res_order_book) = tokio::join!( self.client.active_orders(&self.pair), - self.client.active_positions(&self.pair) + self.client.order_book(&self.pair) ); - let (_open_orders, _opt_open_positions) = (open_orders?, opt_open_positions?); + + let (open_orders, order_book) = (res_open_orders?, res_order_book?); + + for active_order in open_orders { + debug!( + "Found open order, calling \"{}\" strategy.", + self.strategy.name() + ); + + let (_, strat_messages) = self.strategy.on_open_order(&active_order, &order_book)?; + + if let Some(messages) = strat_messages { + for m in messages { + match m { + Message::SubmitOrder { order: order_form } => { + info!("Closing open order..."); + info!("\tCancelling open order #{}", &active_order.id); + self.client.cancel_order(&active_order).await?; + + info!("\tSubmitting {}...", order_form.kind()); + self.client.submit_order(&order_form).await?; + info!("Done!"); + } + _ => { + debug!( + "Received unsupported message from order strategy. Unimplemented." + ) + } + } + } + } + } Ok((None, None)) } diff --git a/rustybot/src/strategy.rs b/rustybot/src/strategy.rs index 34803e1..3ac2f03 100644 --- a/rustybot/src/strategy.rs +++ b/rustybot/src/strategy.rs @@ -5,6 +5,7 @@ use dyn_clone::DynClone; use log::info; use crate::events::{Event, EventKind, EventMetadata, Message}; +use crate::managers::OptionUpdate; use crate::models::{ ActiveOrder, OrderBook, OrderBookEntry, OrderForm, OrderKind, Position, PositionProfitState, PositionState, TradingPlatform, @@ -42,15 +43,19 @@ pub trait OrderStrategy: DynClone + Send + Sync { fn name(&self) -> String; /// This method is called when the OrderManager checks the open orders on a new tick. /// It should manage if some orders have to be closed or keep open. - fn on_open_order(&self); - /// This method is called when the OrderManager is requested to close - /// a position that has an open order associated to it. - fn on_position_order( + fn on_open_order( &self, order: &ActiveOrder, - open_position: &Position, order_book: &OrderBook, - ) -> Result<(Option>, Option>), BoxError>; + ) -> Result; + // /// This method is called when the OrderManager is requested to close + // /// a position that has an open order associated to it. + // fn on_position_order( + // &self, + // order: &ActiveOrder, + // open_position: &Position, + // order_book: &OrderBook, + // ) -> Result; } impl Debug for dyn OrderStrategy { @@ -81,12 +86,6 @@ impl TrailingStop { } fn update_stop_percentage(&mut self, position: &Position) { - info!( - "\tState: {:?} | PL%: {:0.2}", - position.profit_state().unwrap(), - position.pl_perc() - ); - if let Some(profit_state) = position.profit_state() { let profit_state_delta = match profit_state { PositionProfitState::MinimumProfit => Some(0.2), @@ -95,12 +94,6 @@ impl TrailingStop { }; if let Some(profit_state_delta) = profit_state_delta { - println!( - "PL%: {:0.2} | Delta: {}", - position.pl_perc(), - profit_state_delta - ); - let current_stop_percentage = position.pl_perc() - profit_state_delta; match profit_state { @@ -121,6 +114,12 @@ impl TrailingStop { _ => {} } } + info!( + "\tState: {:?} | PL%: {:0.2} | Stop: {:0.2}", + position.profit_state().unwrap(), + position.pl_perc(), + self.stop_percentages.get(&position.id()).unwrap_or(&0.0) + ); } } } @@ -223,6 +222,7 @@ impl PositionStrategy for TrailingStop { if let Some(profit_state) = position.profit_state() { match profit_state { PositionProfitState::Critical => { + info!("Maximum loss reached. Closing position."); return (position, None, Some(vec![close_message])); } _ => {} @@ -267,16 +267,11 @@ impl OrderStrategy for FastOrderStrategy { "Fast order strategy".into() } - fn on_open_order(&self) { - unimplemented!() - } - - fn on_position_order( + fn on_open_order( &self, order: &ActiveOrder, - _: &Position, order_book: &OrderBook, - ) -> Result<(Option>, Option>), BoxError> { + ) -> Result { let mut messages = vec![]; // long @@ -310,4 +305,44 @@ impl OrderStrategy for FastOrderStrategy { Ok((None, (!messages.is_empty()).then_some(messages))) } + + // fn on_position_order( + // &self, + // order: &ActiveOrder, + // _: &Position, + // order_book: &OrderBook, + // ) -> Result { + // let mut messages = vec![]; + // + // // long + // let offer_comparison = { + // if order.current_form.amount() > 0.0 { + // order_book.highest_bid() + // } else { + // order_book.lowest_ask() + // } + // }; + // + // // if the best offer is higher than our threshold, + // // ask the manager to close the position with a market order + // let order_price = order + // .current_form + // .price() + // .ok_or("The active order does not have a price!")?; + // let delta = (1.0 - (offer_comparison / order_price)).abs() * 100.0; + // + // if delta > self.threshold { + // messages.push(Message::SubmitOrder { + // order: OrderForm::new( + // order.symbol.clone(), + // OrderKind::Market { + // amount: order.current_form.amount(), + // }, + // order.current_form.platform().clone(), + // ), + // }) + // } + // + // Ok((None, (!messages.is_empty()).then_some(messages))) + // } }