retrieving updated information on open orders before calling strategy

This commit is contained in:
Giulio De Pasquale 2021-01-24 13:41:18 +00:00
parent 5b84c99703
commit 9b92d38318
2 changed files with 135 additions and 35 deletions

View File

@ -155,8 +155,10 @@ impl Connector for BitfinexConnector {
Ok(ticker) Ok(ticker)
} }
async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<ActiveOrder>, BoxError> { async fn active_orders(&self, _: &SymbolPair) -> Result<Vec<ActiveOrder>, BoxError> {
unimplemented!() let response = self.bfx.orders.active_orders().await?;
Ok(response.iter().map(Into::into).collect())
} }
async fn submit_order(&self, order: &OrderForm) -> Result<ActiveOrder, BoxError> { async fn submit_order(&self, order: &OrderForm) -> Result<ActiveOrder, BoxError> {
@ -321,6 +323,21 @@ impl From<&bitfinex::orders::OrderResponse> for TradingPlatform {
} }
} }
impl From<&bitfinex::orders::ActiveOrder> for TradingPlatform {
fn from(response: &bitfinex::orders::ActiveOrder) -> Self {
match response.order_type() {
bitfinex::orders::OrderKind::Limit
| bitfinex::orders::OrderKind::Market
| bitfinex::orders::OrderKind::StopLimit
| bitfinex::orders::OrderKind::Stop
| bitfinex::orders::OrderKind::TrailingStop
| bitfinex::orders::OrderKind::Fok
| bitfinex::orders::OrderKind::Ioc => Self::Margin,
_ => Self::Exchange,
}
}
}
impl From<&bitfinex::orders::OrderResponse> for OrderKind { impl From<&bitfinex::orders::OrderResponse> for OrderKind {
fn from(response: &OrderResponse) -> Self { fn from(response: &OrderResponse) -> Self {
match response.order_type() { match response.order_type() {
@ -345,11 +362,11 @@ impl From<&bitfinex::orders::OrderResponse> for OrderKind {
| bitfinex::orders::OrderKind::ExchangeStopLimit => Self::StopLimit { | bitfinex::orders::OrderKind::ExchangeStopLimit => Self::StopLimit {
price: response.price(), price: response.price(),
amount: response.amount(), amount: response.amount(),
limit_price: response.price_aux_limit(), limit_price: response.price_aux_limit().expect("Limit price not found!"),
}, },
bitfinex::orders::OrderKind::TrailingStop bitfinex::orders::OrderKind::TrailingStop
| bitfinex::orders::OrderKind::ExchangeTrailingStop => Self::TrailingStop { | bitfinex::orders::OrderKind::ExchangeTrailingStop => Self::TrailingStop {
distance: response.price_trailing(), distance: response.price_trailing().expect("Distance not found!"),
amount: response.amount(), amount: response.amount(),
}, },
bitfinex::orders::OrderKind::Fok | bitfinex::orders::OrderKind::ExchangeFok => { bitfinex::orders::OrderKind::Fok | bitfinex::orders::OrderKind::ExchangeFok => {
@ -368,6 +385,70 @@ impl From<&bitfinex::orders::OrderResponse> for OrderKind {
} }
} }
impl From<&bitfinex::orders::ActiveOrder> for OrderKind {
fn from(response: &bitfinex::orders::ActiveOrder) -> Self {
match response.order_type() {
bitfinex::orders::OrderKind::Limit | bitfinex::orders::OrderKind::ExchangeLimit => {
Self::Limit {
price: response.price(),
amount: response.amount(),
}
}
bitfinex::orders::OrderKind::Market | bitfinex::orders::OrderKind::ExchangeMarket => {
Self::Market {
amount: response.amount(),
}
}
bitfinex::orders::OrderKind::Stop | bitfinex::orders::OrderKind::ExchangeStop => {
Self::Stop {
price: response.price(),
amount: response.amount(),
}
}
bitfinex::orders::OrderKind::StopLimit
| bitfinex::orders::OrderKind::ExchangeStopLimit => Self::StopLimit {
price: response.price(),
amount: response.amount(),
limit_price: response.price_aux_limit().expect("Limit price not found!"),
},
bitfinex::orders::OrderKind::TrailingStop
| bitfinex::orders::OrderKind::ExchangeTrailingStop => Self::TrailingStop {
distance: response.price_trailing().expect("Distance not found!"),
amount: response.amount(),
},
bitfinex::orders::OrderKind::Fok | bitfinex::orders::OrderKind::ExchangeFok => {
Self::FillOrKill {
price: response.price(),
amount: response.amount(),
}
}
bitfinex::orders::OrderKind::Ioc | bitfinex::orders::OrderKind::ExchangeIoc => {
Self::ImmediateOrCancel {
price: response.price(),
amount: response.amount(),
}
}
}
}
}
impl From<&bitfinex::orders::ActiveOrder> for ActiveOrder {
fn from(order: &bitfinex::orders::ActiveOrder) -> Self {
let pair = SymbolPair::from_str(&order.symbol()).expect("Invalid symbol!");
Self {
exchange: Exchange::Bitfinex,
id: order.id(),
group_id: order.group_id().map(|x| x as u64),
client_id: Some(order.client_id()),
symbol: pair.clone(),
current_form: OrderForm::new(pair, order.into(), order.into()),
creation_timestamp: order.creation_timestamp(),
update_timestamp: order.update_timestamp(),
}
}
}
impl From<TradingPairTicker> for PriceTicker { impl From<TradingPairTicker> for PriceTicker {
fn from(t: TradingPairTicker) -> Self { fn from(t: TradingPairTicker) -> Self {
Self { Self {

View File

@ -319,7 +319,8 @@ impl PositionManager {
* ORDERS * ORDERS
******************/ ******************/
pub type TrackedPositionsMap = HashMap<u64, ActiveOrder>; // Position ID: Order ID
pub type TrackedPositionsMap = HashMap<u64, u64>;
pub struct OrderManagerHandle { pub struct OrderManagerHandle {
sender: Sender<ActorMessage>, sender: Sender<ActorMessage>,
@ -405,7 +406,7 @@ impl OrderManager {
pub async fn handle_message(&mut self, msg: ActorMessage) -> Result<(), BoxError> { pub async fn handle_message(&mut self, msg: ActorMessage) -> Result<(), BoxError> {
match msg.message { match msg.message {
Message::Update { .. } => { Message::Update { .. } => {
self.update(); self.update().await?;
} }
Message::ClosePosition { Message::ClosePosition {
position, position,
@ -424,39 +425,23 @@ impl OrderManager {
position: &Position, position: &Position,
order_form: &OrderForm, order_form: &OrderForm,
) -> Result<(), BoxError> { ) -> Result<(), BoxError> {
let open_order = self.tracked_positions.get(&position.id()); info!("Closing position #{}", position.id());
debug!("Retrieving open orders...");
let open_orders = self.client.active_orders(&self.pair).await?;
let opt_position_order = open_orders
.iter()
.find(|x| x.current_form.amount().neg() == position.amount());
debug!("Closing position #{}", position.id());
debug!("Getting current prices..."); debug!("Getting current prices...");
let order_book = self.client.order_book(&self.pair).await?; let order_book = self.client.order_book(&self.pair).await?;
// 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, the strategy method is called, otherwise we open
// an undercut limit order at the best current price. // an undercut limit order at the best current price.
match open_order { match opt_position_order {
Some(open_order) => { // No open order, undercutting best price with limit order
debug!("There is an open order. Calling strategy.");
let (_, messages) =
self.strategy
.on_position_close(open_order, position, &order_book)?;
if let Some(messages) = messages {
for m in messages {
match m {
Message::ClosePosition { order_form, .. } => {
info!("Closing open order with a {} order", order_form.kind());
if let Ok(_) = self.client.submit_order(&order_form).await {
info!("Cancelling open order #{}", open_order.id);
self.client.cancel_order(open_order).await?;
}
}
_ => {
debug!("Received unsupported message from order strategy. Unimplemented.")
}
}
}
}
}
None => { None => {
let closing_price = self.best_closing_price(&position, &order_book); let closing_price = self.best_closing_price(&position, &order_book);
@ -471,16 +456,50 @@ impl OrderManager {
); );
info!("Submitting {} order", order_form.kind()); info!("Submitting {} order", order_form.kind());
let active_order = self.client.submit_order(&order_form).await?; 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()
);
self.tracked_positions.insert(position.id(), active_order); let (_, strat_messages) =
self.strategy
.on_position_close(active_order, position, &order_book)?;
if let Some(messages) = strat_messages {
for m in messages {
match m {
Message::ClosePosition { order_form, .. } => {
info!("Closing open order with a {} order", order_form.kind());
if let Ok(_) = self.client.submit_order(&order_form).await {
info!("Cancelling open order #{}", active_order.id);
self.client.cancel_order(active_order).await?;
}
}
_ => {
debug!("Received unsupported message from order strategy. Unimplemented.")
}
}
}
}
} }
} }
Ok(()) Ok(())
} }
pub fn update(&self) -> Result<OptionUpdate, BoxError> { pub async fn update(&self) -> Result<OptionUpdate, BoxError> {
// TODO: implement me // TODO: implement me
Ok((None, None)) Ok((None, None))
} }