Skip to main content

apple_quant_algorithmic/volume/
delta.rs

1use std::ops::Add;
2
3use rust_decimal::Decimal;
4
5use crate::instrument::{AsDecimal, InstrumentSpec};
6
7use super::{AggressorSide, DirectionalIntentVolume, DirectionlessVolume, RestingSide};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10pub enum VolumeDelta<IS: InstrumentSpec> {
11	Zero,
12	AggressiveDelta {
13		directionless_volume: DirectionlessVolume<IS>,
14		aggressor_side: AggressorSide,
15	},
16	RestingDelta {
17		directionless_volume: DirectionlessVolume<IS>,
18		resting_side: RestingSide,
19	},
20}
21
22impl<IS: InstrumentSpec> AsDecimal<IS::VolumeSpec> for VolumeDelta<IS> {
23	fn as_decimal(&self) -> Decimal {
24		match self {
25			Self::Zero => Decimal::ZERO,
26			Self::AggressiveDelta {
27				directionless_volume,
28				aggressor_side,
29			} => {
30				directionless_volume.as_decimal()
31					* aggressor_side
32						.as_directional_intent()
33						.as_decimal()
34			}
35			Self::RestingDelta {
36				directionless_volume,
37				resting_side,
38			} => {
39				directionless_volume.as_decimal()
40					* resting_side
41						.as_directional_intent()
42						.as_decimal()
43			}
44		}
45	}
46}
47
48impl<IS: InstrumentSpec> Add for VolumeDelta<IS> {
49	type Output = Option<DirectionalIntentVolume<IS>>;
50
51	fn add(
52		self,
53		rhs: Self,
54	) -> Self::Output {
55		let self_directional_intent_volume: Option<DirectionalIntentVolume<IS>> = match self {
56			Self::Zero => None,
57			Self::AggressiveDelta {
58				directionless_volume,
59				aggressor_side,
60			} => Some(
61				aggressor_side
62					.as_directional_intent()
63					.with_volume(directionless_volume),
64			),
65			Self::RestingDelta {
66				directionless_volume,
67				resting_side,
68			} => Some(
69				resting_side
70					.as_directional_intent()
71					.with_volume(directionless_volume),
72			),
73		};
74
75		let rhs_directional_intent_volume: Option<DirectionalIntentVolume<IS>> = match rhs {
76			Self::Zero => None,
77			Self::AggressiveDelta {
78				directionless_volume: volume_t,
79				aggressor_side,
80			} => Some(
81				aggressor_side
82					.as_directional_intent()
83					.with_volume(volume_t),
84			),
85			Self::RestingDelta {
86				directionless_volume,
87				resting_side,
88			} => Some(
89				resting_side
90					.as_directional_intent()
91					.with_volume(directionless_volume),
92			),
93		};
94
95		match (
96			self_directional_intent_volume,
97			rhs_directional_intent_volume,
98		) {
99			(None, None) => None,
100			(Some(self_directional_intent_volume), None) => Some(self_directional_intent_volume),
101			(None, Some(rhs_directional_intent_volume)) => Some(rhs_directional_intent_volume),
102			(Some(self_directional_intent_volume), Some(rhs_directional_intent_volume)) => {
103				self_directional_intent_volume + rhs_directional_intent_volume
104			}
105		}
106	}
107}