orders are now per orderform and not per order manager. current order strategy is set only when executing limit order on profit by trailing stop

This commit is contained in:
Giulio De Pasquale 2021-02-20 22:17:53 +00:00
parent 669bd70946
commit 634f86c6fa
3 changed files with 81 additions and 29 deletions

View File

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Neg; use std::ops::Neg;
use futures_util::stream::FuturesUnordered; use futures_util::stream::FuturesUnordered;
use futures_util::StreamExt; use futures_util::StreamExt;
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
@ -14,9 +16,7 @@ use crate::BoxError;
use crate::connectors::{Client, ExchangeDetails}; use crate::connectors::{Client, ExchangeDetails};
use crate::currency::SymbolPair; use crate::currency::SymbolPair;
use crate::events::{ActionMessage, ActorMessage, Event}; use crate::events::{ActionMessage, ActorMessage, Event};
use crate::models::{ use crate::models::{ActiveOrder, OrderBook, OrderForm, OrderKind, OrderMetadata, Position, PriceTicker};
ActiveOrder, OrderBook, OrderForm, OrderKind, Position, PriceTicker,
};
use crate::strategy::{HiddenTrailingStop, MarketEnforce, OrderStrategy, PositionStrategy}; use crate::strategy::{HiddenTrailingStop, MarketEnforce, OrderStrategy, PositionStrategy};
pub type OptionUpdate = (Option<Vec<Event>>, Option<Vec<ActionMessage>>); pub type OptionUpdate = (Option<Vec<Event>>, Option<Vec<ActionMessage>>);
@ -331,10 +331,10 @@ impl OrderManagerHandle {
} }
} }
pub fn new(pair: SymbolPair, client: Client, strategy: Box<dyn OrderStrategy>) -> Self { pub fn new(pair: SymbolPair, client: Client) -> Self {
let (sender, receiver) = channel(1); 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)); tokio::spawn(OrderManagerHandle::run_order_manager(manager));
@ -390,7 +390,6 @@ pub struct OrderManager {
pair: SymbolPair, pair: SymbolPair,
open_orders: Vec<ActiveOrder>, open_orders: Vec<ActiveOrder>,
client: Client, client: Client,
strategy: Box<dyn OrderStrategy>,
} }
impl OrderManager { impl OrderManager {
@ -398,14 +397,12 @@ impl OrderManager {
receiver: Receiver<ActorMessage>, receiver: Receiver<ActorMessage>,
pair: SymbolPair, pair: SymbolPair,
client: Client, client: Client,
strategy: Box<dyn OrderStrategy>,
) -> Self { ) -> Self {
OrderManager { OrderManager {
receiver, receiver,
pair, pair,
open_orders: Vec::new(), open_orders: Vec::new(),
client, client,
strategy,
tracked_positions: HashMap::new(), tracked_positions: HashMap::new(),
} }
} }
@ -452,9 +449,17 @@ impl OrderManager {
} }
pub async fn submit_order(&mut self, order_form: &OrderForm) -> Result<OptionUpdate, BoxError> { pub async fn submit_order(&mut self, order_form: &OrderForm) -> Result<OptionUpdate, BoxError> {
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."); debug!("Adding order to tracked orders.");
if let Some(metadata) = order_form.metadata() { if let Some(metadata) = order_form.metadata() {
@ -515,7 +520,10 @@ impl OrderManager {
position.platform(), position.platform(),
position.amount().neg(), 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()); info!("Submitting {} order", order_form.kind());
if let Err(e) = self.client.submit_order(&order_form).await { 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!( trace!(
"Found open order, calling \"{}\" strategy.", "Found open order with \"{}\" strategy.",
self.strategy.name() 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 { if let Some(messages) = strat_messages {
for m in messages { for m in messages {
@ -602,7 +613,7 @@ impl OrderManager {
self.client.cancel_order(&active_order).await?; self.client.cancel_order(&active_order).await?;
info!("\tSubmitting {}...", order_form.kind()); info!("\tSubmitting {}...", order_form.kind());
self.client.submit_order(&order_form).await?; self.submit_order(&order_form).await?;
info!("Done!"); info!("Done!");
} }
_ => { _ => {
@ -659,7 +670,6 @@ impl PairManager {
order_manager: OrderManagerHandle::new( order_manager: OrderManagerHandle::new(
pair.clone(), pair.clone(),
client.clone(), client.clone(),
Box::new(MarketEnforce::default()),
), ),
position_manager: PositionManagerHandle::new( position_manager: PositionManagerHandle::new(
pair, pair,

View File

@ -2,8 +2,11 @@ use std::fmt;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use dyn_clone::clone_box;
use crate::connectors::Exchange; use crate::connectors::Exchange;
use crate::currency::{Symbol, SymbolPair}; use crate::currency::{Symbol, SymbolPair};
use crate::strategy::OrderStrategy;
/*************** /***************
* Prices * Prices
@ -148,7 +151,7 @@ impl OrderDetails {
} }
} }
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct ActiveOrder { pub struct ActiveOrder {
exchange: Exchange, exchange: Exchange,
id: u64, id: u64,
@ -158,6 +161,7 @@ pub struct ActiveOrder {
order_form: OrderForm, order_form: OrderForm,
creation_timestamp: u64, creation_timestamp: u64,
update_timestamp: u64, update_timestamp: u64,
strategy: Option<Box<dyn OrderStrategy>>,
} }
impl ActiveOrder { impl ActiveOrder {
@ -178,6 +182,7 @@ impl ActiveOrder {
order_form, order_form,
creation_timestamp, creation_timestamp,
update_timestamp, update_timestamp,
strategy: None,
} }
} }
@ -191,6 +196,11 @@ impl ActiveOrder {
self self
} }
pub fn with_strategy(mut self, strategy: Option<Box<dyn OrderStrategy>>) -> Self {
self.strategy = strategy;
self
}
pub fn exchange(&self) -> Exchange { pub fn exchange(&self) -> Exchange {
self.exchange self.exchange
} }
@ -215,6 +225,9 @@ impl ActiveOrder {
pub fn update_timestamp(&self) -> u64 { pub fn update_timestamp(&self) -> u64 {
self.update_timestamp self.update_timestamp
} }
pub fn strategy(&self) -> &Option<Box<dyn OrderStrategy>> {
&self.strategy
}
} }
impl Hash for ActiveOrder { impl Hash for ActiveOrder {
@ -285,13 +298,13 @@ impl Display for OrderKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
OrderKind::Limit { price } => { OrderKind::Limit { price } => {
write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, )
} }
OrderKind::Market => { OrderKind::Market => {
write!(f, "[{}]", self.as_str()) write!(f, "[{}]", self.as_str())
} }
OrderKind::Stop { price } => { 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 } => { OrderKind::StopLimit { stop_price, limit_price } => {
write!( write!(
@ -303,13 +316,13 @@ impl Display for OrderKind {
) )
} }
OrderKind::TrailingStop { distance } => { OrderKind::TrailingStop { distance } => {
write!(f, "[{} | Distance: {:0.5}]", self.as_str(), distance,) write!(f, "[{} | Distance: {:0.5}]", self.as_str(), distance, )
} }
OrderKind::FillOrKill { price } => { OrderKind::FillOrKill { price } => {
write!(f, "[{} | Price: {:0.5}]", self.as_str(), price,) write!(f, "[{} | Price: {:0.5}]", self.as_str(), price, )
} }
OrderKind::ImmediateOrCancel { 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 { pub struct OrderMetadata {
position_id: Option<u64>, position_id: Option<u64>,
strategy: Option<Box<dyn OrderStrategy>>,
}
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 { impl OrderMetadata {
pub fn with_position_id(position_id: u64) -> Self { pub fn new() -> Self {
OrderMetadata { Self {
position_id: Some(position_id), position_id: None,
strategy: None,
} }
} }
pub fn with_position_id(mut self, position_id: Option<u64>) -> Self {
self.position_id = position_id;
self
}
pub fn with_strategy(mut self, strategy: Option<Box<dyn OrderStrategy>>) -> Self {
self.strategy = strategy;
self
}
pub fn position_id(&self) -> Option<u64> { pub fn position_id(&self) -> Option<u64> {
self.position_id self.position_id
} }
pub fn cloned_strategy(&self) -> Option<Box<dyn OrderStrategy>> {
match &self.strategy {
None => { None }
Some(strategy) => {
Some(clone_box(&**strategy))
}
}
}
} }
/*************** /***************

View File

@ -282,7 +282,7 @@ impl PositionStrategy for HiddenTrailingStop {
OrderKind::Stop { price: stop_loss_price }, OrderKind::Stop { price: stop_loss_price },
position.platform(), position.platform(),
position.amount().neg()) 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); 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 { impl Default for MarketEnforce {
fn default() -> Self { fn default() -> Self {
Self { Self {
threshold: 100.0, threshold: 1.2 / 15.0,
} }
} }
} }