use crate::{Error, Result};
use crate::types::{LimitOrderAmounts, LimitOrderData, Side};
use rust_decimal::Decimal;
const MIN_ORDER_SIZE: i64 = 10_000_000_000_000_000;
const PRECISION: i64 = 1_000_000_000_000_000_000;
pub fn retain_significant_digits(value: Decimal, sig_figs: u32) -> Decimal {
if value.is_zero() {
return Decimal::ZERO;
}
let is_negative = value.is_sign_negative();
let abs_value = value.abs().normalize();
let str_value = abs_value.to_string();
let digits_only: String = str_value.chars().filter(|c| c.is_ascii_digit()).collect();
let magnitude = digits_only.len();
let excess = magnitude as i32 - sig_figs as i32;
if excess <= 0 {
return value; }
let mut divisor = Decimal::ONE;
for _ in 0..excess {
divisor *= Decimal::TEN;
}
let truncated = (abs_value / divisor).floor() * divisor;
if is_negative {
-truncated
} else {
truncated
}
}
pub fn get_limit_order_amounts(data: LimitOrderData) -> Result<LimitOrderAmounts> {
let min_size = Decimal::from(MIN_ORDER_SIZE);
let precision = Decimal::from(PRECISION);
if data.quantity_wei < min_size {
return Err(Error::InvalidQuantity(format!(
"Quantity {} is less than minimum {}",
data.quantity_wei, min_size
)));
}
let price = retain_significant_digits(data.price_per_share_wei, 3);
let qty = retain_significant_digits(data.quantity_wei, 5);
let (maker_amount, taker_amount) = match data.side {
Side::Buy => {
let maker_amount = price.checked_mul(qty)
.map(|result| result / precision)
.unwrap_or_else(|| {
(price / precision) * qty
});
let taker_amount = qty;
(maker_amount, taker_amount)
}
Side::Sell => {
let maker_amount = qty;
let taker_amount = price.checked_mul(qty)
.map(|result| result / precision)
.unwrap_or_else(|| {
(price / precision) * qty
});
(maker_amount, taker_amount)
}
};
Ok(LimitOrderAmounts {
last_price: price,
price_per_share: price,
maker_amount,
taker_amount,
})
}