wickra_core/indicators/
estimated_leverage_ratio.rs1use crate::derivatives::DerivativesTick;
4use crate::traits::Indicator;
5
6#[derive(Debug, Clone, Default)]
35pub struct EstimatedLeverageRatio {
36 ready: bool,
37}
38
39impl EstimatedLeverageRatio {
40 #[must_use]
42 pub const fn new() -> Self {
43 Self { ready: false }
44 }
45}
46
47impl Indicator for EstimatedLeverageRatio {
48 type Input = DerivativesTick;
49 type Output = f64;
50
51 fn update(&mut self, tick: DerivativesTick) -> Option<f64> {
52 let base = tick.long_size + tick.short_size;
53 let elr = if base > 0.0 {
54 tick.open_interest / base
55 } else {
56 0.0
57 };
58 self.ready = true;
59 Some(elr)
60 }
61
62 fn reset(&mut self) {
63 self.ready = false;
64 }
65
66 fn warmup_period(&self) -> usize {
67 1
68 }
69
70 fn is_ready(&self) -> bool {
71 self.ready
72 }
73
74 fn name(&self) -> &'static str {
75 "EstimatedLeverageRatio"
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::traits::BatchExt;
83 use approx::assert_relative_eq;
84
85 fn tick(oi: f64, long: f64, short: f64) -> DerivativesTick {
86 DerivativesTick::new_unchecked(
87 0.0, 100.0, 100.0, 100.0, oi, long, short, 0.0, 0.0, 0.0, 0.0, 0,
88 )
89 }
90
91 #[test]
92 fn accessors_and_metadata() {
93 let e = EstimatedLeverageRatio::new();
94 assert_eq!(e.warmup_period(), 1);
95 assert_eq!(e.name(), "EstimatedLeverageRatio");
96 assert!(!e.is_ready());
97 }
98
99 #[test]
100 fn ratio_reference_value() {
101 let mut e = EstimatedLeverageRatio::new();
102 assert_relative_eq!(
104 e.update(tick(1_000.0, 400.0, 600.0)).unwrap(),
105 1.0,
106 epsilon = 1e-12
107 );
108 }
109
110 #[test]
111 fn higher_oi_raises_ratio() {
112 let mut e = EstimatedLeverageRatio::new();
113 let low = e.update(tick(1_000.0, 500.0, 500.0)).unwrap();
114 let high = e.update(tick(3_000.0, 500.0, 500.0)).unwrap();
115 assert!(high > low);
116 }
117
118 #[test]
119 fn zero_base_is_zero() {
120 let mut e = EstimatedLeverageRatio::new();
121 assert_relative_eq!(
122 e.update(tick(1_000.0, 0.0, 0.0)).unwrap(),
123 0.0,
124 epsilon = 1e-12
125 );
126 }
127
128 #[test]
129 fn ready_after_first_update() {
130 let mut e = EstimatedLeverageRatio::new();
131 assert!(!e.is_ready());
132 e.update(tick(1_000.0, 500.0, 500.0));
133 assert!(e.is_ready());
134 }
135
136 #[test]
137 fn reset_clears_state() {
138 let mut e = EstimatedLeverageRatio::new();
139 e.update(tick(1_000.0, 500.0, 500.0));
140 assert!(e.is_ready());
141 e.reset();
142 assert!(!e.is_ready());
143 }
144
145 #[test]
146 fn batch_equals_streaming() {
147 let ticks: Vec<DerivativesTick> = (0..40)
148 .map(|i| tick(1_000.0 + f64::from(i) * 10.0, 500.0, 500.0))
149 .collect();
150 let batch = EstimatedLeverageRatio::new().batch(&ticks);
151 let mut b = EstimatedLeverageRatio::new();
152 let streamed: Vec<_> = ticks.iter().map(|x| b.update(*x)).collect();
153 assert_eq!(batch, streamed);
154 }
155}