use std::{cmp::Ordering, convert::TryFrom, fmt};
use serde::{Deserialize, Serialize, de};
use super::{
SATS_PER_BTC, error::LeverageValidationError, margin::Margin, price::Price, quantity::Quantity,
serde_util,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Leverage(f64);
impl Leverage {
pub const MIN: Self = Self(1.);
pub const MAX: Self = Self(100.);
pub fn bounded<T>(value: T) -> Self
where
T: Into<f64>,
{
let as_f64: f64 = value.into();
let clamped = as_f64.clamp(Self::MIN.0, Self::MAX.0);
Self(clamped)
}
pub fn as_f64(&self) -> f64 {
self.0
}
pub fn try_calculate(
quantity: Quantity,
margin: Margin,
price: Price,
) -> Result<Self, LeverageValidationError> {
let leverage_value = quantity.as_f64() * SATS_PER_BTC / (margin.as_f64() * price.as_f64());
Self::try_from(leverage_value)
}
}
impl From<Leverage> for f64 {
fn from(value: Leverage) -> f64 {
value.0
}
}
impl TryFrom<u8> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<u16> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<u32> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<u64> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<i8> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: i8) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<i16> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: i16) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<i32> for Leverage {
type Error = LeverageValidationError;
fn try_from(leverage: i32) -> Result<Self, Self::Error> {
Self::try_from(leverage as f64)
}
}
impl TryFrom<i64> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<usize> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<isize> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: isize) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<f32> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: f32) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<f64> for Leverage {
type Error = LeverageValidationError;
fn try_from(value: f64) -> Result<Self, Self::Error> {
if value < Self::MIN.0 {
return Err(LeverageValidationError::TooLow { value });
}
if value > Self::MAX.0 {
return Err(LeverageValidationError::TooHigh { value });
}
Ok(Leverage(value))
}
}
impl Eq for Leverage {}
impl Ord for Leverage {
fn cmp(&self, other: &Self) -> Ordering {
self.0
.partial_cmp(&other.0)
.expect("`Leverage` must be finite")
}
}
impl PartialOrd for Leverage {
fn partial_cmp(&self, other: &Leverage) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Display for Leverage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Serialize for Leverage {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_util::float_without_decimal::serialize(&self.0, serializer)
}
}
impl<'de> Deserialize<'de> for Leverage {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let leverage_f64 = f64::deserialize(deserializer)?;
Leverage::try_from(leverage_f64).map_err(|e| de::Error::custom(e.to_string()))
}
}