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:
parent
669bd70946
commit
634f86c6fa
@ -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,
|
||||
|
@ -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 {
|
||||
@ -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<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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user