Ta4j Wiki

Documentation, examples and further information of the ta4j project

View the Wiki On GitHub

This project is maintained by ta4j Organization

Trendlines & Swing Points

Trendlines and swing points are the core building blocks behind support/resistance analysis, breakout systems, and Elliott-style structure detection. Ta4j ships a full toolkit for detecting swings, turning them into markers, and projecting data-driven support and resistance lines that behave the way traders draw them by hand.

What you get

Quick start: plot swings and lines

BarSeries series = CsvFileBarSeriesDataSource.loadSeriesFromFile(); // daily AAPL sample

// 5–bar fractal swings (symmetric window, no equal lows/highs allowed)
LowPriceIndicator low = new LowPriceIndicator(series);
HighPriceIndicator high = new HighPriceIndicator(series);
RecentFractalSwingLowIndicator swingLows = new RecentFractalSwingLowIndicator(low, 5, 5, 0);
RecentFractalSwingHighIndicator swingHighs = new RecentFractalSwingHighIndicator(high, 5, 5, 0);

// Markers only where a swing is confirmed
SwingPointMarkerIndicator swingLowMarkers = new SwingPointMarkerIndicator(series, swingLows);
SwingPointMarkerIndicator swingHighMarkers = new SwingPointMarkerIndicator(series, swingHighs);

// Data-driven support/resistance lines over the last 200 bars
TrendLineSupportIndicator support = new TrendLineSupportIndicator(series, 5, 200);
TrendLineResistanceIndicator resistance = new TrendLineResistanceIndicator(series, 5, 200);

ChartWorkflow charts = new ChartWorkflow("temp/charts");
ChartPlan plan = charts.builder()
    .withTitle("Trendlines with fractal swing markers")
    .withSeries(series)
    .withIndicatorOverlay(support).withLineColor(Color.GREEN).withOpacity(0.6f)
    .withIndicatorOverlay(resistance).withLineColor(Color.RED).withOpacity(0.6f)
    .withIndicatorOverlay(swingLowMarkers).withLineColor(Color.GREEN).withLineWidth(3f).withConnectAcrossNaN(true)
    .withIndicatorOverlay(swingHighMarkers).withLineColor(Color.RED).withLineWidth(3f).withConnectAcrossNaN(true)
    .toPlan();
charts.display(plan);

Swing point detectors

Fractal swings (window-based)

RecentFractalSwingHighIndicator / RecentFractalSwingLowIndicator confirm a swing when the candidate bar beats its neighbors inside a symmetric or asymmetric window.

Use fractals when you want visually obvious turning points and don’t mind waiting a few bars for confirmation.

// 7-bar symmetric window that tolerates one additional equal bar in the plateau
RecentFractalSwingHighIndicator majorHighs = new RecentFractalSwingHighIndicator(high, 7, 7, 1);
int latestHighIndex = majorHighs.getLatestSwingHighIndex(series.getEndIndex());

ZigZag swings (reversal-threshold based)

RecentZigZagSwingHighIndicator / RecentZigZagSwingLowIndicator track swings confirmed when price reverses by at least a configured threshold—no fixed lookahead window.

The OHLC-aware state constructors and state-only recent-swing constructors below are available in ta4j 0.22.9 and later. On 0.22.8, use the released single-price ZigZagStateIndicator(price, reversalAmount) and explicit-price recent-swing constructors.

HighPriceIndicator high = new HighPriceIndicator(series);
LowPriceIndicator low = new LowPriceIndicator(series);
ClosePriceIndicator close = new ClosePriceIndicator(series);
// Confirm swings after a 1.5 * ATR move
ATRIndicator atr = new ATRIndicator(series, 14);
Indicator<Num> atrThreshold = BinaryOperationIndicator.product(atr, 1.5);
ZigZagStateIndicator zigzagState = new ZigZagStateIndicator(high, low, close, atrThreshold);

RecentZigZagSwingLowIndicator zigzagLows = new RecentZigZagSwingLowIndicator(zigzagState);
RecentZigZagSwingHighIndicator zigzagHighs = new RecentZigZagSwingHighIndicator(zigzagState);

The state-only recent-swing constructors automatically reuse the matching low or high source. Use the explicit-source overloads only when custom pivot pricing is intentional.

Choosing a trendline swing source

No single formula is best for every turn shape:

Detector Best fit Confirmation trade-off
Fractal Distinct local extrema and fixed timing requirements Waits for the configured right-side window.
ZigZag Sharp reversals whose importance is defined by price distance or volatility Confirms after the reversal threshold is crossed.

These two sources implement RecentSwingIndicator and plug directly into trendline and marker indicators. Elliott analysis also supports slope-change and tolerant consensus backends through its separate SwingDetector contract; see Pluggable Swing Detection for those runner-specific APIs.

