sclass LiveBollingerBands { replace Candle with TradingCandle. // The magic average + standard deviation generator new Welford welford; // Length of the moving average in candles settable int length = 20; // Bollinger length (how many candles to look at) // Probably wrong word. Defines how many times the standard deviation // we use as the tunnel size (well, twice that, actually) settable double deviation = 2; // result settable DoubleRange range; simplyCached CircularFifoBuffer candles() { ret new CircularFifoBuffer(length); } gettable AverageAndStandardDeviation as; Candle lastCandle() { ret candles().last(); } void feed(TradingCandleMaker candleMaker) { if (candleMaker != null) for (candle : candleMaker.candles()) add(candle); } void add(TradingCandle candle) { if (candle.ongoing()) ret; if (lastCandle() != null && lessOrEq(candle.startTime, lastCandle().startTime)) ret; candles().removeToSize(length-1); candles().add(candle); if (l(candles()) >= length) { var bCandles = candles().asList(); var prices = mapToDoubleArray(bCandles, ->.endPrice()); as = averageAndStandardDeviation(prices); range = bollingerRange(as, deviation); } } }