diff --git a/rustybot/src/managers.rs b/rustybot/src/managers.rs index a848599..014a2a8 100644 --- a/rustybot/src/managers.rs +++ b/rustybot/src/managers.rs @@ -4,7 +4,7 @@ use std::ops::Neg; use bitfinex::ticker::TradingPairTicker; use futures_util::stream::FuturesUnordered; use futures_util::StreamExt; -use log::{debug, error}; +use log::{debug, error, info}; use tokio::signal::unix::Signal; use tokio::sync::mpsc::channel; use tokio::sync::mpsc::{Receiver, Sender}; @@ -16,6 +16,8 @@ use crate::models::{ExecutedOrder, OrderForm, OrderKind, Position, PriceTicker}; use crate::strategy::{FastOrderStrategy, OrderStrategy, PositionStrategy, TrailingStop}; use crate::BoxError; +type OptionUpdate = (Option>, Option>); + pub struct EventManager { events: Vec, } @@ -226,10 +228,8 @@ impl PositionManager { Ok(()) } - pub async fn update( - &mut self, - tick: u64, - ) -> Result<(Option>, Option), BoxError> { + + pub async fn update(&mut self, tick: u64) -> Result { let opt_active_positions = self.client.active_positions(&self.pair).await?; let mut events = vec![]; @@ -265,7 +265,7 @@ impl PositionManager { } }; - Ok(((events.is_empty().then_some(events)), None)) + Ok((None, None)) } pub fn position_previous_tick(&self, id: u64, tick: Option) -> Option<&Position> { @@ -369,19 +369,26 @@ impl OrderManager { pub async fn close_position(&mut self, position: &Position) -> Result<(), BoxError> { let open_order = self.tracked_positions.get(&position.id()); + info!("Closing position {}", position.id()); + // 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 open_order { Some(open_order) => { + info!("There is an open order. Calling strategy."); + self.tracked_positions = self .strategy .on_position_close(open_order, &self.tracked_positions); } None => { + info!("Getting current prices..."); let current_prices = self.client.current_prices(&self.pair).await?; + info!("Calculating best closing price..."); let closing_price = self.best_closing_price(&position, ¤t_prices)?; + info!("Submitting order..."); // submitting order let order_form = OrderForm::new( &self.pair, @@ -394,6 +401,7 @@ impl OrderManager { Err(e) => error!("Could not submit order: {}", e), Ok(o) => { self.tracked_positions.insert(position.id(), o); + info!("Done!"); } }; } @@ -402,7 +410,7 @@ impl OrderManager { Ok(()) } - pub fn update(&self) -> Option> { + pub fn update(&self) -> Result { unimplemented!() } @@ -464,17 +472,16 @@ impl ExchangeManager { } } - pub async fn update_managers(&mut self, tick: u64) -> Result<(), BoxError> { - self.update_price_managers(tick).await?; - self.update_position_managers(tick).await?; + pub async fn update_managers(&mut self, tick: u64) -> Result { + let (price_opt_events, price_opt_signals) = self.update_price_managers(tick).await?; + let (pos_opt_events, pos_opt_signals) = self.update_position_managers(tick).await?; - Ok(()) + debug!("{:?}", pos_opt_signals); + + Ok((pos_opt_events, price_opt_signals)) } - async fn update_position_managers( - &mut self, - tick: u64, - ) -> Result>, BoxError> { + async fn update_position_managers(&mut self, tick: u64) -> Result { let mut futures: FuturesUnordered<_> = self .position_managers .iter_mut() @@ -483,10 +490,10 @@ impl ExchangeManager { while let Some(x) = futures.next().await {} - Ok(None) + Ok((None, None)) } - async fn update_price_managers(&mut self, tick: u64) -> Result>, BoxError> { + async fn update_price_managers(&mut self, tick: u64) -> Result { let mut futures: FuturesUnordered<_> = self .price_managers .iter_mut() @@ -495,6 +502,6 @@ impl ExchangeManager { while let Some(x) = futures.next().await {} - Ok(None) + Ok((None, None)) } } diff --git a/rustybot/src/strategy.rs b/rustybot/src/strategy.rs index e238a8a..c1b27ff 100644 --- a/rustybot/src/strategy.rs +++ b/rustybot/src/strategy.rs @@ -17,7 +17,7 @@ pub trait PositionStrategy: DynClone + Send { &self, position: Position, manager: &PositionManager, - ) -> (Position, Vec, Option); + ) -> (Position, Option>, Option>); } impl Debug for dyn PositionStrategy { @@ -60,7 +60,7 @@ impl TrailingStop { const BREAK_EVEN_PERC: f64 = 0.2; const MIN_PROFIT_PERC: f64 = TrailingStop::BREAK_EVEN_PERC + 0.3; const GOOD_PROFIT_PERC: f64 = TrailingStop::MIN_PROFIT_PERC * 2.5; - const MAX_LOSS_PERC: f64 = -1.7; + const MAX_LOSS_PERC: f64 = -0.01; const TAKER_FEE: f64 = 0.2; @@ -84,11 +84,11 @@ impl PositionStrategy for TrailingStop { &self, position: Position, manager: &PositionManager, - ) -> (Position, Vec, Option) { + ) -> (Position, Option>, Option>) { let mut signals = vec![]; - let pl_perc = TrailingStop::net_pl_percentage(position.pl_perc(), TrailingStop::TAKER_FEE); let events = vec![]; - let mut order = None; + + let pl_perc = TrailingStop::net_pl_percentage(position.pl_perc(), TrailingStop::TAKER_FEE); let state = { if pl_perc > TrailingStop::GOOD_PROFIT_PERC { @@ -114,10 +114,20 @@ impl PositionStrategy for TrailingStop { match opt_pre_pw { Some(prev) => { if prev.profit_state() == Some(state) { - return (new_position, events, order); + return ( + new_position, + (!events.is_empty()).then_some(events), + (!signals.is_empty()).then_some(signals), + ); } } - None => return (new_position, events, order), + None => { + return ( + new_position, + (!events.is_empty()).then_some(events), + (!signals.is_empty()).then_some(signals), + ) + } }; let events = { @@ -158,7 +168,11 @@ impl PositionStrategy for TrailingStop { events }; - return (new_position, events, order); + return ( + new_position, + (!events.is_empty()).then_some(events), + (!signals.is_empty()).then_some(signals), + ); } }