trading_types/
amount.rs

1use core::ops;
2use std::cmp::{Eq, PartialEq, PartialOrd};
3// use std::cmp::{Ord, Ordering};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{Price, Worth};
8
9// Why not Qty as more "loud" maybe? To separate "qty" and "quote".
10// So, Amount
11/// Amount (quantity) of base currency.
12#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialOrd, PartialEq)]
13pub struct Amount(pub f64);
14
15impl Eq for Amount {}
16
17impl From<(Price, Worth)> for Amount {
18    fn from((p, w): (Price, Worth)) -> Self {
19        Self::from_pw(p, w)
20    }
21}
22
23impl Amount {
24    pub fn from_pw(p: Price, w: Worth) -> Self {
25        Self(w.0 / p.0)
26    }
27}
28
29impl ops::Sub<Amount> for Amount {
30    type Output = Self;
31    fn sub(self, rhs: Amount) -> Self {
32        Self(self.0 - rhs.0)
33    }
34}
35
36impl ops::Add<Amount> for Amount {
37    type Output = Self;
38    fn add(self, rhs: Amount) -> Self {
39        Self(self.0 + rhs.0)
40    }
41}
42
43impl ops::AddAssign<Amount> for Amount {
44    fn add_assign(&mut self, rhs: Amount) {
45        self.0 += rhs.0;
46    }
47}
48
49impl ops::SubAssign<Amount> for Amount {
50    fn sub_assign(&mut self, rhs: Amount) {
51        self.0 -= rhs.0;
52    }
53}
54
55impl ops::Mul<f64> for Amount {
56    type Output = Self;
57    fn mul(self, rhs: f64) -> Self {
58        Self(self.0 * rhs)
59    }
60}
61
62impl ops::Div<f64> for Amount {
63    type Output = Self;
64    fn div(self, rhs: f64) -> Self {
65        Self(self.0 / rhs)
66    }
67}
68
69impl ops::Div<Amount> for f64 {
70    type Output = Amount;
71    fn div(self, rhs: Amount) -> Amount {
72        Amount(self / rhs.0)
73    }
74}
75
76impl ops::Div<Amount> for Amount {
77    type Output = f64;
78    fn div(self, rhs: Amount) -> f64 {
79        self.0 / rhs.0
80    }
81}
82
83// for min, max
84// https://www.reddit.com/r/rust/comments/29kia3/no_ord_for_f32/
85// impl Ord for Amount {
86//     fn cmp(&self, rhs: &Self) -> Ordering {
87//         self.0.partial_cmp(&rhs.0).unwrap_or(Ordering::Equal)
88//     }
89// }
90
91#[cfg(test)]
92mod tests {
93    use serde_json::json;
94
95    use super::*;
96
97    #[test]
98    fn test_amount_to_json() {
99        // https://serde.rs/derive.html
100        let a = Amount(1.0);
101        let v = json!(a);
102        assert_eq!(v, 1.0);
103    }
104
105    #[test]
106    fn test_json_to_amount() {
107        let a: Amount = serde_json::from_str(r#"1.0"#).unwrap();
108        assert_eq!(a, Amount(1.0));
109    }
110
111    #[test]
112    fn test_f64_div_amount() {
113        let a = Amount(10.);
114        let actual = 1. / a;
115        assert_eq!(Amount(0.1), actual)
116    }
117}