removed extra function for orderstrategy (for now). order manager update is now working
This commit is contained in:
parent
ef618ad754
commit
ac1fd3669f
@ -404,104 +404,52 @@ 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) => {
|
.into_iter()
|
||||||
error!("Could not retrieve order book: {}", e);
|
.find(|x| x.id() == position_id)
|
||||||
return Err(e);
|
.ok_or("Position #{} not found in open positions.")?;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let position = match open_positions {
|
|
||||||
Ok(opt_positions) => {
|
|
||||||
let positions = opt_positions.ok_or::<BoxError>("No open positions".into())?;
|
|
||||||
|
|
||||||
positions
|
|
||||||
.into_iter()
|
|
||||||
.find(|x| x.id() == position_id)
|
|
||||||
.ok_or::<BoxError>("Position #{} not found in open positions".into())?
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
price: closing_price,
|
price: closing_price,
|
||||||
amount: position.amount().neg(),
|
amount: position.amount().neg(),
|
||||||
},
|
},
|
||||||
TradingPlatform::Margin,
|
TradingPlatform::Margin,
|
||||||
|
);
|
||||||
|
|
||||||
|
info!("Submitting {} order", order_form.kind());
|
||||||
|
if let Err(e) = self.client.submit_order(&order_form).await {
|
||||||
|
error!(
|
||||||
|
"Could not submit {} to close position #{}: {}",
|
||||||
|
order_form.kind(),
|
||||||
|
position.id(),
|
||||||
|
e
|
||||||
);
|
);
|
||||||
|
return Err(e);
|
||||||
info!("Submitting {} order", order_form.kind());
|
|
||||||
if let Err(e) = self.client.submit_order(&order_form).await {
|
|
||||||
error!(
|
|
||||||
"Could not submit {} to close position #{}: {}",
|
|
||||||
order_form.kind(),
|
|
||||||
position.id(),
|
|
||||||
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.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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)))
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user