quantaxis_rs/indicators/
money_flow_index.rs1use std::collections::VecDeque;
2use std::fmt;
3
4use crate::errors::*;
5use crate::{Close, High, Low, Next, Reset, Volume};
6
7#[derive(Debug, Clone)]
55pub struct MoneyFlowIndex {
56 n: u32,
57 money_flows: VecDeque<f64>,
58 prev_typical_price: f64,
59 total_positive_money_flow: f64,
60 total_absolute_money_flow: f64,
61 is_new: bool,
62}
63
64impl MoneyFlowIndex {
65 pub fn new(n: u32) -> Result<Self> {
66 match n {
67 0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
68 _ => {
69 let indicator = Self {
70 n: n,
71 money_flows: VecDeque::with_capacity(n as usize + 1),
72 prev_typical_price: 0.0,
73 total_positive_money_flow: 0.0,
74 total_absolute_money_flow: 0.0,
75 is_new: true,
76 };
77 Ok(indicator)
78 }
79 }
80 }
81}
82
83impl<'a, T: High + Low + Close + Volume> Next<&'a T> for MoneyFlowIndex {
84 type Output = f64;
85
86 fn next(&mut self, input: &'a T) -> f64 {
87 let typical_price = (input.high() + input.low() + input.close()) / 3.0;
88
89 if self.is_new {
90 self.money_flows.push_back(0.0);
93 self.prev_typical_price = typical_price;
94 self.is_new = false;
95 return 50.0;
96 } else {
97 let money_flow = typical_price * input.volume();
98
99 let signed_money_flow = if typical_price >= self.prev_typical_price {
100 self.total_positive_money_flow += money_flow;
101 money_flow
102 } else {
103 -money_flow
104 };
105
106 self.total_absolute_money_flow += money_flow;
107
108 if self.money_flows.len() == (self.n as usize) {
109 let old_signed_money_flow = self.money_flows.pop_front().unwrap();
110 if old_signed_money_flow > 0.0 {
111 self.total_positive_money_flow -= old_signed_money_flow;
112 self.total_absolute_money_flow -= old_signed_money_flow;
113 } else {
114 self.total_absolute_money_flow += old_signed_money_flow;
116 }
117 }
118
119 self.money_flows.push_back(signed_money_flow);
120 self.prev_typical_price = typical_price;
121
122 (self.total_positive_money_flow / self.total_absolute_money_flow) * 100.0
123 }
124 }
125}
126
127impl Default for MoneyFlowIndex {
128 fn default() -> Self {
129 Self::new(14).unwrap()
130 }
131}
132
133impl fmt::Display for MoneyFlowIndex {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 write!(f, "MFI({})", self.n)
136 }
137}
138
139impl Reset for MoneyFlowIndex {
140 fn reset(&mut self) {
141 self.money_flows.clear();
142 self.prev_typical_price = 0.0;
143 self.total_positive_money_flow = 0.0;
144 self.total_absolute_money_flow = 0.0;
145 self.is_new = true;
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use crate::test_helper::*;
153 macro_rules! test_indicator {
154 ($i:tt) => {
155 #[test]
156 fn test_indicator() {
157 let bar = Bar::new();
158
159 let mut indicator = $i::default();
161
162 let first_output = indicator.next(12.3);
164
165 indicator.next(&bar);
167
168 indicator.reset();
170 assert_eq!(indicator.next(12.3), first_output);
171
172 format!("{}", indicator);
174 }
175 };
176 }
177 #[test]
178 fn test_new() {
179 assert!(MoneyFlowIndex::new(0).is_err());
180 assert!(MoneyFlowIndex::new(1).is_ok());
181 }
182
183 #[test]
184 fn test_next_bar() {
185 let mut mfi = MoneyFlowIndex::new(3).unwrap();
186
187 let bar1 = Bar::new().high(3).low(1).close(2).volume(500.0);
189 assert_eq!(mfi.next(&bar1), 50.0);
190
191 let bar2 = Bar::new().high(2.3).low(2.0).close(2.3).volume(1000.0);
193 assert_eq!(mfi.next(&bar2), 100.0);
194
195 let bar3 = Bar::new().high(9).low(7).close(8).volume(200.0);
197 assert_eq!(mfi.next(&bar3), 100.0);
198
199 let bar4 = Bar::new().high(5).low(3).close(4).volume(500.0);
201 assert_eq!(mfi.next(&bar4), 3800.0 / 5800.0 * 100.0);
202
203 let bar5 = Bar::new().high(4).low(2).close(3).volume(5000.0);
205 assert_eq!(mfi.next(&bar5), 1600.0 / 18600.0 * 100.0);
206
207 let bar6 = Bar::new().high(2).low(1).close(1.5).volume(6000.0);
209 assert_eq!(mfi.next(&bar6), 0.0 / 23800.0 * 100.0);
210
211 let bar7 = Bar::new().high(2).low(2).close(2).volume(7000.0);
213 assert_eq!(mfi.next(&bar7), 14000.0 / 38000.0 * 100.0);
214 }
215
216 #[test]
217 fn test_reset() {
218 let mut mfi = MoneyFlowIndex::new(3).unwrap();
219
220 let bar1 = Bar::new().high(2).low(1).close(1.5).volume(1000.0);
221 let bar2 = Bar::new().high(5).low(3).close(4).volume(2000.0);
222 let bar3 = Bar::new().high(9).low(7).close(8).volume(3000.0);
223 let bar4 = Bar::new().high(5).low(3).close(4).volume(4000.0);
224 let bar5 = Bar::new().high(5).low(3).close(4).volume(5000.0);
225 let bar6 = Bar::new().high(2).low(1).close(1.5).volume(6000.0);
226
227 assert_eq!(mfi.next(&bar1), 50.0);
228 assert_eq!(mfi.next(&bar2), 100.0);
229 assert_eq!(mfi.next(&bar3), 100.0);
230 assert_eq!(round(mfi.next(&bar4)), 66.667);
231 assert_eq!(round(mfi.next(&bar5)), 73.333);
232 assert_eq!(round(mfi.next(&bar6)), 44.444);
233
234 mfi.reset();
235
236 assert_eq!(mfi.next(&bar1), 50.0);
237 assert_eq!(mfi.next(&bar2), 100.0);
238 assert_eq!(mfi.next(&bar3), 100.0);
239 assert_eq!(round(mfi.next(&bar4)), 66.667);
240 assert_eq!(round(mfi.next(&bar5)), 73.333);
241 assert_eq!(round(mfi.next(&bar6)), 44.444);
242 }
243
244 #[test]
245 fn test_default() {
246 MoneyFlowIndex::default();
247 }
248
249 #[test]
250 fn test_display() {
251 let mfi = MoneyFlowIndex::new(10).unwrap();
252 assert_eq!(format!("{}", mfi), "MFI(10)");
253 }
254
255}