wickra_core/indicators/
funding_rate.rs1use crate::derivatives::DerivativesTick;
4use crate::traits::Indicator;
5
6#[derive(Debug, Clone, Default)]
35pub struct FundingRate {
36 has_emitted: bool,
37}
38
39impl FundingRate {
40 #[must_use]
42 pub const fn new() -> Self {
43 Self { has_emitted: false }
44 }
45}
46
47impl Indicator for FundingRate {
48 type Input = DerivativesTick;
49 type Output = f64;
50
51 #[inline]
52 fn update(&mut self, tick: DerivativesTick) -> Option<f64> {
53 self.has_emitted = true;
54 Some(tick.funding_rate)
55 }
56
57 fn reset(&mut self) {
58 self.has_emitted = false;
59 }
60
61 #[inline]
62 fn warmup_period(&self) -> usize {
63 1
64 }
65
66 #[inline]
67 fn is_ready(&self) -> bool {
68 self.has_emitted
69 }
70
71 #[inline]
72 fn name(&self) -> &'static str {
73 "FundingRate"
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::traits::BatchExt;
81
82 fn tick(funding_rate: f64) -> DerivativesTick {
83 DerivativesTick::new_unchecked(
84 funding_rate,
85 100.0,
86 100.0,
87 100.0,
88 0.0,
89 0.0,
90 0.0,
91 0.0,
92 0.0,
93 0.0,
94 0.0,
95 0,
96 )
97 }
98
99 #[test]
100 fn accessors_and_metadata() {
101 let fr = FundingRate::new();
102 assert_eq!(fr.name(), "FundingRate");
103 assert_eq!(fr.warmup_period(), 1);
104 assert!(!fr.is_ready());
105 }
106
107 #[test]
108 fn passes_through_funding_rate() {
109 let mut fr = FundingRate::new();
110 assert_eq!(fr.update(tick(0.0001)), Some(0.0001));
111 assert_eq!(fr.update(tick(-0.0003)), Some(-0.0003));
112 assert!(fr.is_ready());
113 }
114
115 #[test]
116 fn batch_equals_streaming() {
117 let ticks: Vec<DerivativesTick> =
118 (0..20).map(|i| tick(0.0001 * f64::from(i - 10))).collect();
119 let mut a = FundingRate::new();
120 let mut b = FundingRate::new();
121 assert_eq!(
122 a.batch(&ticks),
123 ticks.iter().map(|x| b.update(*x)).collect::<Vec<_>>()
124 );
125 }
126
127 #[test]
128 fn reset_clears_state() {
129 let mut fr = FundingRate::new();
130 fr.update(tick(0.0001));
131 assert!(fr.is_ready());
132 fr.reset();
133 assert!(!fr.is_ready());
134 }
135}