First steps towards REST + WS connectors (BFX lib still in the works)
This commit is contained in:
parent
354ef407f3
commit
f43fcb0206
47
Cargo.lock
generated
47
Cargo.lock
generated
@ -109,7 +109,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
"tungstenite 0.13.0",
|
||||
"url",
|
||||
]
|
||||
|
||||
@ -1189,7 +1189,7 @@ dependencies = [
|
||||
"regex",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tungstenite",
|
||||
"tungstenite 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1353,6 +1353,26 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
@ -1450,7 +1470,7 @@ dependencies = [
|
||||
"log 0.4.11",
|
||||
"pin-project 1.0.2",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
"tungstenite 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1531,6 +1551,27 @@ dependencies = [
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fe8dada8c1a3aeca77d6b51a4f1314e0f4b8e438b7b1b71e3ddaca8080e4093"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"bytes 1.0.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"input_buffer",
|
||||
"log 0.4.11",
|
||||
"native-tls",
|
||||
"rand 0.8.2",
|
||||
"sha-1",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
|
@ -4,11 +4,12 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bitfinex::api::Bitfinex;
|
||||
use bitfinex::api::RestClient;
|
||||
use bitfinex::book::BookPrecision;
|
||||
use bitfinex::orders::{CancelOrderForm, OrderMeta};
|
||||
use bitfinex::responses::{OrderResponse, TradeResponse};
|
||||
use bitfinex::ticker::TradingPairTicker;
|
||||
use bitfinex::websockets::WebSocketClient;
|
||||
use futures_retry::RetryPolicy;
|
||||
use log::trace;
|
||||
use tokio::macros::support::Future;
|
||||
@ -36,7 +37,7 @@ pub enum ExchangeDetails {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Client {
|
||||
exchange: Exchange,
|
||||
inner: Arc<Box<dyn Connector>>,
|
||||
inner: Arc<Box<dyn RestConnector>>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
@ -168,8 +169,9 @@ impl Client {
|
||||
pub async fn trading_fees(&self) -> Result<Vec<TradingFees>, BoxError> { self.inner.trading_fees().await }
|
||||
}
|
||||
|
||||
/// This trait represents a REST API service.
|
||||
#[async_trait]
|
||||
pub trait Connector: Send + Sync {
|
||||
pub trait RestConnector: Send + Sync {
|
||||
fn name(&self) -> String;
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError>;
|
||||
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError>;
|
||||
@ -193,18 +195,26 @@ pub trait Connector: Send + Sync {
|
||||
async fn trading_fees(&self) -> Result<Vec<TradingFees>, BoxError>;
|
||||
}
|
||||
|
||||
impl Debug for dyn Connector {
|
||||
impl Debug for dyn RestConnector {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}", self.name())
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait represents a WebSocket API service.
|
||||
#[async_trait]
|
||||
pub trait WebSocketConnector: Send + Sync {
|
||||
fn name(&self) -> String;
|
||||
async fn connect(&self) -> Result<(), BoxError>;
|
||||
}
|
||||
|
||||
/**************
|
||||
* BITFINEX
|
||||
**************/
|
||||
|
||||
pub struct BitfinexConnector {
|
||||
bfx: Bitfinex,
|
||||
rest: bitfinex::api::RestClient,
|
||||
ws: bitfinex::websockets::WebSocketClient,
|
||||
}
|
||||
|
||||
impl BitfinexConnector {
|
||||
@ -219,7 +229,8 @@ impl BitfinexConnector {
|
||||
|
||||
pub fn new(api_key: &str, api_secret: &str) -> Self {
|
||||
BitfinexConnector {
|
||||
bfx: Bitfinex::new(Some(api_key.into()), Some(api_secret.into())),
|
||||
rest: RestClient::new(Some(api_key.into()), Some(api_secret.into())),
|
||||
ws: WebSocketClient::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,14 +271,14 @@ impl BitfinexConnector {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Connector for BitfinexConnector {
|
||||
impl RestConnector for BitfinexConnector {
|
||||
fn name(&self) -> String {
|
||||
"Bitfinex".into()
|
||||
"Bitfinex REST".into()
|
||||
}
|
||||
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError> {
|
||||
let active_positions =
|
||||
BitfinexConnector::retry_nonce(|| self.bfx.positions.active_positions()).await?;
|
||||
BitfinexConnector::retry_nonce(|| self.rest.positions.active_positions()).await?;
|
||||
|
||||
let positions: Vec<_> = active_positions
|
||||
.into_iter()
|
||||
@ -282,7 +293,7 @@ impl Connector for BitfinexConnector {
|
||||
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError> {
|
||||
let symbol_name = BitfinexConnector::format_trading_pair(pair);
|
||||
|
||||
let ticker: TradingPairTicker = self.bfx.ticker.trading_pair(symbol_name).await?;
|
||||
let ticker: TradingPairTicker = self.rest.ticker.trading_pair(symbol_name).await?;
|
||||
|
||||
Ok(ticker)
|
||||
}
|
||||
@ -291,7 +302,7 @@ impl Connector for BitfinexConnector {
|
||||
let symbol_name = BitfinexConnector::format_trading_pair(pair);
|
||||
|
||||
let response = BitfinexConnector::retry_nonce(|| {
|
||||
self.bfx.book.trading_pair(&symbol_name, BookPrecision::P0)
|
||||
self.rest.book.trading_pair(&symbol_name, BookPrecision::P0)
|
||||
})
|
||||
.await?;
|
||||
|
||||
@ -308,7 +319,7 @@ impl Connector for BitfinexConnector {
|
||||
}
|
||||
|
||||
async fn active_orders(&self, _: &SymbolPair) -> Result<Vec<ActiveOrder>, BoxError> {
|
||||
let response = BitfinexConnector::retry_nonce(|| self.bfx.orders.active_orders()).await?;
|
||||
let response = BitfinexConnector::retry_nonce(|| self.rest.orders.active_orders()).await?;
|
||||
|
||||
Ok(response.iter().map(Into::into).collect())
|
||||
}
|
||||
@ -351,7 +362,7 @@ impl Connector for BitfinexConnector {
|
||||
};
|
||||
|
||||
let response =
|
||||
BitfinexConnector::retry_nonce(|| self.bfx.orders.submit_order(&order_form)).await?;
|
||||
BitfinexConnector::retry_nonce(|| self.rest.orders.submit_order(&order_form)).await?;
|
||||
|
||||
// parsing response into ActiveOrder and adding leverage from order form
|
||||
let order_response: ActiveOrder = (&response).try_into()?;
|
||||
@ -364,7 +375,7 @@ impl Connector for BitfinexConnector {
|
||||
let cancel_form = order.into();
|
||||
|
||||
let response =
|
||||
BitfinexConnector::retry_nonce(|| self.bfx.orders.cancel_order(&cancel_form)).await?;
|
||||
BitfinexConnector::retry_nonce(|| self.rest.orders.cancel_order(&cancel_form)).await?;
|
||||
|
||||
Ok((&response).try_into()?)
|
||||
}
|
||||
@ -377,7 +388,7 @@ impl Connector for BitfinexConnector {
|
||||
amount: f64,
|
||||
) -> Result<(), BoxError> {
|
||||
BitfinexConnector::retry_nonce(|| {
|
||||
self.bfx.account.transfer_between_wallets(
|
||||
self.rest.account.transfer_between_wallets(
|
||||
from.into(),
|
||||
to.into(),
|
||||
symbol.to_string(),
|
||||
@ -394,7 +405,7 @@ impl Connector for BitfinexConnector {
|
||||
order: &OrderDetails,
|
||||
) -> Result<Option<Vec<Trade>>, BoxError> {
|
||||
let response = BitfinexConnector::retry_nonce(|| {
|
||||
self.bfx
|
||||
self.rest
|
||||
.trades
|
||||
.generated_by_order(order.pair().trading_repr(), order.id())
|
||||
})
|
||||
@ -412,7 +423,7 @@ impl Connector for BitfinexConnector {
|
||||
pair: &SymbolPair,
|
||||
) -> Result<Option<Vec<OrderDetails>>, BoxError> {
|
||||
let response =
|
||||
BitfinexConnector::retry_nonce(|| self.bfx.orders.history(Some(pair.trading_repr())))
|
||||
BitfinexConnector::retry_nonce(|| self.rest.orders.history(Some(pair.trading_repr())))
|
||||
.await?;
|
||||
let mapped_vec: Vec<_> = response.iter().map(Into::into).collect();
|
||||
|
||||
@ -422,7 +433,7 @@ impl Connector for BitfinexConnector {
|
||||
async fn trading_fees(&self) -> Result<Vec<TradingFees>, BoxError> {
|
||||
let mut fees = vec![];
|
||||
let accountfees =
|
||||
BitfinexConnector::retry_nonce(|| self.bfx.account.account_summary()).await?;
|
||||
BitfinexConnector::retry_nonce(|| self.rest.account.account_summary()).await?;
|
||||
|
||||
// Derivatives
|
||||
let derivative_taker = TradingFees::Taker {
|
||||
@ -464,6 +475,17 @@ impl Connector for BitfinexConnector {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WebSocketConnector for BitfinexConnector {
|
||||
fn name(&self) -> String {
|
||||
"Bitfinex WS".into()
|
||||
}
|
||||
|
||||
async fn connect(&self) -> Result<(), BoxError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ActiveOrder> for CancelOrderForm {
|
||||
fn from(o: &ActiveOrder) -> Self {
|
||||
Self::from_id(o.id())
|
||||
|
Loading…
Reference in New Issue
Block a user