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.WyckoffPhaseIndicator: phase inference engine (cycle + phase + confidence + latest event index).WyckoffPhase: record with cycle type, phase type, confidence, and latest event index.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"));
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();
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);
boolean inAccumulationAdvance = phase.cycleType() == WyckoffCycleType.ACCUMULATION
&& (phase.phaseType() == WyckoffPhaseType.PHASE_D || phase.phaseType() == WyckoffPhaseType.PHASE_E)
&& phase.confidence() >= 0.75;
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"));
if (inAccumulationAdvance && aboveValue && notOverextended && nearSupport) {
// 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 |