Both trendline swing sources are causal at the requested evaluation index: they use only bars available at that index, while the reported pivot can refer to the earlier bar where the confirmed extreme occurred.

Showing swings on charts

SwingPointMarkerIndicator outputs prices only at swing indexes (NaN elsewhere) so chart overlays become discrete markers instead of lines.

SwingPointMarkerIndicator swingLowMarkers = new SwingPointMarkerIndicator(series, swingLows);
SwingPointMarkerIndicator swingHighMarkers = new SwingPointMarkerIndicator(series, swingHighs);

chart.builder()
    .withSeries(series)
    .withIndicatorOverlay(swingLowMarkers).withLineColor(Color.GREEN).withLineWidth(3f).withConnectAcrossNaN(true)
    .withIndicatorOverlay(swingHighMarkers).withLineColor(Color.RED).withLineWidth(3f).withConnectAcrossNaN(true)
    .toPlan();

Trendline indicators

TrendLineSupportIndicator and TrendLineResistanceIndicator project the “best” straight line across the last barCount bars using swing highs/lows as anchors. They:

Core inputs

// Fractal-based support line over the last 300 bars, heavier bias to touching many swings
TrendLineSupportIndicator support = new TrendLineSupportIndicator(
    series,
    5,               // surrounding higher bars
    300,
    TrendLineSupportIndicator.ScoringWeights.touchCountBiasPreset()
);

// ZigZag-based resistance line using a custom swing detector
ZigZagStateIndicator zz = new ZigZagStateIndicator(high,
        new ConstantIndicator<>(series, series.numFactory().numOf(25)));
RecentZigZagSwingHighIndicator swingHighs = new RecentZigZagSwingHighIndicator(zz, high);
TrendLineResistanceIndicator resistance = new TrendLineResistanceIndicator(
    swingHighs,
    5, 5,            // preceding / following lower bars (kept for symmetry) 
    250
);

Scoring weights (pick the “best” line)

Weights must sum to 1.0;

Each lever tilts the search toward a different style of line:

TrendLineSupportIndicator.ScoringWeights customWeights =
    TrendLineSupportIndicator.ScoringWeights.builder()
        .weightForTouchingSwingPoints(0.55)
        .weightForTouchingExtremeSwing(0.20)
        .weightForKeepingSwingsInsideLine(0.10)
        .weightForStayingCloseToSwings(0.10)
        .weightForRecentAnchorPoints(0.05)  // Default is now 0.05 (5%)
        .build();

TrendLineSupportIndicator adaptiveSupport = new TrendLineSupportIndicator(series, 4, 180, customWeights);

Presets: touchCountBiasPreset() (connect as many swings as possible) and extremeSwingBiasPreset() (force the line through the extreme swing).

Touch tolerance (what counts as “on the line”)

Tolerance is applied per swing to count a touch:

TrendLineResistanceIndicator tightResistance = new TrendLineResistanceIndicator(
    series,
    4,
    150,
    TrendLineResistanceIndicator.ScoringWeights.defaultWeights(),
    TrendLineResistanceIndicator.ToleranceSettings.absolute(0.25) // 25 cents wide
);

Performance knobs & metadata

Runnable analysis harness

ta4jexamples.analysis.TrendLineAndSwingPointAnalysis is the companion example for this page. It performs regression-style headroom checks across bundled datasets for fractal and ZigZag swing sources, then renders a chart with support/resistance lines and swing markers.

Run it from the ta4j source checkout:

mvn -pl ta4j-examples -Dexec.mainClass=ta4jexamples.analysis.TrendLineAndSwingPointAnalysis exec:java

Use it after changing trendline scoring, swing detection, chart overlay rendering, or default search caps. In headless environments the checks still run; chart display is skipped or saved according to the example configuration.

Strategy patterns

ClosePriceIndicator close = new ClosePriceIndicator(series);
TrendLineResistanceIndicator resistance = new TrendLineResistanceIndicator(series, 5, 200);
TrendLineSupportIndicator support = new TrendLineSupportIndicator(series, 5, 200);

Rule breakoutLong = new CrossedUpIndicatorRule(close, resistance);
Rule bounceLong = new CrossedDownIndicatorRule(close, support)
        .and(new CrossedUpIndicatorRule(close, support));

Strategy trendlineStrategy = new BaseStrategy("Trendline break/bounce", breakoutLong, bounceLong.negation());

Visual examples

Trendline scoring presets Support/resistance lines from fractal swings. Default (red/green), touch-count bias (cyan/blue), and extreme-bias (orange/magenta) presets make different anchor choices.

ZigZag swing markers ZigZag-based swings confirmed after ATR-sized reversals. Fewer, higher-conviction swings compared to fractals.

Best practices & pitfalls

Rationale Notes (2026-04-27)