sclass ATR extends CandleBasedIndicator { // For first phase settable double sum; settable long steps; // For second phase settable SmoothedMovingAverage sma; // ATR value settable double atr = Double.NaN; // ATR values collected as ticker gettable TickerSequence atrHistory = new TickerSequence("ATR"); Double value() { ret atr(); } // Do we have enough data for a proper value calculation? bool complete() { ret steps >= length(); } { length = 14; onCandleAdded((IVF1) candle -> { var x = candle.move(); var u = max(x, 0.0); var d = neg(min(x, 0.0)); if (!complete()) { upSum += u; downSum += d; } else { if (up == null) { up = new SmoothedMovingAverage(length()); down = new SmoothedMovingAverage(length()); up.add(upSum/steps); down.add(downSum/steps); } else { up().add(u); down().add(d); } var rs = div(up()!, down()!); rsi(100-100/(1+rs)); long time = candle.endTime().toLong(); rsiHistory?.addIfPriceChanged(rsi, time); if (postSmoother == null) postSmoother = new SimpleMovingAverage(smoothingPeriod); postSmoother.add(rsi); rsiSmoothed(postSmoother!); rsiSmoothedHistory?.addIfPriceChanged(rsiSmoothed, time); } ++steps; }); } TickerSequence asTicker(L candles) { feed(candles); ret rsiHistory; } void reset :: after { resetFields(this, "upSum downSum steps up down postSmoother rsi rsiSmoothed rsiHistory rsiSmoothedHistory"); } }