fetch account fees on-demand and apply them to position p/l

This commit is contained in:
Giulio De Pasquale 2021-02-13 14:58:15 +00:00
parent b46aec3395
commit ce8eec71ff
2 changed files with 102 additions and 17 deletions

View File

@ -57,21 +57,52 @@ impl Client {
pair: &SymbolPair, pair: &SymbolPair,
) -> Result<Option<Vec<Position>>, BoxError> { ) -> Result<Option<Vec<Position>>, BoxError> {
// retrieving open positions and order book to calculate effective profit/loss // retrieving open positions and order book to calculate effective profit/loss
let (positions, order_book) = tokio::join!( let (positions, order_book, fees) = tokio::join!(
self.inner.active_positions(pair), self.inner.active_positions(pair),
self.inner.order_book(pair) self.inner.order_book(pair),
self.inner.trading_fees()
); );
let (mut positions, order_book) = (positions?, order_book?); let (mut positions, order_book, fees) = (positions?, order_book?, fees?);
let (best_ask, best_bid) = (order_book.lowest_ask(), order_book.highest_bid()); let (best_ask, best_bid) = (order_book.lowest_ask(), order_book.highest_bid());
let derivative_taker = fees
.iter()
.filter_map(|x| match x {
TradingFees::Taker {
platform,
percentage,
} if platform == &TradingPlatform::Derivative => Some(percentage),
_ => None,
})
.next()
.ok_or("Could not retrieve derivative taker fee!")?;
let margin_taker = fees
.iter()
.filter_map(|x| match x {
TradingFees::Taker {
platform,
percentage,
} if platform == &TradingPlatform::Margin => Some(percentage),
_ => None,
})
.next()
.ok_or("Could not retrieve margin taker fee!")?;
// updating positions with effective profit/loss // updating positions with effective profit/loss
// TODO: change fee with account's taker fee
positions.iter_mut().flatten().for_each(|x| { positions.iter_mut().flatten().for_each(|x| {
let fee = match x.platform() {
TradingPlatform::Funding | TradingPlatform::Exchange => {
unimplemented!()
}
TradingPlatform::Margin => margin_taker,
TradingPlatform::Derivative => derivative_taker,
};
if x.is_short() { if x.is_short() {
x.update_profit_loss(best_ask, 0.075); x.update_profit_loss(best_ask, *fee);
} else { } else {
x.update_profit_loss(best_bid, 0.075); x.update_profit_loss(best_bid, *fee);
} }
}); });
@ -380,7 +411,46 @@ impl Connector for BitfinexConnector {
} }
async fn trading_fees(&self) -> Result<Vec<TradingFees>, BoxError> { async fn trading_fees(&self) -> Result<Vec<TradingFees>, BoxError> {
unimplemented!() let mut fees = vec![];
let accountfees = self.bfx.account.account_summary().await?;
// Derivatives
let derivative_taker = TradingFees::Taker {
platform: TradingPlatform::Derivative,
percentage: accountfees.derivative_taker() * 100.0,
};
let derivative_maker = TradingFees::Maker {
platform: TradingPlatform::Derivative,
percentage: accountfees.derivative_rebate() * 100.0,
};
fees.push(derivative_taker);
fees.push(derivative_maker);
// Exchange
let exchange_taker = TradingFees::Taker {
platform: TradingPlatform::Exchange,
percentage: accountfees.taker_to_fiat() * 100.0,
};
let exchange_maker = TradingFees::Maker {
platform: TradingPlatform::Exchange,
percentage: accountfees.maker_fee() * 100.0,
};
fees.push(exchange_taker);
fees.push(exchange_maker);
// Margin
let margin_taker = TradingFees::Taker {
platform: TradingPlatform::Margin,
percentage: accountfees.taker_to_fiat() * 100.0,
};
let margin_maker = TradingFees::Maker {
platform: TradingPlatform::Margin,
percentage: accountfees.maker_fee() * 100.0,
};
fees.push(margin_taker);
fees.push(margin_maker);
Ok(fees)
} }
} }
@ -423,6 +493,14 @@ impl TryInto<Position> for bitfinex::positions::Position {
} }
}; };
let platform = {
if self.symbol().to_ascii_lowercase().contains("f0") {
TradingPlatform::Derivative
} else {
TradingPlatform::Margin
}
};
Ok(Position::new( Ok(Position::new(
SymbolPair::from_str(self.symbol())?, SymbolPair::from_str(self.symbol())?,
state, state,
@ -432,6 +510,7 @@ impl TryInto<Position> for bitfinex::positions::Position {
self.pl_perc(), self.pl_perc(),
self.price_liq(), self.price_liq(),
self.position_id(), self.position_id(),
platform,
) )
.with_creation_date(self.mts_create()) .with_creation_date(self.mts_create())
.with_creation_update(self.mts_update())) .with_creation_update(self.mts_update()))
@ -648,23 +727,23 @@ impl From<&bitfinex::orders::ActiveOrder> for OrderDetails {
// TODO: fields are hardcoded, to fix // TODO: fields are hardcoded, to fix
impl From<&bitfinex::responses::TradeResponse> for Trade { impl From<&bitfinex::responses::TradeResponse> for Trade {
fn from(response: &TradeResponse) -> Self { fn from(response: &TradeResponse) -> Self {
let pair = SymbolPair::from_str(&response.symbol).unwrap(); let pair = SymbolPair::from_str(&response.symbol()).unwrap();
let fee = { let fee = {
if response.is_maker { if response.is_maker() {
OrderFee::Maker(response.fee) OrderFee::Maker(response.fee())
} else { } else {
OrderFee::Taker(response.fee) OrderFee::Taker(response.fee())
} }
}; };
Self { Self {
trade_id: response.trade_id, trade_id: response.trade_id(),
pair, pair,
execution_timestamp: response.execution_timestamp, execution_timestamp: response.execution_timestamp(),
price: response.execution_price, price: response.execution_price(),
amount: response.execution_amount, amount: response.execution_amount(),
fee, fee,
fee_currency: Symbol::new(response.symbol.clone()), fee_currency: Symbol::new(response.symbol().to_owned().clone()),
} }
} }
} }

View File

@ -186,7 +186,7 @@ impl PartialEq for ActiveOrder {
impl Eq for ActiveOrder {} impl Eq for ActiveOrder {}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum TradingPlatform { pub enum TradingPlatform {
Exchange, Exchange,
Derivative, Derivative,
@ -396,6 +396,7 @@ pub struct Position {
position_id: u64, position_id: u64,
creation_date: Option<u64>, creation_date: Option<u64>,
creation_update: Option<u64>, creation_update: Option<u64>,
platform: TradingPlatform,
} }
impl Position { impl Position {
@ -408,6 +409,7 @@ impl Position {
pl_perc: f64, pl_perc: f64,
price_liq: f64, price_liq: f64,
position_id: u64, position_id: u64,
platform: TradingPlatform,
) -> Self { ) -> Self {
Position { Position {
pair, pair,
@ -421,6 +423,7 @@ impl Position {
creation_date: None, creation_date: None,
creation_update: None, creation_update: None,
profit_state: None, profit_state: None,
platform,
} }
} }
@ -505,6 +508,9 @@ impl Position {
pub fn is_long(&self) -> bool { pub fn is_long(&self) -> bool {
self.amount.is_sign_positive() self.amount.is_sign_positive()
} }
pub fn platform(&self) -> TradingPlatform {
self.platform
}
} }
impl Hash for Position { impl Hash for Position {