apple_quant_algorithmic/volume/
directional_intent_volume.rs1use std::borrow::Borrow;
2use std::cmp;
3
4use apple_quant_core::{
5 log::error, AddChecked, AddReleaseUnchecked, AddUnchecked, SubChecked,
6 SubReleaseUnchecked, SubUnchecked,
7};
8
9use num_traits::{Signed, Zero};
10
11use crate::{
12 instrument::{AsDecimal, InstrumentSpec},
13 points::{Subpoints, WholePoints},
14};
15
16use super::{
17 AggressiveVolume, DirectionalIntent, DirectionlessVolume, FromVolumeType,
18 FromVolumeTypeError, RestingVolume, VolumeConstruct, ZeroableVolume,
19};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub struct DirectionalIntentVolume<IS: InstrumentSpec> {
23 pub directional_intent: DirectionalIntent,
24 pub directionless_volume: DirectionlessVolume<IS>,
25}
26
27impl<IS: InstrumentSpec> DirectionalIntentVolume<IS> {
28 pub fn from_volume_type_positive_unchecked(
29 volume_type: IS::VolumeType,
30 ) -> Self {
31 debug_assert!(volume_type.is_positive() || volume_type.is_zero());
32
33 Self {
34 directional_intent: DirectionalIntent::Positive,
35 directionless_volume: DirectionlessVolume::<IS>::new_unchecked(volume_type),
36 }
37 }
38
39 pub fn from_volume_type_negative_unchecked(
40 volume_type: IS::VolumeType,
41 ) -> Self {
42 debug_assert!(volume_type.is_positive() || volume_type.is_zero());
43
44 Self {
45 directional_intent: DirectionalIntent::Negative,
46 directionless_volume: DirectionlessVolume::<IS>::new_unchecked(volume_type),
47 }
48 }
49
50 pub fn as_flipped(
51 &self,
52 ) -> Self {
53 Self {
54 directional_intent: self.directional_intent.as_flipped(),
55 directionless_volume: self.directionless_volume,
56 }
57 }
58
59 pub fn as_volume_type_signed(
60 &self,
61 ) -> IS::VolumeType {
62 let volume_type = self.directionless_volume.as_volume_type();
63 debug_assert!(volume_type.is_positive() || volume_type.is_zero());
64
65 if self.directional_intent.is_positive() {
66 return volume_type;
67 } else {
68 return -volume_type;
69 }
70 }
71}
72
73impl<IS: InstrumentSpec> VolumeConstruct<
74 (
75 DirectionalIntent,
76 DirectionlessVolume<IS>,
77 ),
78 (),
79> for DirectionalIntentVolume<IS> {
80 fn new_checked(
81 t: impl Into<(
82 DirectionalIntent,
83 DirectionlessVolume<IS>,
84 )>,
85 ) -> Result<Self, ()>
86 where
87 Self: Sized,
88 {
89 Ok(Self::new_unchecked(t))
90 }
91
92 fn new_unchecked(
93 t: impl Into<(
94 DirectionalIntent,
95 DirectionlessVolume<IS>,
96 )>,
97 ) -> Self {
98 let (
99 directional_intent,
100 directionless_volume,
101 ) = t.into();
102
103 Self {
104 directional_intent,
105 directionless_volume,
106 }
107 }
108}
109
110impl<IS: InstrumentSpec> FromVolumeType<IS> for DirectionalIntentVolume<IS> {
111 fn from_volume_type_checked(
112 volume_type: impl Into<IS::VolumeType>,
113 ) -> Result<Self, FromVolumeTypeError>
114 where
115 Self: Sized,
116 {
117 let volume_type = volume_type.into();
118
119 if volume_type.is_zero() {
120 return Err(FromVolumeTypeError::new(volume_type.as_decimal()));
121 }
122
123 Ok(Self::from_volume_type_unchecked(volume_type))
124 }
125
126 fn from_volume_type_unchecked(
127 volume_type: impl Into<IS::VolumeType>,
128 ) -> Self {
129 let volume_type = volume_type.into();
130
131 if volume_type.is_positive() {
132 return Self::from_volume_type_positive_unchecked(volume_type);
133 }
134
135 Self::from_volume_type_negative_unchecked(volume_type.abs())
136 }
137}
138
139impl<IS: InstrumentSpec> ZeroableVolume for DirectionalIntentVolume<IS> {
140 const ZERO: Self = DirectionalIntentVolume {
141 directional_intent: DirectionalIntent::Positive,
142 directionless_volume: DirectionlessVolume::ZERO,
143 };
144
145 fn is_zero(
146 &self,
147 ) -> bool {
148 self.directionless_volume == DirectionlessVolume::ZERO
149 }
150}
151
152impl<IS: InstrumentSpec> From<AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
153 fn from(
154 value: AggressiveVolume<IS>,
155 ) -> Self {
156 let directional_intent = value.as_aggressor_side().into();
157 let directionless_volume = value.into_directionless_volume();
158
159 Self {
160 directional_intent,
161 directionless_volume,
162 }
163 }
164}
165
166impl<IS: InstrumentSpec> From<&AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
167 fn from(
168 value: &AggressiveVolume<IS>,
169 ) -> Self {
170 Self::from(*value)
171 }
172}
173
174impl<IS: InstrumentSpec> From<RestingVolume<IS>> for DirectionalIntentVolume<IS> {
175 fn from(
176 value: RestingVolume<IS>,
177 ) -> Self {
178 let directional_intent = value.as_resting_side().into();
179 let directionless_volume = value.into_directionless_volume();
180
181 Self {
182 directional_intent,
183 directionless_volume,
184 }
185 }
186}
187
188impl<IS: InstrumentSpec> From<&RestingVolume<IS>> for DirectionalIntentVolume<IS> {
189 fn from(
190 value: &RestingVolume<IS>,
191 ) -> Self {
192 Self::from(*value)
193 }
194}
195
196impl<IS: InstrumentSpec> PartialOrd for DirectionalIntentVolume<IS> {
197 fn partial_cmp(
198 &self,
199 other: &Self,
200 ) -> Option<cmp::Ordering> {
201 Some(self.cmp(other))
202 }
203}
204
205impl<IS: InstrumentSpec> Ord for DirectionalIntentVolume<IS> {
206 fn cmp(
207 &self,
208 other: &Self,
209 ) -> cmp::Ordering {
210 let lhs = self.as_volume_type_signed();
211 let rhs = other.as_volume_type_signed();
212
213 lhs.cmp(&rhs)
214 }
215}
216
217impl<IS: InstrumentSpec> From<WholePoints> for DirectionalIntentVolume<IS> {
218 fn from(
219 value: WholePoints,
220 ) -> Self {
221 match Self::from_volume_type_unchecked_release(
222 value.into_subpoints::<IS::VolumeSpec>(),
223 ) {
224 Ok(
225 directional_intent_volume,
226 ) => directional_intent_volume,
227 Err(e) => {
228 error!("{e}");
229 panic!();
230 },
231 }
232 }
233}
234
235impl<IS: InstrumentSpec> From<&WholePoints> for DirectionalIntentVolume<IS> {
236 fn from(
237 value: &WholePoints,
238 ) -> Self {
239 (*value).into()
240 }
241}
242
243impl<IS: InstrumentSpec> From<Subpoints> for DirectionalIntentVolume<IS> {
244 fn from(
245 value: Subpoints,
246 ) -> Self {
247 match Self::from_volume_type_unchecked_release(value) {
248 Ok(
249 directional_intent_volume,
250 ) => directional_intent_volume,
251 Err(e) => {
252 error!("{e}");
253 panic!();
254 },
255 }
256 }
257}
258
259impl<IS: InstrumentSpec> From<&Subpoints> for DirectionalIntentVolume<IS> {
260 fn from(
261 value: &Subpoints,
262 ) -> Self {
263 (*value).into()
264 }
265}
266
267impl<IS: InstrumentSpec> From<DirectionalIntentVolume<IS>> for Result<
268 DirectionalIntentVolume<IS>,
269 FromVolumeTypeError,
270> {
271 fn from(
272 value: DirectionalIntentVolume<IS>,
273 ) -> Self {
274 Ok(value)
275 }
276}
277
278impl_volume_binop!(
279 DirectionalIntentVolume,
280 AddReleaseUnchecked,
281 AddChecked,
282 add_checked,
283 AddUnchecked,
284 add_unchecked,
285 |lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
286 lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
287 lhs + rhs; DirectionalIntentVolume::<IS>::from_volume_type_checked(volume_type) },
288 |lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
289 lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
290 lhs + rhs; DirectionalIntentVolume::<IS>::from_volume_type_unchecked(volume_type) },
291 FromVolumeTypeError,
292 IS,
293 InstrumentSpec
294);
295
296impl_volume_binop!(
297 DirectionalIntentVolume,
298 SubReleaseUnchecked,
299 SubChecked,
300 sub_checked,
301 SubUnchecked,
302 sub_unchecked,
303 |lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
304 lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
305 lhs - rhs; DirectionalIntentVolume::<IS>::from_volume_type_checked(volume_type) },
306 |lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
307 lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
308 lhs - rhs; DirectionalIntentVolume::<IS>::from_volume_type_unchecked(volume_type) },
309 FromVolumeTypeError,
310 IS,
311 InstrumentSpec
312);