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