use crate::markets::perps::meta::PerpAsset;
use crate::trade::error::TradeError;
use crate::trade::margin::tables::{LeverageError, MarginTable, checked_leverage};
use crate::trade::ticket::{Market, Refusal};
use crate::utils::sign::{L1Action, Map};
use crate::utils::{Asset, Dec};
pub use crate::account::holdings::MarginMode;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UpdateLeverage {
asset: Asset,
mode: MarginMode,
leverage: u32,
}
impl UpdateLeverage {
pub fn new(asset: Asset, mode: MarginMode, leverage: u32) -> Result<UpdateLeverage, TradeError> {
match leverage {
0 => Err(TradeError::NoLeverage),
leverage => Ok(UpdateLeverage { asset, mode, leverage }),
}
}
#[must_use]
pub const fn leverage(&self) -> u32 {
self.leverage
}
#[must_use]
pub const fn mode(&self) -> MarginMode {
self.mode
}
}
impl L1Action for UpdateLeverage {
fn action(&self) -> Map {
Map::new()
.put("type", "updateLeverage")
.put("asset", self.asset)
.put("isCross", matches!(self.mode, MarginMode::Cross))
.put("leverage", self.leverage)
}
}
pub fn update_leverage(
asset: Asset,
perp: &PerpAsset,
mode: MarginMode,
leverage: u32,
) -> Result<UpdateLeverage, LeverageError> {
checked_leverage(asset, &perp.name, perp.max_leverage, perp.allows_cross(), mode, leverage)
}
pub fn update_leverage_for(
asset: Asset,
perp: &PerpAsset,
table: &MarginTable,
mode: MarginMode,
leverage: u32,
notional: Dec,
) -> Result<UpdateLeverage, LeverageError> {
let set = update_leverage(asset, perp, mode, leverage)?;
table.check(&perp.name, leverage, notional)?;
Ok(set)
}
pub fn leverage(market: &Market, mode: MarginMode, leverage: u32) -> Result<UpdateLeverage, Refusal> {
let Some(most) = market.max_leverage() else {
return Err(Refusal::Spot("leverage"));
};
checked_leverage(market.asset(), "", most, market.allows_cross(), mode, leverage).map_err(|error| match error {
LeverageError::TooHigh { .. }
| LeverageError::OverTier { .. }
| LeverageError::Trade(TradeError::NoLeverage) => Refusal::Leverage { asked: leverage, most },
LeverageError::NoCross(_) => Refusal::IsolatedOnly,
LeverageError::Trade(error) => Refusal::Trade(error),
})
}
#[cfg(test)]
#[path = "tests/leverage.rs"]
mod tests;