apple_quant_algorithmic/volume/
directionless.rs1use std::ops::{Add, AddAssign, Sub};
2
3use bevy::prelude::Deref;
4use num_traits::{Signed, Zero};
5use rust_decimal::Decimal;
6use thiserror::Error;
7
8use crate::instrument::{AsDecimal, InstrumentSpec};
9
10#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct DirectionlessVolume<IS: InstrumentSpec>(IS::VolumeType);
12
13impl<IS: InstrumentSpec> DirectionlessVolume<IS> {
14 pub fn new_unchecked(volume: IS::VolumeType) -> Self {
15 Self(volume)
16 }
17
18 pub fn new_checked(volume: IS::VolumeType) -> Result<Self, ()> {
19 if volume.is_negative() || volume.is_zero() {
20 return Err(());
21 }
22
23 Ok(Self(volume))
24 }
25}
26
27impl<IS: InstrumentSpec> Add for DirectionlessVolume<IS> {
28 type Output = Self;
29
30 fn add(
31 self,
32 rhs: Self,
33 ) -> Self::Output {
34 Self(self.0 + rhs.0)
35 }
36}
37
38impl<IS: InstrumentSpec> Add for &DirectionlessVolume<IS> {
39 type Output = DirectionlessVolume<IS>;
40
41 fn add(
42 self,
43 rhs: Self,
44 ) -> Self::Output {
45 DirectionlessVolume::<IS>(self.0 + rhs.0)
46 }
47}
48
49impl<IS: InstrumentSpec> AddAssign for DirectionlessVolume<IS> {
50 fn add_assign(
51 &mut self,
52 rhs: Self,
53 ) {
54 self.0 += rhs.0;
55 }
56}
57
58#[derive(Debug, Error)]
59pub enum DirectionlessVolumeSubError {
60 #[error("Can not have negative directionless volume. Attemped to subtract: {lhs} - {rhs}.")]
61 NegativeVolume { lhs: Decimal, rhs: Decimal },
62}
63
64impl<IS: InstrumentSpec> Sub for DirectionlessVolume<IS> {
65 type Output = Result<Option<Self>, DirectionlessVolumeSubError>;
66
67 fn sub(
68 self,
69 rhs: Self,
70 ) -> Self::Output {
71 if self.0 == rhs.0 {
72 return Ok(None);
73 }
74
75 if self.0 < rhs.0 {
76 return Err(
77 DirectionlessVolumeSubError::NegativeVolume {
78 lhs: self.as_decimal(),
79 rhs: rhs.as_decimal(),
80 },
81 );
82 }
83
84 Ok(Some(Self(self.0 - rhs.0)))
85 }
86}