persistable sclass ADX extends CandleBasedIndicator { // For first phase new Average initialAverage; // For second phase settable SmoothedMovingAverage sma; settable double upMove = Double.NaN; settable double downMove = Double.NaN; settable double plusDM = Double.NaN; settable double minusDM = Double.NaN; // ATR value settable double atr = Double.NaN; // ATR values collected as ticker gettable TickerSequence atrHistory = new TickerSequence("ATR"); Double value() { ret atr(); } *(int *length) {} { length = 14; onCandleAdded((IVF1) candle -> { if (candles().size() < 2) ret; var today = candle; var yesterday = candles().nextToLast(); upMove(today.high()-yesterday.high()); downMove(yesterday.low()-today.low()); plusDM(upMove > downMove && upMove > 0 ? upMove : 0); minusDM(downMove > upMove && downMove > 0 ? downMove : 0); tr(trueRange(ll(candles().nextToLast(), candles().last()))); if (initialAverage.count() < length()) ret with initialAverage.add(tr); if (sma == null) { sma(new SmoothedMovingAverage(length())); sma().add(initialAverage!); } else sma().add(tr); atr(sma()!); long time = candle.endTime().toLong(); atrHistory?.addIfPriceChanged(atr, time); }); } TickerSequence asTicker(L candles) { feed(candles); ret atrHistory; } void reset :: after { resetFields(this, "initialAverage sma tr atr atrHistory"); } }