BarSeries, compute a result, and return it on demand. They compose freely — any indicator can accept another indicator as its input.
The Indicator interface
Every indicator implementsIndicator<T>, where T is the type of value returned:
getValue(int index)— returns the computed value at the given bar index.getCountOfUnstableBars()— returns how many leading bars produce unreliable output (the warm-up period).getBarSeries()— returns the backing series.
Num (i.e., Indicator<Num>), but ta4j also has Indicator<Boolean>, Indicator<Bar>, and other specialized types.
Categories of built-in indicators
Ta4j ships with 190+ indicators organized by analytical category:| Category | Examples |
|---|---|
| Trend | EMAIndicator, SMAIndicator, WMAIndicator, MACDIndicator, IchimokuIndicator, AroonIndicator |
| Momentum | RSIIndicator, StochasticOscillatorKIndicator, CCIIndicator, ROCIndicator, MOMIndicator |
| Volatility | ATRIndicator, BollingerBandsUpperIndicator, BollingerBandsLowerIndicator, StandardDeviationIndicator |
| Volume | VolumeIndicator, VWAPIndicator, OBVIndicator, MFIIndicator, ChaikinMoneyFlowIndicator |
| Price helpers | ClosePriceIndicator, OpenPriceIndicator, HighPriceIndicator, LowPriceIndicator, TypicalPriceIndicator |
| Pattern | BullishEngulfingIndicator, MorningStarIndicator, DojiIndicator, and many more candlestick patterns |
Creating basic indicators
All indicators that work on price data start from a price helper. The most common starting point isClosePriceIndicator:
Composing indicators
Indicators are composable: pass anyIndicator<Num> where an input indicator is expected. This lets you build complex chains without writing custom calculation code.
CachedIndicator and performance
Most indicators in ta4j extendCachedIndicator<T>, which stores computed values in an internal ring buffer. When getValue(index) is called multiple times for the same index, only the first call triggers calculate(int) — subsequent calls return the cached result immediately.
This matters most when you compose indicators:
- An EMA(12) composes over
close. - A MACD indicator calls
EMA(12).getValue(i)andEMA(26).getValue(i)for every bar. - Because both EMAs are cached, the MACD never recomputes an EMA value that was already calculated.
RecursiveCachedIndicator is a variant designed for indicators whose value at index i depends on their own value at index i-1 (e.g., EMA itself). It manages the recursive dependency safely and without stack overflow.
The cache is a ring buffer sized to
series.getMaximumBarCount(). When bars are evicted from the series, corresponding cached values are also evicted. This keeps memory usage bounded during live trading.The unstable bars concept (warm-up period)
Many indicators need a minimum number of bars before their output is mathematically meaningful. This warm-up period is reported bygetCountOfUnstableBars().
isStable() default implementation checks that series.getBarCount() >= getCountOfUnstableBars(). Values returned during the unstable period may be NaN or mathematically incorrect — do not trade on them.
When composing indicators, unstable periods are additive for sequential pipelines:
A complete indicator chain example
Streaming over all values
Indicator exposes a stream() method that returns a Stream<T> over every bar in the series. This is convenient for logging, analysis, or collecting values into a list:
JSON serialization
Indicators can be serialized to and restored from JSON. This is useful for saving strategy configurations or sharing indicator setups:Custom indicator classes must be in the
org.ta4j.core.indicators package (or a sub-package) for the default class resolver to find them during deserialization.