greed 0.5.2

A rust tool to automate trades 📈
Documentation
use num_decimal::num_bigint::BigInt;
use num_decimal::num_rational::BigRational;
use num_decimal::Num;

pub trait NumFromFloat {
    fn from_f64(float: f64) -> Self;
}

pub trait NumFloor {
    fn floor_with(&self, precision: u32) -> Self;
}

#[allow(dead_code)]
pub trait NumAmountRounding {
    fn round_for_notional(&self) -> Self;
    fn round_for_quantity(&self) -> Self;
}

impl NumFromFloat for Num {
    fn from_f64(float: f64) -> Self {
        let rational: BigRational = BigRational::from_float(float).unwrap_or_default();
        let (numer, denom) = rational.into();
        Num::new(numer, denom)
    }
}

impl NumFloor for Num {
    fn floor_with(&self, precision: u32) -> Self {
        let factor = BigInt::from(10).pow(precision);
        let value = self * factor.clone();
        value.trunc() / factor.clone()
    }
}

impl NumAmountRounding for Num {
    fn round_for_notional(&self) -> Self {
        self.floor_with(2)
    }

    fn round_for_quantity(&self) -> Self {
        self.floor_with(7)
    }
}

#[allow(dead_code)]
pub trait NumPercent {
    fn percent_of(&self, percent: f64) -> Self;
    fn percent_above(&self, target: Num) -> Self;

    fn percent_below(&self, target: Num) -> Self;
}

impl NumPercent for Num {
    fn percent_of(&self, percent: f64) -> Self {
        let percent_num = Num::from_f64(percent / 100.0);
        self * percent_num
    }

    fn percent_above(&self, target: Num) -> Self {
        let difference = self - target.clone();
        let percent = difference / target.clone();
        percent * 100
    }

    fn percent_below(&self, target: Num) -> Self {
        let difference = target.clone() - self;
        let percent = difference / target.clone();
        percent * 100
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn from_f64_fraction() {
        let num = Num::from_f64(0.5);
        let expected = Num::new(1, 2);
        assert_eq!(expected, num)
    }

    #[test]
    fn from_f64_whole_number() {
        let num = Num::from_f64(10.0);
        let expected = Num::from(10);
        assert_eq!(expected, num)
    }

    #[test]
    fn from_f64_zero() {
        let num = Num::from_f64(0.0);
        let expected = Num::from(0);
        assert_eq!(expected, num)
    }

    #[test]
    fn floor_with_precision() {
        let num = Num::from_f64(10.129);
        let floored = num.floor_with(2);
        let expected = Num::from_f64(10.12);
        assert_eq!(expected.to_f64(), floored.to_f64())
    }

    #[test]
    fn percent_of_percent_is_fraction() {
        let num = Num::from_f64(10.0);
        let percent = num.percent_of(10.5);
        let expected = Num::from_f64(1.05);
        assert_eq!(expected.to_f64().unwrap(), percent.to_f64().unwrap())
    }

    #[test]
    fn percent_of_num_is_fraction() {
        let num = Num::from_f64(10.50);
        let percent = num.percent_of(50.0);
        let expected = Num::from_f64(5.25);
        assert_eq!(expected.to_f64().unwrap(), percent.to_f64().unwrap())
    }

    #[test]
    fn percent_of_whole_number() {
        let num = Num::from_f64(10.0);
        let percent = num.percent_of(50.0);
        let expected = Num::from_f64(5.0);
        assert_eq!(expected, percent)
    }

    #[test]
    fn percent_above() {
        let num = Num::from_f64(15.0);
        let target = Num::from_f64(10.0);
        let percent = num.percent_above(target);
        let expected = Num::from_f64(50.0);
        assert_eq!(expected, percent)
    }

    #[test]
    fn percent_below() {
        let num = Num::from_f64(5.0);
        let target = Num::from_f64(10.0);
        let percent = num.percent_below(target);
        let expected = Num::from_f64(50.0);
        assert_eq!(expected, percent)
    }
}