diff --git a/src/managers.rs b/src/managers.rs index 3e2ddc5..42f28fc 100644 --- a/src/managers.rs +++ b/src/managers.rs @@ -1,6 +1,8 @@ + use std::collections::HashMap; use std::ops::Neg; + use futures_util::stream::FuturesUnordered; use futures_util::StreamExt; use log::{debug, error, info, trace}; @@ -14,9 +16,7 @@ use crate::BoxError; use crate::connectors::{Client, ExchangeDetails}; use crate::currency::SymbolPair; use crate::events::{ActionMessage, ActorMessage, Event}; -use crate::models::{ - ActiveOrder, OrderBook, OrderForm, OrderKind, Position, PriceTicker, -}; +use crate::models::{ActiveOrder, OrderBook, OrderForm, OrderKind, OrderMetadata, Position, PriceTicker}; use crate::strategy::{HiddenTrailingStop, MarketEnforce, OrderStrategy, PositionStrategy}; pub type OptionUpdate = (Option>, Option>); @@ -331,10 +331,10 @@ impl OrderManagerHandle { } } - pub fn new(pair: SymbolPair, client: Client, strategy: Box) -> Self { + pub fn new(pair: SymbolPair, client: Client) -> Self { let (sender, receiver) = channel(1); - let manager = OrderManager::new(receiver, pair, client, strategy); + let manager = OrderManager::new(receiver, pair, client); tokio::spawn(OrderManagerHandle::run_order_manager(manager)); @@ -390,7 +390,6 @@ pub struct OrderManager { pair: SymbolPair, open_orders: Vec, client: Client, - strategy: Box, } impl OrderManager { @@ -398,14 +397,12 @@ impl OrderManager { receiver: Receiver, pair: SymbolPair, client: Client, - strategy: Box, ) -> Self { OrderManager { receiver, pair, open_orders: Vec::new(), client, - strategy, tracked_positions: HashMap::new(), } } @@ -452,9 +449,17 @@ impl OrderManager { } pub async fn submit_order(&mut self, order_form: &OrderForm) -> Result { - info!("Submiting {}", order_form.kind()); + info!("Submitting order: {}", order_form.kind()); - let active_order = self.client.submit_order(order_form).await?; + // adding strategy to order, if present in the metadata + let active_order = { + if let Some(metadata) = order_form.metadata() { + // TODO: this seems extremely dirty. Double check! + self.client.submit_order(order_form).await?.with_strategy(metadata.cloned_strategy()) + } else { + self.client.submit_order(order_form).await? + } + }; debug!("Adding order to tracked orders."); if let Some(metadata) = order_form.metadata() { @@ -515,7 +520,10 @@ impl OrderManager { position.platform(), position.amount().neg(), ) - .with_leverage(Some(position.leverage())); + .with_leverage(Some(position.leverage())) + .with_metadata(Some(OrderMetadata::new() + .with_strategy(Some(Box::new(MarketEnforce::default())))) + ); info!("Submitting {} order", order_form.kind()); if let Err(e) = self.client.submit_order(&order_form).await { @@ -585,13 +593,16 @@ impl OrderManager { } } - for active_order in open_orders { + // TODO: this syntax can be simplified + for active_order in open_orders.iter().filter(|x| x.strategy().is_some()) { + let strategy = active_order.strategy().as_ref().unwrap(); + trace!( - "Found open order, calling \"{}\" strategy.", - self.strategy.name() + "Found open order with \"{}\" strategy.", + strategy.name() ); - let (_, strat_messages) = self.strategy.on_open_order(&active_order, &order_book)?; + let (_, strat_messages) = strategy.on_open_order(&active_order, &order_book)?; if let Some(messages) = strat_messages { for m in messages { @@ -602,7 +613,7 @@ impl OrderManager { self.client.cancel_order(&active_order).await?; info!("\tSubmitting {}...", order_form.kind()); - self.client.submit_order(&order_form).await?; + self.submit_order(&order_form).await?; info!("Done!"); } _ => { @@ -659,7 +670,6 @@ impl PairManager { order_manager: OrderManagerHandle::new( pair.clone(), client.clone(), - Box::new(MarketEnforce::default()), ), position_manager: PositionManagerHandle::new( pair, diff --git a/src/models.rs b/src/models.rs index eb7bc33..01e673f 100644 --- a/src/models.rs +++ b/src/models.rs @@ -2,8 +2,11 @@ use std::fmt; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; +use dyn_clone::clone_box; + use crate::connectors::Exchange; use crate::currency::{Symbol, SymbolPair}; +use crate::strategy::OrderStrategy; /*************** * Prices @@ -148,7 +151,7 @@ impl OrderDetails { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct ActiveOrder { exchange: Exchange, id: u64, @@ -158,6 +161,7 @@ pub struct ActiveOrder { order_form: OrderForm, creation_timestamp: u64, update_timestamp: u64, + strategy: Option>, } impl ActiveOrder { @@ -178,6 +182,7 @@ impl ActiveOrder { order_form, creation_timestamp, update_timestamp, + strategy: None, } } @@ -191,6 +196,11 @@ impl ActiveOrder { self } + pub fn with_strategy(mut self, strategy: Option>) -> Self { + self.strategy = strategy; + self + } + pub fn exchange(&self) -> Exchange { self.exchange } @@ -215,6 +225,9 @@ impl ActiveOrder { pub fn update_timestamp(&self) -> u64 { self.update_timestamp } + pub fn strategy(&self) -> &Option> { + &self.strategy + } } impl Hash for ActiveOrder { @@ -285,13 +298,13 @@ impl Display for OrderKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { OrderKind::Limit { price } => { - write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) + write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, ) } OrderKind::Market => { write!(f, "[{}]", self.as_str()) } OrderKind::Stop { price } => { - write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) + write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, ) } OrderKind::StopLimit { stop_price, limit_price } => { write!( @@ -303,13 +316,13 @@ impl Display for OrderKind { ) } OrderKind::TrailingStop { distance } => { - write!(f, "[{} | Distance: {:0.5}]", self.as_str(), distance,) + write!(f, "[{} | Distance: {:0.5}]", self.as_str(), distance, ) } OrderKind::FillOrKill { price } => { - write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) + write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, ) } OrderKind::ImmediateOrCancel { price } => { - write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) + write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, ) } } } @@ -389,21 +402,50 @@ impl OrderForm { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct OrderMetadata { position_id: Option, + strategy: Option>, +} + +impl Clone for OrderMetadata { + fn clone(&self) -> Self { + Self { + position_id: self.position_id.clone(), + strategy: self.strategy.as_ref().map(|x| clone_box(&**x)), + } + } } impl OrderMetadata { - pub fn with_position_id(position_id: u64) -> Self { - OrderMetadata { - position_id: Some(position_id), + pub fn new() -> Self { + Self { + position_id: None, + strategy: None, } } + pub fn with_position_id(mut self, position_id: Option) -> Self { + self.position_id = position_id; + self + } + + pub fn with_strategy(mut self, strategy: Option>) -> Self { + self.strategy = strategy; + self + } + pub fn position_id(&self) -> Option { self.position_id } + pub fn cloned_strategy(&self) -> Option> { + match &self.strategy { + None => { None } + Some(strategy) => { + Some(clone_box(&**strategy)) + } + } + } } /*************** diff --git a/src/strategy.rs b/src/strategy.rs index fbf1d12..0ee31bc 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -282,7 +282,7 @@ impl PositionStrategy for HiddenTrailingStop { OrderKind::Stop { price: stop_loss_price }, position.platform(), position.amount().neg()) - .with_metadata(Some(OrderMetadata::with_position_id(position.id()))) + .with_metadata(Some(OrderMetadata::new().with_position_id(Some(position.id())))) }; let stop_loss_set = *self.stop_loss_flags.entry(position.id()).or_insert(false); @@ -590,7 +590,7 @@ pub struct MarketEnforce { impl Default for MarketEnforce { fn default() -> Self { Self { - threshold: 100.0, + threshold: 1.2 / 15.0, } } }