ux_indicators/indicators/
obv.rs1#![allow(dead_code)]
2
3use std::fmt;
4
5use crate::{Close, Next, Reset, Volume};
6
7use crate::{Factory};
8use crate::indicators::SimpleMovingAverage;
9
10pub struct ObvFactory {
11}
12
13impl ObvFactory {
14 pub fn new() -> Self {
15 Self{}
16 }
17}
18
19impl Factory for ObvFactory {
20 fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
21 Box::new(SimpleMovingAverage::default())
22 }
23}
24
25#[derive(Debug, Clone)]
80pub struct OnBalanceVolume {
81 obv: f64,
82 prev_close: f64,
83}
84
85impl OnBalanceVolume {
86 pub fn new() -> Self {
87 Self {
88 obv: 0.0,
89 prev_close: 0.0,
90 }
91 }
92}
93
94impl<'a, T: Close + Volume> Next<&'a T> for OnBalanceVolume {
95 type Output = f64;
96
97 fn next(&mut self, input: &'a T) -> f64 {
98 if input.close() > self.prev_close {
99 self.obv = self.obv + input.volume();
100 } else if input.close() < self.prev_close {
101 self.obv = self.obv - input.volume();
102 }
103 self.prev_close = input.close();
104 self.obv
105 }
106}
107
108impl Default for OnBalanceVolume {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114impl fmt::Display for OnBalanceVolume {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 write!(f, "OBV")
117 }
118}
119
120impl Reset for OnBalanceVolume {
121 fn reset(&mut self) {
122 self.obv = 0.0;
123 self.prev_close = 0.0;
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::test_helper::*;
131
132 #[test]
133 fn test_next_bar() {
134 let mut obv = OnBalanceVolume::new();
135
136 let bar1 = Bar::new().close(1.5).volume(1000.0);
137 let bar2 = Bar::new().close(5).volume(5000.0);
138 let bar3 = Bar::new().close(4).volume(9000.0);
139 let bar4 = Bar::new().close(4).volume(4000.0);
140
141 assert_eq!(obv.next(&bar1), 1000.0);
142
143 assert_eq!(obv.next(&bar2), 6000.0);
145
146 assert_eq!(obv.next(&bar3), -3000.0);
148
149 assert_eq!(obv.next(&bar4), -3000.0);
151 }
152
153 #[test]
154 fn test_reset() {
155 let mut obv = OnBalanceVolume::new();
156
157 let bar1 = Bar::new().close(1.5).volume(1000.0);
158 let bar2 = Bar::new().close(4).volume(2000.0);
159 let bar3 = Bar::new().close(8).volume(3000.0);
160
161 assert_eq!(obv.next(&bar1), 1000.0);
162 assert_eq!(obv.next(&bar2), 3000.0);
163 assert_eq!(obv.next(&bar3), 6000.0);
164
165 obv.reset();
166
167 assert_eq!(obv.next(&bar1), 1000.0);
168 assert_eq!(obv.next(&bar2), 3000.0);
169 assert_eq!(obv.next(&bar3), 6000.0);
170 }
171
172 #[test]
173 fn test_default() {
174 OnBalanceVolume::default();
175 }
176
177 #[test]
178 fn test_display() {
179 let obv = OnBalanceVolume::new();
180 assert_eq!(format!("{}", obv), "OBV");
181 }
182
183}