How to limit the input when using next iterator?

Viewed 112

I'm calculation the Exponential Moving Average using the ta library. Currently, I add each close value with the next iterator. What I want to do is limit the input of the ema to 201 values (the output is different when you calculate the ema200 on 201 input values or on for example 500 input values). Is this possible in any way?

use ta::indicators::ExponentialMovingAverage as EMA;
use ta::Next;

pub fn main() {
    let mut reader = csv::Reader::from_path("datafile.csv").unwrap();

    let mut ema = EMA::new(200).unwrap();
    
    for record in reader.deserialize() {
        let (timestamp, open, high, low, close, volume): (String, f64, f64, f64, f64, f64) = record.unwrap();

        let ema_val = ema.next(close);

        println!("{} - ema: {}", timestamp, ema_val);
    }
}

My data file looks something likes this:

timestamp,open,high,low,close,volume
2017-01-03,757.919983,758.760010,747.700012,753.669983,3521100
2017-01-04,758.390015,759.679993,754.200012,757.179993,2510500
2017-01-05,761.549988,782.400024,760.260010,780.450012,5830100
2017-01-06,782.359985,799.440002,778.479980,795.989990,5986200
2017-01-09,798.000000,801.770020,791.770020,796.919983,3440100
2017-01-10,796.599976,798.000000,789.539978,795.900024,2558400
2017-01-11,793.659973,799.500000,789.510010,799.020020,2992800
2017-01-12,800.309998,814.130005,799.500000,813.640015,4873900
2017-01-13,814.320007,821.650024,811.400024,817.140015,3791900
2017-01-17,815.700012,816.000000,803.440002,809.719971,3659400
2017-01-18,809.500000,811.729980,804.270020,807.479980,2354200
2017-01-19,810.000000,813.510010,807.320007,809.039978,2540800
2017-01-20,815.280029,816.020020,806.260010,808.330017,3376200
2017-01-23,806.799988,818.500000,805.080017,817.880005,2797500
2017-01-24,822.000000,823.989990,814.500000,822.440002,2971700
2017-01-25,825.789978,837.419983,825.289978,836.520020,3922600
2017-01-26,835.530029,843.840027,833.000000,839.150024,3586300
2017-01-27,839.000000,839.700012,829.440002,835.770020,2998700
2017-01-30,833.000000,833.500000,816.380005,830.380005,3747300
2017-01-31,823.750000,826.989990,819.559998,823.479980,3137200
1 Answers

Well the whole point of an EMA is that the weights of older input values never reach exactly 0, but just decrease exponentially. The way it's defined and implemented makes the update very efficient, because calling next on the EMA object really just involves updating one single value.

If I understand correctly what you want to do, it is to compute an EMA which includes a hard weight cut-off at 200 time steps.

So what you want is not really an exponential moving average, but rather a moving average with exponentially decaying weights. There's a subtle difference, because with that requirement, you'd now have to keep track of all the preceding 200 weights.

I don't see a simple way to hack that into the EMA struct of that ta crate, so you'd have to roll your own indicator. For that, I suggest checking out the source code, not for the exponential moving average, but for the simple moving average, because that one shows how you keep track of the weights already seen: https://docs.rs/ta/0.5.0/src/ta/indicators/simple_moving_average.rs.html#44-50

Then you just have to figure out how to compute the weights correctly and do the update.

But alternatively, you can just stop and think why you want to add such a "windowing" to your EMA.

Related