core/rustybot/src/connectors.rs

138 lines
4.1 KiB
Rust
Raw Normal View History

2021-01-06 21:17:01 +00:00
use std::convert::{TryFrom, TryInto};
use async_trait::async_trait;
use bitfinex::api::Bitfinex;
2021-01-11 17:16:44 +00:00
use bitfinex::orders::{OrderForm, OrderMeta};
2021-01-06 21:17:01 +00:00
use bitfinex::ticker::TradingPairTicker;
use crate::currency::{Symbol, SymbolPair};
2021-01-11 17:16:44 +00:00
use crate::orders::{Order, OrderKind};
2021-01-06 21:17:01 +00:00
use crate::positions::{Position, PositionState};
use crate::BoxError;
2021-01-11 17:16:44 +00:00
#[derive(Eq, PartialEq, Hash, Clone)]
pub enum ExchangeKind {
Bitfinex,
}
2021-01-06 21:17:01 +00:00
#[async_trait]
pub trait Connector {
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError>;
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError>;
async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<Order>, BoxError>;
2021-01-11 17:16:44 +00:00
async fn submit_order(
&self,
pair: &SymbolPair,
amount: f64,
price: f64,
kind: &OrderKind,
) -> Result<(), BoxError>;
2021-01-06 21:17:01 +00:00
}
pub struct BfxWrapper {
bfx: Bitfinex,
affiliate_code: Option<String>,
// account_info: String,
// ledger: String,
}
impl BfxWrapper {
pub fn new(api_key: &str, api_secret: &str) -> Self {
BfxWrapper {
bfx: Bitfinex::new(Some(api_key.into()), Some(api_secret.into())),
affiliate_code: None,
}
}
pub fn with_affiliate_code(mut self, affiliate_code: Option<String>) -> Self {
self.affiliate_code = affiliate_code;
self
}
}
impl TryInto<Position> for bitfinex::positions::Position {
type Error = BoxError;
fn try_into(self) -> Result<Position, Self::Error> {
let state = {
if self.status().to_lowercase().contains("active") {
PositionState::Open
} else {
PositionState::Closed
}
};
Ok(Position::new(
self.symbol().try_into()?,
state,
self.amount(),
self.base_price(),
self.pl(),
self.pl_perc(),
self.price_liq(),
self.position_id(),
)
.with_creation_date(self.mts_create())
.with_creation_update(self.mts_update()))
}
}
2021-01-11 17:16:44 +00:00
impl From<&OrderKind> for bitfinex::orders::OrderKind {
fn from(o: &OrderKind) -> Self {
match o {
OrderKind::Limit => Self::Limit,
OrderKind::ExchangeLimit => Self::ExchangeLimit,
OrderKind::Market => Self::Market,
OrderKind::ExchangeMarket => Self::ExchangeMarket,
OrderKind::Stop => Self::Stop,
OrderKind::ExchangeStop => Self::ExchangeStop,
OrderKind::StopLimit => Self::StopLimit,
OrderKind::ExchangeStopLimit => Self::ExchangeStopLimit,
OrderKind::TrailingStop => Self::TrailingStop,
OrderKind::Fok => Self::Fok,
OrderKind::ExchangeFok => Self::ExchangeFok,
OrderKind::Ioc => Self::Ioc,
OrderKind::ExchangeIoc => Self::ExchangeIoc,
}
}
}
2021-01-06 21:17:01 +00:00
#[async_trait]
impl Connector for BfxWrapper {
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError> {
let active_positions = self.bfx.positions.active_positions().await?;
Ok(active_positions
.into_iter()
.filter_map(|x| x.try_into().ok())
.filter(|x: &Position| x.pair() == pair)
.collect())
}
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError> {
let ticker: TradingPairTicker = self.bfx.ticker.trading_pair(pair.clone()).await?;
Ok(ticker)
}
async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<Order>, BoxError> {
unimplemented!()
}
2021-01-11 17:16:44 +00:00
async fn submit_order(
&self,
pair: &SymbolPair,
amount: f64,
price: f64,
kind: &OrderKind,
) -> Result<(), BoxError> {
let order_form = match &self.affiliate_code {
Some(affiliate_code) => OrderForm::new(pair.trading_repr(), price, amount, kind.into())
.with_meta(OrderMeta::new(affiliate_code.clone())),
None => OrderForm::new(pair.trading_repr(), price, amount, kind.into()),
};
Ok(self.bfx.orders.submit_order(&order_form).await?)
2021-01-06 21:17:01 +00:00
}
}