I'm writing a small set of technical-analysis functions and utilising the impl Iterator
feature to avoid having to allocate intermediate vectors if I need to chain these.
However for the macd()
function, to avoid use after move errors I have to clone the iterators. What is the cost of this given the function as a whole is lazy? Will it copy the underlying elements or is this more for clarity rather than anything else.
Any other hints to make this performant always appreciated.
fn sma<'a, I>(mut i: I, period: usize) -> impl Iterator<Item = f32> + Clone + 'a
where
I: Iterator<Item = f32> + Clone + 'a,
{
use std::collections::VecDeque;
let mut v: VecDeque<f32> = i.by_ref().take(period - 1).collect();
let initial = v.iter().sum::<f32>() / period as f32;
v.push_front(0.0);
i.scan(initial, move |state, it| {
let pop = v.pop_front().unwrap();
*state = ((*state) * period as f32 + it - pop) / period as f32;
v.push_back(it);
Some(*state)
})
}
fn macd<'a, I>(mut i: I, slow: usize, fast: usize, signal: usize) -> impl Iterator<Item = (f32, f32, f32)> + 'a
where
I: Iterator<Item = f32> + Clone + 'a,
{
let macd = {
let slow_sma = sma(i.clone(), slow);
let fast_sma = sma(i, fast);
slow_sma.zip(fast_sma).map(|(slow, fast)| slow - fast)
};
let signal_sma = sma(macd.clone(), signal);
let hist = macd.clone().zip(signal_sma.clone()).map(|(macd, signal)| macd - signal);
izip!(macd, signal_sma, hist)
}