ux_indicators/indicators/
mfi.rs1#![allow(dead_code)]
2
3use std::collections::VecDeque;
4use std::fmt;
5
6use crate::errors::*;
7use crate::{Close, High, Low, Next, Reset, Volume};
8
9use crate::{Factory};
10use crate::indicators::SimpleMovingAverage;
11
12pub struct MfiFactory {
13}
14
15impl MfiFactory {
16 pub fn new() -> Self {
17 Self{}
18 }
19}
20
21impl Factory for MfiFactory {
22 fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
23 Box::new(SimpleMovingAverage::default())
24 }
25}
26
27#[derive(Debug, Clone)]
75pub struct MoneyFlowIndex {
76 n: u32,
77 money_flows: VecDeque<f64>,
78 prev_typical_price: f64,
79 total_positive_money_flow: f64,
80 total_absolute_money_flow: f64,
81 is_new: bool,
82}
83
84impl MoneyFlowIndex {
85 pub fn new(n: u32) -> Result<Self> {
86 match n {
87 0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
88 _ => {
89 let indicator = Self {
90 n: n,
91 money_flows: VecDeque::with_capacity(n as usize + 1),
92 prev_typical_price: 0.0,
93 total_positive_money_flow: 0.0,
94 total_absolute_money_flow: 0.0,
95 is_new: true,
96 };
97 Ok(indicator)
98 }
99 }
100 }
101}
102
103impl<'a, T: High + Low + Close + Volume> Next<&'a T> for MoneyFlowIndex {
104 type Output = f64;
105
106 fn next(&mut self, input: &'a T) -> f64 {
107 let typical_price = (input.high() + input.low() + input.close()) / 3.0;
108
109 if self.is_new {
110 self.money_flows.push_back(0.0);
113 self.prev_typical_price = typical_price;
114 self.is_new = false;
115 return 50.0;
116 } else {
117 let money_flow = typical_price * input.volume();
118
119 let signed_money_flow = if typical_price >= self.prev_typical_price {
120 self.total_positive_money_flow += money_flow;
121 money_flow
122 } else {
123 -money_flow
124 };
125
126 self.total_absolute_money_flow += money_flow;
127
128 if self.money_flows.len() == (self.n as usize) {
129 let old_signed_money_flow = self.money_flows.pop_front().unwrap();
130 if old_signed_money_flow > 0.0 {
131 self.total_positive_money_flow -= old_signed_money_flow;
132 self.total_absolute_money_flow -= old_signed_money_flow;
133 } else {
134 self.total_absolute_money_flow += old_signed_money_flow;
136 }
137 }
138
139 self.money_flows.push_back(signed_money_flow);
140 self.prev_typical_price = typical_price;
141
142 (self.total_positive_money_flow / self.total_absolute_money_flow) * 100.0
143 }
144 }
145}
146
147impl Default for MoneyFlowIndex {
148 fn default() -> Self {
149 Self::new(14).unwrap()
150 }
151}
152
153impl fmt::Display for MoneyFlowIndex {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 write!(f, "MFI({})", self.n)
156 }
157}
158
159impl Reset for MoneyFlowIndex {
160 fn reset(&mut self) {
161 self.money_flows.clear();
162 self.prev_typical_price = 0.0;
163 self.total_positive_money_flow = 0.0;
164 self.total_absolute_money_flow = 0.0;
165 self.is_new = true;
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172 use crate::test_helper::*;
173
174 #[test]
175 fn test_new() {
176 assert!(MoneyFlowIndex::new(0).is_err());
177 assert!(MoneyFlowIndex::new(1).is_ok());
178 }
179
180 #[test]
181 fn test_next_bar() {
182 let mut mfi = MoneyFlowIndex::new(3).unwrap();
183
184 let bar1 = Bar::new().high(3).low(1).close(2).volume(500.0);
186 assert_eq!(mfi.next(&bar1), 50.0);
187
188 let bar2 = Bar::new().high(2.3).low(2.0).close(2.3).volume(1000.0);
190 assert_eq!(mfi.next(&bar2), 100.0);
191
192 let bar3 = Bar::new().high(9).low(7).close(8).volume(200.0);
194 assert_eq!(mfi.next(&bar3), 100.0);
195
196 let bar4 = Bar::new().high(5).low(3).close(4).volume(500.0);
198 assert_eq!(mfi.next(&bar4), 3800.0 / 5800.0 * 100.0);
199
200 let bar5 = Bar::new().high(4).low(2).close(3).volume(5000.0);
202 assert_eq!(mfi.next(&bar5), 1600.0 / 18600.0 * 100.0);
203
204 let bar6 = Bar::new().high(2).low(1).close(1.5).volume(6000.0);
206 assert_eq!(mfi.next(&bar6), 0.0 / 23800.0 * 100.0);
207
208 let bar7 = Bar::new().high(2).low(2).close(2).volume(7000.0);
210 assert_eq!(mfi.next(&bar7), 14000.0 / 38000.0 * 100.0);
211 }
212
213 #[test]
214 fn test_reset() {
215 let mut mfi = MoneyFlowIndex::new(3).unwrap();
216
217 let bar1 = Bar::new().high(2).low(1).close(1.5).volume(1000.0);
218 let bar2 = Bar::new().high(5).low(3).close(4).volume(2000.0);
219 let bar3 = Bar::new().high(9).low(7).close(8).volume(3000.0);
220 let bar4 = Bar::new().high(5).low(3).close(4).volume(4000.0);
221 let bar5 = Bar::new().high(5).low(3).close(4).volume(5000.0);
222 let bar6 = Bar::new().high(2).low(1).close(1.5).volume(6000.0);
223
224 assert_eq!(mfi.next(&bar1), 50.0);
225 assert_eq!(mfi.next(&bar2), 100.0);
226 assert_eq!(mfi.next(&bar3), 100.0);
227 assert_eq!(round(mfi.next(&bar4)), 66.667);
228 assert_eq!(round(mfi.next(&bar5)), 73.333);
229 assert_eq!(round(mfi.next(&bar6)), 44.444);
230
231 mfi.reset();
232
233 assert_eq!(mfi.next(&bar1), 50.0);
234 assert_eq!(mfi.next(&bar2), 100.0);
235 assert_eq!(mfi.next(&bar3), 100.0);
236 assert_eq!(round(mfi.next(&bar4)), 66.667);
237 assert_eq!(round(mfi.next(&bar5)), 73.333);
238 assert_eq!(round(mfi.next(&bar6)), 44.444);
239 }
240
241 #[test]
242 fn test_default() {
243 MoneyFlowIndex::default();
244 }
245
246 #[test]
247 fn test_display() {
248 let mfi = MoneyFlowIndex::new(10).unwrap();
249 assert_eq!(format!("{}", mfi), "MFI(10)");
250 }
251
252}