quantaxis_rs/indicators/
on_balance_volume.rs1use std::fmt;
2
3use crate::{Close, Next, Reset, Volume};
4
5#[derive(Debug, Clone)]
60pub struct OnBalanceVolume {
61 obv: f64,
62 prev_close: f64,
63}
64
65impl OnBalanceVolume {
66 pub fn new() -> Self {
67 Self {
68 obv: 0.0,
69 prev_close: 0.0,
70 }
71 }
72}
73
74impl<'a, T: Close + Volume> Next<&'a T> for OnBalanceVolume {
75 type Output = f64;
76
77 fn next(&mut self, input: &'a T) -> f64 {
78 if input.close() > self.prev_close {
79 self.obv = self.obv + input.volume();
80 } else if input.close() < self.prev_close {
81 self.obv = self.obv - input.volume();
82 }
83 self.prev_close = input.close();
84 self.obv
85 }
86}
87
88impl Default for OnBalanceVolume {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl fmt::Display for OnBalanceVolume {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 write!(f, "OBV")
97 }
98}
99
100impl Reset for OnBalanceVolume {
101 fn reset(&mut self) {
102 self.obv = 0.0;
103 self.prev_close = 0.0;
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::test_helper::*;
111
112 #[test]
113 fn test_next_bar() {
114 let mut obv = OnBalanceVolume::new();
115
116 let bar1 = Bar::new().close(1.5).volume(1000.0);
117 let bar2 = Bar::new().close(5).volume(5000.0);
118 let bar3 = Bar::new().close(4).volume(9000.0);
119 let bar4 = Bar::new().close(4).volume(4000.0);
120
121 assert_eq!(obv.next(&bar1), 1000.0);
122
123 assert_eq!(obv.next(&bar2), 6000.0);
125
126 assert_eq!(obv.next(&bar3), -3000.0);
128
129 assert_eq!(obv.next(&bar4), -3000.0);
131 }
132
133 #[test]
134 fn test_reset() {
135 let mut obv = OnBalanceVolume::new();
136
137 let bar1 = Bar::new().close(1.5).volume(1000.0);
138 let bar2 = Bar::new().close(4).volume(2000.0);
139 let bar3 = Bar::new().close(8).volume(3000.0);
140
141 assert_eq!(obv.next(&bar1), 1000.0);
142 assert_eq!(obv.next(&bar2), 3000.0);
143 assert_eq!(obv.next(&bar3), 6000.0);
144
145 obv.reset();
146
147 assert_eq!(obv.next(&bar1), 1000.0);
148 assert_eq!(obv.next(&bar2), 3000.0);
149 assert_eq!(obv.next(&bar3), 6000.0);
150 }
151
152 #[test]
153 fn test_default() {
154 OnBalanceVolume::default();
155 }
156
157 #[test]
158 fn test_display() {
159 let obv = OnBalanceVolume::new();
160 assert_eq!(format!("{}", obv), "OBV");
161 }
162
163}