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