use crate::trade::error::TradeError;
use crate::trade::margin::MarginMode;
use crate::trade::orders::Side;
use crate::trade::ticket::{Market, Refusal};
use crate::utils::sign::{L1Action, Map};
use crate::utils::{Asset, BadUnits, Dec, Round};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UpdateIsolatedMargin {
asset: Asset,
position: Side,
ntli: i64,
}
impl UpdateIsolatedMargin {
pub fn new(asset: Asset, position: Side, usdc: Dec) -> Result<UpdateIsolatedMargin, TradeError> {
let bad = |error: BadUnits| TradeError::Margin(error);
if usdc.places() > 6 {
return Err(bad(BadUnits::TooFine { value: usdc, places: 6 }));
}
let ntli = usdc.units_at(6, Round::Down).and_then(|units| i64::try_from(units).ok());
match ntli {
Some(0) => Err(bad(BadUnits::NotPositive(usdc))),
Some(ntli) => Ok(UpdateIsolatedMargin { asset, position, ntli }),
None => Err(bad(BadUnits::TooLarge(usdc))),
}
}
#[must_use]
pub const fn ntli(&self) -> i64 {
self.ntli
}
}
impl L1Action for UpdateIsolatedMargin {
fn action(&self) -> Map {
Map::new()
.put("type", "updateIsolatedMargin")
.put("asset", self.asset)
.put("isBuy", self.position.is_buy())
.put("ntli", self.ntli)
}
}
pub fn add_margin(asset: Asset, position: Side, usdc: Dec) -> Result<UpdateIsolatedMargin, TradeError> {
match usdc.is_positive() {
true => UpdateIsolatedMargin::new(asset, position, usdc),
false => Err(TradeError::Margin(BadUnits::NotPositive(usdc))),
}
}
pub fn remove_margin(asset: Asset, position: Side, usdc: Dec) -> Result<UpdateIsolatedMargin, TradeError> {
match usdc.is_positive() {
true => UpdateIsolatedMargin::new(asset, position, usdc.negate()),
false => Err(TradeError::Margin(BadUnits::NotPositive(usdc))),
}
}
pub fn margin(market: &Market, position: Dec, mode: MarginMode, usdc: Dec) -> Result<UpdateIsolatedMargin, Refusal> {
if market.is_spot() {
return Err(Refusal::Spot("margin"));
}
if position.is_zero() {
return Err(Refusal::NoPosition);
}
if mode == MarginMode::Cross {
return Err(Refusal::CrossPosition);
}
let side = match position.is_positive() {
true => Side::Buy,
false => Side::Sell,
};
Ok(UpdateIsolatedMargin::new(market.asset(), side, usdc)?)
}
#[cfg(test)]
#[path = "tests/isolated.rs"]
mod tests;