Documentation, examples and further information of the ta4j project
This project is maintained by ta4j Organization
This guide explains how to use ta4j’s VWAP, support/resistance, and Wyckoff indicator families together for both backtesting and live trading.
Combined, they answer:
VWAPIndicator: rolling VWAP over barCount.AnchoredVWAPIndicator: VWAP that resets on a fixed anchor or dynamic anchor signal.MVWAPIndicator: moving average of VWAP.VWAPDeviationIndicator: price - vwap.VWAPStandardDeviationIndicator: volume-weighted standard deviation around VWAP.VWAPBandIndicator: VWAP bands (VWAP +/- multiplier * stdDev).VWAPZScoreIndicator: normalized deviation (deviation / stdDev).VolumeProfileKDEIndicator: kernel density estimate of volume-at-price.
getDensityAtPrice(index, price)getModePrice(index)PriceClusterSupportIndicator / PriceClusterResistanceIndicator:
weighted price clustering in a rolling lookback.BounceCountSupportIndicator / BounceCountResistanceIndicator:
bounce-frequency-driven zones.TrendLineSupportIndicator / TrendLineResistanceIndicator:
linear regression trendline support/resistance over rolling windows.WyckoffPhaseIndicator: phase inference engine (cycle + phase + confidence + latest event index).WyckoffPhase: record with cycle type, phase type, confidence, and latest event index.WyckoffCycleFacade: unified entry point wrapping phase indicator plus cycle-level helpers.WyckoffCycleAnalysis / WyckoffCycleAnalysisResult: multi-degree cycle analysis utilities.WyckoffEventDetector, WyckoffStructureTracker, WyckoffVolumeProfile:
internal components used by the phase indicator.BarSeries series = ...;
NumFactory num = series.numFactory();
ClosePriceIndicator close = new ClosePriceIndicator(series);
VolumeIndicator volume = new VolumeIndicator(series, 1);
// 1) Value context (VWAP)
VWAPIndicator vwap = new VWAPIndicator(close, volume, 20);
VWAPStandardDeviationIndicator vwapStd = new VWAPStandardDeviationIndicator(vwap);
VWAPBandIndicator upperBand = new VWAPBandIndicator(vwap, vwapStd, 2.0, VWAPBandIndicator.BandType.UPPER);
VWAPBandIndicator lowerBand = new VWAPBandIndicator(vwap, vwapStd, 2.0, VWAPBandIndicator.BandType.LOWER);
VWAPDeviationIndicator deviation = new VWAPDeviationIndicator(close, vwap);
VWAPZScoreIndicator zScore = new VWAPZScoreIndicator(deviation, vwapStd);
// 2) Location context (S/R)
PriceClusterSupportIndicator support = new PriceClusterSupportIndicator(close, volume, 150,
num.numOf("0.25"), num.numOf("0.5"));
PriceClusterResistanceIndicator resistance = new PriceClusterResistanceIndicator(close, volume, 150,
num.numOf("0.25"), num.numOf("0.5"));
TrendLineSupportIndicator trendSupport = new TrendLineSupportIndicator(series, 2, 80);
TrendLineResistanceIndicator trendResistance = new TrendLineResistanceIndicator(series, 2, 80);
VolumeProfileKDEIndicator profile = new VolumeProfileKDEIndicator(close, volume, 150, num.numOf("0.5"));
// 3) Phase context (Wyckoff)
WyckoffPhaseIndicator wyckoff = WyckoffPhaseIndicator.builder(series)
.withSwingConfiguration(2, 2, 1)
.withVolumeWindows(5, 20)
.withTolerances(num.numOf("0.02"), num.numOf("0.05"))
.withVolumeThresholds(num.numOf("1.6"), num.numOf("0.7"))
.build();
// Optional high-level alternative: use the facade when you want cycle + phase context
// and trading-range helpers from one entrypoint.
WyckoffCycleFacade wyckoffFacade = WyckoffCycleFacade.builder(series)
.withSwingConfiguration(2, 2, 1)
.withVolumeWindows(5, 20)
.withTolerances(num.numOf("0.02"), num.numOf("0.05"))
.withVolumeThresholds(num.numOf("1.6"), num.numOf("0.7"))
.build();
// Facade helpers
WyckoffPhase facadePhase = wyckoffFacade.phase(series.getEndIndex());
Num rangeLow = wyckoffFacade.tradingRangeLow(series.getEndIndex());
Num rangeHigh = wyckoffFacade.tradingRangeHigh(series.getEndIndex());
Recent code drift note:
39194498 (2026-02-21, #1444) introduced the modern stack here: VWAP derivatives (VWAPBandIndicator, VWAPDeviationIndicator, VWAPStandardDeviationIndicator, VWAPZScoreIndicator), Wyckoff cycle analysis/facade, and KDE/cluster/bounce support-resistance indicators.b814436b (#1360) is the trendline baseline for this page (AbstractTrendLineIndicator, TrendLineSupportIndicator, TrendLineResistanceIndicator).279d9056 (2026-03-05, #1448) extended Wyckoff analysis workflow integration (WyckoffCycleAnalysisRunner) while preserving the core WyckoffPhaseIndicator/WyckoffCycleFacade usage shown below.See Backtesting for execution options. This section focuses on feature-specific patterns.
These indicators have meaningful warmup periods. Always compute a global unstable window and set it on the strategy.
int unstableBars = Math.max(
Math.max(zScore.getCountOfUnstableBars(), support.getCountOfUnstableBars()),
wyckoff.getCountOfUnstableBars());
strategy.setUnstableBars(unstableBars);
int i = series.getEndIndex();
Num price = close.getValue(i);
WyckoffPhase phase = wyckoff.getValue(i); // low-level indicator path
WyckoffPhase cyclePhase = wyckoffFacade.phase(i); // high-level facade path
Num cycleRangeLow = wyckoffFacade.tradingRangeLow(i);
boolean inAccumulationAdvance = phase.cycleType() == WyckoffCycleType.ACCUMULATION
&& (phase.phaseType() == WyckoffPhaseType.PHASE_D || phase.phaseType() == WyckoffPhaseType.PHASE_E)
&& phase.confidence() >= 0.75;
boolean cycleAgrees = cyclePhase.cycleType() == WyckoffCycleType.ACCUMULATION;
boolean aboveValue = price.isGreaterThan(vwap.getValue(i));
boolean notOverextended = zScore.getValue(i).isLessThan(num.numOf("2.0"));
boolean nearSupport = price.minus(support.getValue(i)).abs().isLessThanOrEqual(num.numOf("0.5"));
boolean nearCycleRangeLow = price.minus(cycleRangeLow).abs().isLessThanOrEqual(num.numOf("0.5"));
if (inAccumulationAdvance && cycleAgrees && aboveValue && notOverextended && nearSupport && nearCycleRangeLow) {
// candidate long condition
}
upperBand or resistance.zScore exceeds your stretch threshold and momentum stalls.lookbackLength, bandwidth, tolerance, and Wyckoff thresholds.Num to avoid precision drift when moving between DoubleNum and DecimalNum.See Live Trading for ingestion/runtime architecture. This section focuses on strategy behavior.
For production bots, evaluate entries/exits on completed bars for deterministic behavior. If you evaluate intrabar, expect more signal churn around VWAP bands and S/R boundaries.
Use anchored VWAP when your execution model depends on event regimes.
Indicator<Boolean> anchorSignal = ...; // true on session open, major news, manual resets, etc.
AnchoredVWAPIndicator anchored = new AnchoredVWAPIndicator(series, anchorSignal);
Recommended anchor sources:
In live routing, require at least two independent confirmations to reduce noise:
price > vwap for long bias, opposite for short bias).Persist:
WyckoffPhase and transition index (getLastPhaseTransitionIndex).This avoids duplicated triggers after restart.
zScore is already stretched.Start here, then tune per instrument/timeframe.
| Component | Intraday baseline | Swing baseline |
|---|---|---|
VWAPIndicator barCount |
20-60 | 50-120 |
VWAPBand multiplier |
1.5-2.0 | 2.0-2.5 |
VolumeProfileKDE lookback |
100-200 | 150-300 |
VolumeProfileKDE bandwidth |
0.25-0.75 (price-unit dependent) | 0.5-1.5 |
PriceCluster tolerance |
0.1%-0.3% of price | 0.2%-0.6% of price |
| Wyckoff volume windows | 5 / 20 | 10 / 40 |