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 equal neighbor on each side
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.

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(close, atrThreshold);

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

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

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