diff --git a/rustybot/src/connectors.rs b/rustybot/src/connectors.rs index d708ddc..b3702af 100644 --- a/rustybot/src/connectors.rs +++ b/rustybot/src/connectors.rs @@ -1,11 +1,14 @@ +use std::convert::{TryFrom, TryInto}; +use std::fmt::{Debug, Formatter}; +use std::str::FromStr; +use std::sync::Arc; + use async_trait::async_trait; use bitfinex::api::Bitfinex; -use bitfinex::orders::OrderMeta; +use bitfinex::orders::{OrderMeta, OrderResponse}; use bitfinex::ticker::TradingPairTicker; +use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc}; use log::debug; -use std::convert::TryInto; -use std::fmt::{Debug, Formatter}; -use std::sync::Arc; use crate::currency::SymbolPair; use crate::models::{ @@ -13,7 +16,6 @@ use crate::models::{ PriceTicker, }; use crate::BoxError; -use std::str::FromStr; #[derive(Eq, PartialEq, Hash, Clone, Debug)] pub enum ExchangeKind { @@ -65,6 +67,10 @@ impl Client { pub async fn order_book(&self, pair: &SymbolPair) -> Result { self.inner.order_book(pair).await } + + pub async fn cancel_order(&self, order: &ActiveOrder) -> Result { + self.inner.cancel_order(order).await + } } #[async_trait] @@ -75,6 +81,7 @@ pub trait Connector: Send + Sync { async fn order_book(&self, pair: &SymbolPair) -> Result; async fn active_orders(&self, pair: &SymbolPair) -> Result, BoxError>; async fn submit_order(&self, order: OrderForm) -> Result; + async fn cancel_order(&self, order: &ActiveOrder) -> Result; } impl Debug for dyn Connector { @@ -169,21 +176,7 @@ impl Connector for BitfinexConnector { let response = self.bfx.orders.submit_order(&order_form).await?; - Ok(ActiveOrder { - id: response.id(), - group_id: response.gid(), - client_id: response.cid(), - symbol: SymbolPair::from_str(response.symbol())?, - creation_timestamp: response.mts_create(), - update_timestamp: response.mts_update(), - amount: response.amount(), - amount_original: response.amount_orig(), - order_type: (&response.order_type()).into(), - previous_order_type: response.prev_order_type().map(|x| (&x).into()), - price: response.price(), - price_avg: response.price_avg(), - hidden: response.hidden(), - }) + Ok(response.try_into()?) } async fn order_book(&self, pair: &SymbolPair) -> Result { @@ -207,6 +200,43 @@ impl Connector for BitfinexConnector { Ok(OrderBook::new(pair.clone()).with_entries(entries)) } + + async fn cancel_order(&self, order: &ActiveOrder) -> Result { + let date = DateTime::::from_utc( + NaiveDateTime::from_timestamp(order.update_timestamp as i64, 0), + Utc, + ); + let cancel_form = bitfinex::orders::CancelOrderForm::new(order.id, order.client_id, date); + + Ok(self + .bfx + .orders + .cancel_order(&cancel_form) + .await? + .try_into()?) + } +} + +impl TryFrom for ActiveOrder { + type Error = BoxError; + + fn try_from(response: OrderResponse) -> Result { + Ok(Self { + id: response.id(), + group_id: response.gid(), + client_id: response.cid(), + symbol: SymbolPair::from_str(response.symbol())?, + creation_timestamp: response.mts_create(), + update_timestamp: response.mts_update(), + amount: response.amount(), + amount_original: response.amount_orig(), + order_type: (&response.order_type()).into(), + previous_order_type: response.prev_order_type().map(|x| (&x).into()), + price: response.price(), + price_avg: response.price_avg(), + hidden: response.hidden(), + }) + } } impl TryInto for bitfinex::positions::Position { diff --git a/rustybot/src/managers.rs b/rustybot/src/managers.rs index dbbc0d6..cdc9d7e 100644 --- a/rustybot/src/managers.rs +++ b/rustybot/src/managers.rs @@ -449,8 +449,15 @@ impl OrderManager { // TODO FIXME match order_kind { OrderKind::Market => { - self.submit_market_order(1.0, position.amount().neg()) - .await?; + info!("Closing open order with a market order."); + if let Ok(_) = self + .submit_market_order(1.0, position.amount().neg()) + .await + { + // cancel active order + info!("Cancelling open order #{}", open_order.id); + self.client.cancel_order(open_order).await?; + } } _ => {} } @@ -495,7 +502,7 @@ impl OrderManager { } pub async fn submit_limit_order( - &mut self, + &self, closing_price: f64, amount: f64, ) -> Result { @@ -510,7 +517,7 @@ impl OrderManager { } pub async fn submit_exchange_limit_order( - &mut self, + &self, closing_price: f64, amount: f64, ) -> Result { @@ -526,7 +533,7 @@ impl OrderManager { } pub async fn submit_market_order( - &mut self, + &self, closing_price: f64, amount: f64, ) -> Result { @@ -541,7 +548,7 @@ impl OrderManager { } pub async fn submit_exchange_market_order( - &mut self, + &self, closing_price: f64, amount: f64, ) -> Result { diff --git a/rustybot/src/strategy.rs b/rustybot/src/strategy.rs index 985a4ed..b954bd8 100644 --- a/rustybot/src/strategy.rs +++ b/rustybot/src/strategy.rs @@ -16,7 +16,7 @@ use crate::BoxError; * DEFINITIONS ***************/ -pub trait PositionStrategy: DynClone + Send { +pub trait PositionStrategy: DynClone + Send + Sync { fn name(&self) -> String; fn on_new_tick( &self, @@ -31,7 +31,7 @@ impl Debug for dyn PositionStrategy { } } -pub trait OrderStrategy: DynClone + Send { +pub trait OrderStrategy: DynClone + Send + Sync { /// The name of the strategy, used for debugging purposes fn name(&self) -> String; /// This method is called when the OrderManager checks the open orders on a new tick. @@ -235,11 +235,6 @@ impl OrderStrategy for FastOrderStrategy { // ask the manager to close the position with a market order let delta = (1.0 - (offer_comparison / order.price)) * 100.0; - debug!( - "Offer comp: {} | Our offer: {} | Current delta: {}", - offer_comparison, order.price, delta - ); - if delta > self.threshold { messages.push(Message::ClosePosition { position: active_position.clone(),