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::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<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 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<ActiveOrder>,
client: Client,
strategy: Box<dyn OrderStrategy>,
}
impl OrderManager {
@ -398,14 +397,12 @@ impl OrderManager {
receiver: Receiver<ActorMessage>,
pair: SymbolPair,
client: Client,
strategy: Box<dyn OrderStrategy>,
) -> 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<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.");
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,

View File

@ -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<Box<dyn OrderStrategy>>,
}
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<Box<dyn OrderStrategy>>) -> 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<Box<dyn OrderStrategy>> {
&self.strategy
}
}
impl Hash for ActiveOrder {
@ -389,21 +402,50 @@ impl OrderForm {
}
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct OrderMetadata {
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 {
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<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> {
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 },
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,
}
}
}