rust #10

Merged
peperunas merged 127 commits from rust into master 2021-02-18 09:42:16 +00:00
2 changed files with 125 additions and 111 deletions
Showing only changes of commit ac1fd3669f - Show all commits

View File

@ -404,104 +404,52 @@ impl OrderManager {
info!("Closing position #{}", position_id);
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.order_book(&self.pair),
self.client.active_positions(&self.pair)
);
let open_orders = match open_orders {
Ok(open_orders) => open_orders,
Err(e) => {
error!("Could not retrieve open orders: {}", e);
return Err(e);
}
};
let (open_orders, order_book, open_positions) =
(res_open_orders?, res_order_book?, res_open_positions?);
let order_book = match order_book {
Ok(order_book) => order_book,
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()
.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 position = open_positions
.ok_or("No open positions!")?
.into_iter()
.find(|x| x.id() == position_id)
.ok_or("Position #{} not found in open positions.")?;
let opt_position_order = open_orders
.iter()
.find(|x| x.current_form.amount().neg() == position.amount());
// checking if the position has an open order.
// If so, the strategy method is called, otherwise we open
// an undercut limit order at the best current price.
match opt_position_order {
// If so, don't do anything since the order is taken care of
// in the update phase.
// 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
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!
let order_form = OrderForm::new(
self.pair.clone(),
OrderKind::Limit {
price: closing_price,
amount: position.amount().neg(),
},
TradingPlatform::Margin,
// TODO: hardcoded platform to Margin!
let order_form = OrderForm::new(
self.pair.clone(),
OrderKind::Limit {
price: closing_price,
amount: position.amount().neg(),
},
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
);
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.")
}
}
}
}
return Err(e);
}
}
@ -512,11 +460,42 @@ impl OrderManager {
pub async fn update(&self) -> Result<OptionUpdate, BoxError> {
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_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))
}

View File

@ -5,6 +5,7 @@ use dyn_clone::DynClone;
use log::info;
use crate::events::{Event, EventKind, EventMetadata, Message};
use crate::managers::OptionUpdate;
use crate::models::{
ActiveOrder, OrderBook, OrderBookEntry, OrderForm, OrderKind, Position, PositionProfitState,
PositionState, TradingPlatform,
@ -42,15 +43,19 @@ pub trait OrderStrategy: DynClone + Send + Sync {
fn name(&self) -> String;
/// 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.
fn on_open_order(&self);
/// 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(
fn on_open_order(
&self,
order: &ActiveOrder,
open_position: &Position,
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 {
@ -81,12 +86,6 @@ impl TrailingStop {
}
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() {
let profit_state_delta = match profit_state {
PositionProfitState::MinimumProfit => Some(0.2),
@ -95,12 +94,6 @@ impl TrailingStop {
};
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;
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() {
match profit_state {
PositionProfitState::Critical => {
info!("Maximum loss reached. Closing position.");
return (position, None, Some(vec![close_message]));
}
_ => {}
@ -267,16 +267,11 @@ impl OrderStrategy for FastOrderStrategy {
"Fast order strategy".into()
}
fn on_open_order(&self) {
unimplemented!()
}
fn on_position_order(
fn on_open_order(
&self,
order: &ActiveOrder,
_: &Position,
order_book: &OrderBook,
) -> Result<(Option<Vec<Event>>, Option<Vec<Message>>), BoxError> {
) -> Result<OptionUpdate, BoxError> {
let mut messages = vec![];
// long
@ -310,4 +305,44 @@ impl OrderStrategy for FastOrderStrategy {
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)))
// }
}