I'm trying to understand how the DecayedValue can be used as moving average. According to the wiki, and some comments in the source, this should be possible. I must not be using correctly though, because I am getting numbers that I can't make sense of. What I thought you would do is
I seem to be missing something though, because the numbers I am getting for the initail intermediate resulsts are really, really low. Why would the numbers be so low at the beginning of the series, for so long? I'm getting numbers in the 50s and 60s initially...
See below for example program + output.
Advice appreciated! Hope to funnel this back into the docs. Thanks!
/ Generate the list of cumulative sums using the implicit monoid
def cumulativeSum[T : Monoid](list: List[T]) = {
list.tail.scanLeft(list.head)(_ + _)
}
// S&P 500 closing prices for April 2014
val raw = List(
99.74, 100.25, 99.81, 96.61, 95.09, 95.96, 98.42, 96.28,
96.2, 96.49, 97.36, 99.74, 99.94, 99.39, 99.8, 102.31,
101.1, 99.17, 97.81, 98.85, 101.84
)
val days = 5 // window for moving average/decayed value
val warmup = Seq.fill(days - 1)(Double.NaN) // no moving avgs until n days
val simpleAverages = raw.map(AveragedValue(_))
// a simple, cumulative average using the AveragedValue monoid
val simpleAvgs = cumulativeSum(simpleAverages).map(_.value)
// Moving average requires keeping O(N) memory
val moving5DayAvgs = warmup ++ simpleAverages.sliding(days, 1).map{ (window) =>
window.monoidSum.value
}
// DecayedValue can represent a moving average with O(1) memory
implicit val monoid = (DecayedValue.monoidWithEpsilon(0.99))
val decayedValues = raw.zipWithIndex.map { case (value, atTime) =>
DecayedValue.build(value, atTime, days)
}
val decayedValueAvgs = warmup ++ cumulativeSum(decayedValues).drop(days - 1).map(_.average(days))
Here's the output (notice how Decayed is well below the other averages for most of the series)