removed extra function for orderstrategy (for now). order manager update is now working

This commit is contained in:
Giulio De Pasquale 2021-01-26 17:01:58 +00:00
parent ef618ad754
commit ac1fd3669f
2 changed files with 125 additions and 111 deletions

View File

@ -404,57 +404,34 @@ impl OrderManager {
info!("Closing position #{}", position_id); info!("Closing position #{}", position_id);
debug!("Retrieving open orders, positions and current prices..."); debug!("Retrieving open orders, positions and current prices...");
let (open_orders, order_book, open_positions) = tokio::join!( let (res_open_orders, res_order_book, res_open_positions) = tokio::join!(
self.client.active_orders(&self.pair), self.client.active_orders(&self.pair),
self.client.order_book(&self.pair), self.client.order_book(&self.pair),
self.client.active_positions(&self.pair) self.client.active_positions(&self.pair)
); );
let open_orders = match open_orders { let (open_orders, order_book, open_positions) =
Ok(open_orders) => open_orders, (res_open_orders?, res_order_book?, res_open_positions?);
Err(e) => {
error!("Could not retrieve open orders: {}", e);
return Err(e);
}
};
let order_book = match order_book { let position = open_positions
Ok(order_book) => order_book, .ok_or("No open positions!")?
Err(e) => {
error!("Could not retrieve order book: {}", e);
return Err(e);
}
};
let position = match open_positions {
Ok(opt_positions) => {
let positions = opt_positions.ok_or::<BoxError>("No open positions".into())?;
positions
.into_iter() .into_iter()
.find(|x| x.id() == position_id) .find(|x| x.id() == position_id)
.ok_or::<BoxError>("Position #{} not found in open positions".into())? .ok_or("Position #{} not found in open positions.")?;
}
Err(e) => {
error!("Could not retrieve open positions: {}", e);
return Err(e);
}
};
let opt_position_order = open_orders let opt_position_order = open_orders
.iter() .iter()
.find(|x| x.current_form.amount().neg() == position.amount()); .find(|x| x.current_form.amount().neg() == position.amount());
// checking if the position has an open order. // checking if the position has an open order.
// If so, the strategy method is called, otherwise we open // If so, don't do anything since the order is taken care of
// an undercut limit order at the best current price. // in the update phase.
match opt_position_order { // If no order is open, send an undercut limit order at the best current price.
if let None = opt_position_order {
// No open order, undercutting best price with limit order // No open order, undercutting best price with limit order
None => {
let closing_price = self.best_closing_price(&position, &order_book); let closing_price = self.best_closing_price(&position, &order_book);
// TODO: hardocoded platform to Margin! // TODO: hardcoded platform to Margin!
let order_form = OrderForm::new( let order_form = OrderForm::new(
self.pair.clone(), self.pair.clone(),
OrderKind::Limit { OrderKind::Limit {
@ -475,35 +452,6 @@ impl OrderManager {
return Err(e); return Err(e);
} }
} }
Some(active_order) => {
debug!(
"Found open order, calling \"{}\" strategy.",
self.strategy.name()
);
let (_, strat_messages) =
self.strategy
.on_position_order(active_order, &position, &order_book)?;
if let Some(messages) = strat_messages {
for m in messages {
match m {
Message::SubmitOrder { order } => {
info!("Closing open order.");
info!("Cancelling open order #{}", active_order.id);
self.client.cancel_order(active_order).await?;
info!("Submitting {}...", order.kind());
self.client.submit_order(&order).await?;
}
_ => {
debug!("Received unsupported message from order strategy. Unimplemented.")
}
}
}
}
}
}
Ok((None, None)) Ok((None, None))
} }
@ -512,11 +460,42 @@ impl OrderManager {
pub async fn update(&self) -> Result<OptionUpdate, BoxError> { pub async fn update(&self) -> Result<OptionUpdate, BoxError> {
trace!("\t[OrderManager] Updating {}", self.pair); trace!("\t[OrderManager] Updating {}", self.pair);
let (open_orders, opt_open_positions) = tokio::join!( let (res_open_orders, res_order_book) = tokio::join!(
self.client.active_orders(&self.pair), self.client.active_orders(&self.pair),
self.client.active_positions(&self.pair) self.client.order_book(&self.pair)
); );
let (_open_orders, _opt_open_positions) = (open_orders?, opt_open_positions?);
let (open_orders, order_book) = (res_open_orders?, res_order_book?);
for active_order in open_orders {
debug!(
"Found open order, calling \"{}\" strategy.",
self.strategy.name()
);
let (_, strat_messages) = self.strategy.on_open_order(&active_order, &order_book)?;
if let Some(messages) = strat_messages {
for m in messages {
match m {
Message::SubmitOrder { order: order_form } => {
info!("Closing open order...");
info!("\tCancelling open order #{}", &active_order.id);
self.client.cancel_order(&active_order).await?;
info!("\tSubmitting {}...", order_form.kind());
self.client.submit_order(&order_form).await?;
info!("Done!");
}
_ => {
debug!(
"Received unsupported message from order strategy. Unimplemented."
)
}
}
}
}
}
Ok((None, None)) Ok((None, None))
} }

View File

@ -5,6 +5,7 @@ use dyn_clone::DynClone;
use log::info; use log::info;
use crate::events::{Event, EventKind, EventMetadata, Message}; use crate::events::{Event, EventKind, EventMetadata, Message};
use crate::managers::OptionUpdate;
use crate::models::{ use crate::models::{
ActiveOrder, OrderBook, OrderBookEntry, OrderForm, OrderKind, Position, PositionProfitState, ActiveOrder, OrderBook, OrderBookEntry, OrderForm, OrderKind, Position, PositionProfitState,
PositionState, TradingPlatform, PositionState, TradingPlatform,
@ -42,15 +43,19 @@ pub trait OrderStrategy: DynClone + Send + Sync {
fn name(&self) -> String; fn name(&self) -> String;
/// This method is called when the OrderManager checks the open orders on a new tick. /// This method is called when the OrderManager checks the open orders on a new tick.
/// It should manage if some orders have to be closed or keep open. /// It should manage if some orders have to be closed or keep open.
fn on_open_order(&self); fn on_open_order(
/// This method is called when the OrderManager is requested to close
/// a position that has an open order associated to it.
fn on_position_order(
&self, &self,
order: &ActiveOrder, order: &ActiveOrder,
open_position: &Position,
order_book: &OrderBook, order_book: &OrderBook,
) -> Result<(Option<Vec<Event>>, Option<Vec<Message>>), BoxError>; ) -> Result<OptionUpdate, BoxError>;
// /// This method is called when the OrderManager is requested to close
// /// a position that has an open order associated to it.
// fn on_position_order(
// &self,
// order: &ActiveOrder,
// open_position: &Position,
// order_book: &OrderBook,
// ) -> Result<OptionUpdate, BoxError>;
} }
impl Debug for dyn OrderStrategy { impl Debug for dyn OrderStrategy {
@ -81,12 +86,6 @@ impl TrailingStop {
} }
fn update_stop_percentage(&mut self, position: &Position) { fn update_stop_percentage(&mut self, position: &Position) {
info!(
"\tState: {:?} | PL%: {:0.2}",
position.profit_state().unwrap(),
position.pl_perc()
);
if let Some(profit_state) = position.profit_state() { if let Some(profit_state) = position.profit_state() {
let profit_state_delta = match profit_state { let profit_state_delta = match profit_state {
PositionProfitState::MinimumProfit => Some(0.2), PositionProfitState::MinimumProfit => Some(0.2),
@ -95,12 +94,6 @@ impl TrailingStop {
}; };
if let Some(profit_state_delta) = profit_state_delta { if let Some(profit_state_delta) = profit_state_delta {
println!(
"PL%: {:0.2} | Delta: {}",
position.pl_perc(),
profit_state_delta
);
let current_stop_percentage = position.pl_perc() - profit_state_delta; let current_stop_percentage = position.pl_perc() - profit_state_delta;
match profit_state { match profit_state {
@ -121,6 +114,12 @@ impl TrailingStop {
_ => {} _ => {}
} }
} }
info!(
"\tState: {:?} | PL%: {:0.2} | Stop: {:0.2}",
position.profit_state().unwrap(),
position.pl_perc(),
self.stop_percentages.get(&position.id()).unwrap_or(&0.0)
);
} }
} }
} }
@ -223,6 +222,7 @@ impl PositionStrategy for TrailingStop {
if let Some(profit_state) = position.profit_state() { if let Some(profit_state) = position.profit_state() {
match profit_state { match profit_state {
PositionProfitState::Critical => { PositionProfitState::Critical => {
info!("Maximum loss reached. Closing position.");
return (position, None, Some(vec![close_message])); return (position, None, Some(vec![close_message]));
} }
_ => {} _ => {}
@ -267,16 +267,11 @@ impl OrderStrategy for FastOrderStrategy {
"Fast order strategy".into() "Fast order strategy".into()
} }
fn on_open_order(&self) { fn on_open_order(
unimplemented!()
}
fn on_position_order(
&self, &self,
order: &ActiveOrder, order: &ActiveOrder,
_: &Position,
order_book: &OrderBook, order_book: &OrderBook,
) -> Result<(Option<Vec<Event>>, Option<Vec<Message>>), BoxError> { ) -> Result<OptionUpdate, BoxError> {
let mut messages = vec![]; let mut messages = vec![];
// long // long
@ -310,4 +305,44 @@ impl OrderStrategy for FastOrderStrategy {
Ok((None, (!messages.is_empty()).then_some(messages))) Ok((None, (!messages.is_empty()).then_some(messages)))
} }
// fn on_position_order(
// &self,
// order: &ActiveOrder,
// _: &Position,
// order_book: &OrderBook,
// ) -> Result<OptionUpdate, BoxError> {
// let mut messages = vec![];
//
// // long
// let offer_comparison = {
// if order.current_form.amount() > 0.0 {
// order_book.highest_bid()
// } else {
// order_book.lowest_ask()
// }
// };
//
// // if the best offer is higher than our threshold,
// // ask the manager to close the position with a market order
// let order_price = order
// .current_form
// .price()
// .ok_or("The active order does not have a price!")?;
// let delta = (1.0 - (offer_comparison / order_price)).abs() * 100.0;
//
// if delta > self.threshold {
// messages.push(Message::SubmitOrder {
// order: OrderForm::new(
// order.symbol.clone(),
// OrderKind::Market {
// amount: order.current_form.amount(),
// },
// order.current_form.platform().clone(),
// ),
// })
// }
//
// Ok((None, (!messages.is_empty()).then_some(messages)))
// }
} }