yata/indicators/
ease_of_movement.rs1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use super::HLC;
5use crate::core::{Error, Method, MovingAverageConstructor, PeriodType, Window, OHLCV};
6use crate::core::{IndicatorConfig, IndicatorInstance, IndicatorResult};
7use crate::helpers::MA;
8use crate::methods::Cross;
9
10#[derive(Debug, Clone, Copy)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30pub struct EaseOfMovement<M: MovingAverageConstructor = MA> {
31 pub ma: M,
37 pub period2: PeriodType,
41}
42
43impl<M: MovingAverageConstructor> IndicatorConfig for EaseOfMovement<M> {
44 type Instance = EaseOfMovementInstance<M>;
45
46 const NAME: &'static str = "EaseOfMovement";
47
48 fn init<T: OHLCV>(self, candle: &T) -> Result<Self::Instance, Error> {
49 if !self.validate() {
50 return Err(Error::WrongConfig);
51 }
52
53 let cfg = self;
54 Ok(Self::Instance {
55 m1: cfg.ma.init(0.)?, w: Window::new(cfg.period2, HLC::from(candle)),
57 cross: Cross::new((), &(0.0, 0.0))?,
58
59 cfg,
60 })
61 }
62
63 fn validate(&self) -> bool {
64 self.ma.ma_period() > 1 && self.ma.ma_period() < PeriodType::MAX && self.period2 >= 1
65 }
66
67 fn set(&mut self, name: &str, value: String) -> Result<(), Error> {
68 match name {
69 "ma" => match value.parse() {
70 Err(_) => return Err(Error::ParameterParse(name.to_string(), value.to_string())),
71 Ok(value) => self.ma = value,
72 },
73 "period2" => match value.parse() {
74 Err(_) => return Err(Error::ParameterParse(name.to_string(), value.to_string())),
75 Ok(value) => self.period2 = value,
76 },
77
78 _ => {
79 return Err(Error::ParameterParse(name.to_string(), value));
80 }
81 };
82
83 Ok(())
84 }
85
86 fn size(&self) -> (u8, u8) {
87 (1, 1)
88 }
89}
90
91impl Default for EaseOfMovement<MA> {
92 fn default() -> Self {
93 Self {
94 ma: MA::SMA(13),
95 period2: 1,
96 }
97 }
98}
99
100#[derive(Debug, Clone)]
101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
102pub struct EaseOfMovementInstance<M: MovingAverageConstructor = MA> {
103 cfg: EaseOfMovement<M>,
104
105 m1: M::Instance,
106 w: Window<HLC>,
107 cross: Cross,
108}
109
110impl<M: MovingAverageConstructor> IndicatorInstance for EaseOfMovementInstance<M> {
111 type Config = EaseOfMovement<M>;
112
113 fn config(&self) -> &Self::Config {
114 &self.cfg
115 }
116
117 fn next<T: OHLCV>(&mut self, candle: &T) -> IndicatorResult {
118 let prev_candle = self.w.push(HLC::from(candle));
119
120 let d_high = candle.high() - prev_candle.high();
121 let d_low = candle.low() - prev_candle.low();
122
123 let d = (d_high + d_low) * 0.5;
124
125 let v = if candle.volume() == 0.0 {
126 0.0
127 } else {
128 d * (candle.high() - candle.low()) / candle.volume()
129 };
130
131 debug_assert!(v.is_finite() && !v.is_nan());
132
133 let value = self.m1.next(&v);
134
135 let signal = self.cross.next(&(value, 0.0));
143
144 IndicatorResult::new(&[value], &[signal])
145 }
146}