I was trying to use this lib
this lib is cool that can help you to calculate financing indicators, and it used a beautiful way to present the incoming value of an indicator: a Next trait
so after some coding the code looks like
let mut ema5 = EMA::new(5)?;
let mut ema7 = EMA::new(7)?;
let mut ema10 = EMA::new(10)?;
let mut ema14 = EMA::new(14)?;
let mut ema20 = EMA::new(20)?;
let mut ema35 = EMA::new(35)?;
let mut ema60 = EMA::new(60)?;
let mut ema90 = EMA::new(90)?;
let mut ema120 = EMA::new(120)?;
for info in infos {
let dt = DataItem::builder()
.open(info.open)
.high(info.high)
.low(info.low)
.close(info.close)
volume(info.volume)
.build()?
r.ema5 = ema5.next(&dt);
r.ema7 = ema7.next(&dt);
r.ema10 = ema10.next(&dt);
r.ema14 = ema14.next(&dt);
r.ema20 = ema20.next(&dt);
r.ema35 = ema35.next(&dt);
r.ema60 = ema60.next(&dt);
r.ema90 = ema90.next(&dt);
r.ema120 = ema120.next(&dt);
}
ema5.reset();
ema7.reset();
ema10.reset();
ema14.reset();
ema20.reset();
ema35.reset();
ema60.reset();
ema90.reset();
ema120.reset();
a lot of duplicate function calls, so it makes me thinking a way to collect them in a Vector or Map then I can looping those function calls.
first I tried to modify a play ground example to see is storing a trait into a map as value doable, seems OK!
but here comes the hard part, because the Next trait in the TA lib has different output, like EMA returns a single f64 but MACD returns a tuple of three f64...
the error is
E0191: the value of the associated type `Output` (from trait `ta::Next`) must be specified
and since the Output type still cannot specific into multiple types, so the way I did is sperated different return types into different HashMaps, the final code will be like:
trait CalcOp: Next<&'static DataItem> + Reset {}
impl CalcOp for EMA {}
impl CalcOp for SMA {}
impl CalcOp for MACD {}
struct Calc {
ind_f64: HashMap<Indicators, Box<dyn CalcOp<Output = f64>>>,
ind_tripule_f64: HashMap<Indicators, Box<dyn CalcOp<Output = (f64, f64, f64)>>>,
}
impl Calc {
fn new() -> Calc {
let mut c = Calc {
// the num of the Indicator enum
// trying to find a smart way to solve this
ind_f64: HashMap::with_capacity(15),
ind_tripule_f64: HashMap::with_capacity(3),
};
c.ind_f64
.insert(Indicators::EMA5, Box::new(EMA::new(5).unwrap()));
c.ind_tripule_f64
.insert(Indicators::MACD12, Box::new(MACD::new(6, 12, 9).unwrap()));
c
}
fn next(&mut self, dt: &'static DataItem) {
for (_, v) in self.ind_f64.iter_mut() {
v.next();
}
for (_, v) in self.ind_tripule_f64.iter_mut() {
v.next();
}
}
fn reset(&mut self) {
for (_, v) in self.ind_f64.iter_mut() {
v.reset();
}
for (_, v) in self.ind_tripule_f64.iter_mut() {
v.reset();
}
}
}
but there has some problems still remained:
- E0271: type mismatch resolving <ta::indicators::MovingAverageConvergenceDivergence as ta::Next<&'static ta::DataIte m>>::Output == (f64, f64, f64) expected tuple, found struct
good articles that I referenced: