ZigZag Swing Pattern Classifier
Complete taxonomy for classifying ZigZag swing patterns by structure and market regime. Every confirmed ZigZag sequence maps to exactly one variant — no gaps, no overlaps.
When to Use
- Classifying a confirmed L₀→H₁→L₂ (two-pivot) or L₀→H₁→L₂→H₃ (three-pivot) swing
- Looking up market regime implications of a specific pattern
- Answering "how many distinct patterns exist?" and proving exhaustiveness
- Implementing pattern labeling in code (Rust
qtacrate, Python pipelines) - Understanding the epsilon tolerance band that defines "equal"
- Applying Freedman-Diaconis binning for sub-classification depth
Notation (Single Source of Truth)
| Symbol | Definition | Example | | ------ | -------------------------------------------------- | -------- | | L₀ | Initial low (first confirmed pivot) | 1.0800 | | H₁ | Swing high (reversal peak) | 1.0850 | | L₂ | Second low (retracement) | 1.0810 | | H₃ | Second high (three-pivot only) | 1.0870 | | W | Swing magnitude: H₁ − L₀ | 0.0050 | | z | Normalized retracement: (L₂ − L₀) / (H₁ − L₀) | 0.20 | | o | Volatility-normalized overshoot: (L₀ − L₂) / ATR₁₄ | 0.35 | | ε | Tolerance band for "equal" classification | 5 pips | | τ | ZigZag reversal threshold | 6.6 pips |
Price Level Comparisons
| Code | Meaning | Condition | | ------ | ----------- | --------------- | | HL | Higher Low | L₂ > L₀ + ε | | EL | Equal Low | |L₂ − L₀| ≤ ε | | LL | Lower Low | L₂ < L₀ − ε | | HH | Higher High | H₃ > H₁ + ε | | EH | Equal High | |H₃ − H₁| ≤ ε | | LH | Lower High | H₃ < H₁ − ε |
Part 1: Two-Pivot Patterns (UP-DOWN)
Pattern: L₀ → H₁ → L₂ (one up-leg, one down-leg)
Base Classification (3 Classes)
Every UP-DOWN triplet falls into exactly one:
| Class | Condition | Meaning | Frequency | | ------ | --------------- | --------------------- | --------- | | EL | |L₂ − L₀| ≤ ε | Equal Low (retest) | ~20–30% | | HL | L₂ > L₀ + ε | Higher Low (pullback) | ~50–60% | | LL | L₂ < L₀ − ε | Lower Low (undercut) | ~10–20% |
Granular Classification: 9 FD-Binned Variants
HL and LL each decompose into 4 sub-classes using Freedman-Diaconis binning on normalized coordinates:
- HL bins use z = (L₂ − L₀) / (H₁ − L₀), ranging 0 to 1
- LL bins use o = (L₀ − L₂) / ATR₁₄, ranging 0 to ∞
| Variant | z or o Range | Market Regime | Probability | | ---------- | --------------- | ------------------------------------ | ----------- | | EL | |z| ≤ ε_r | Retest — support re-established | 20–30% | | HL-FD1 | 0.75 < z < 1.0 | Shallow pullback — buyers in control | 20–25% | | HL-FD2 | 0.50 < z ≤ 0.75 | Moderate pullback — Fib 38–50% | 15–20% | | HL-FD3 | 0.25 < z ≤ 0.50 | Deep pullback — Fib 61.8% | 10–15% | | HL-FD4 | 0 < z ≤ 0.25 | Near-complete retrace — barely held | 5–10% | | LL-FD1 | o ≤ q₂₀ | Micro undercut — brief false break | 8–12% | | LL-FD2 | q₂₀ < o ≤ q₄₀ | Shallow undercut — moderate panic | 4–8% | | LL-FD3 | q₄₀ < o ≤ q₆₀ | Deep undercut — structural break | 2–5% | | LL-FD4 | o > q₆₀ | Extreme undercut — tail event | <2% |
Trading Implications
| Variant | Entry Signal | Stop Loss | Target | | ---------- | -------------------- | ------------ | ------------ | | EL | Long from L₀+ε | L₀−ε | H₁ + ΔH | | HL-FD1 | Long from L₂ | L₂−ε | H₁ + ΔH | | HL-FD2 | Long at confirmation | L₂−ε | Prior H + ΔH | | HL-FD3 | Reduced size; wait | L₂−ε | Support + ΔH | | HL-FD4 | Extreme risk; avoid | L₂−ε | Critical | | LL-FD1 | Short spike trade | L₂+spike | L₀ | | LL-FD2 | Wait for reversal | Breakout | L₀ | | LL-FD3 | Short continuation | Reversal | New lows | | LL-FD4 | Crisis mode; hedge | Capitulation | TBD |
Optional Sub-Classification Flags
Attach to any variant for richer context:
| Flag | Meaning | Signal | | ------ | ------------------------------- | ------------------------------ | | +C | Any close < L₀ between H₁→L₂ | Stronger bearish commitment | | +S | L₂ occurs in single bar (spike) | Sharp reversal; mean reversion | | +X | Wicks below L₀ only, no close | Liquidity grab; false break |
Example labels: HL-FD2+C, LL-FD4+S+C, EL+X
Part 2: Three-Pivot Patterns (UP-DOWN-UP)
Pattern: L₀ → H₁ → L₂ → H₃ (up-leg, down-leg, up-leg)
9 Exhaustive Variants
Two independent dimensions × 3 values each = 3×3 = 9 mutually exclusive, collectively exhaustive variants.
Dimension 1 — L₂ vs L₀: {HL, EL, LL} Dimension 2 — H₃ vs H₁: {HH, EH, LH}
| # | L₂ vs L₀ | H₃ vs H₁ | Name | Market Regime | | --- | -------- | -------- | --------------------------- | ----------------------- | | 1 | HL | HH | Continuation impulse | Bull trend continuation | | 2 | HL | EH | Double-top test | Range, bullish bias | | 3 | HL | LH | Triangle compression | Neutral consolidation | | 4 | EL | HH | Range break up | Bullish transition | | 5 | EL | EH | Rectangle | Balanced range | | 6 | EL | LH | Lower-high at flat base | Range, bearish bias | | 7 | LL | HH | V-reversal / spring | Bullish reversal | | 8 | LL | EH | Undercut then stall | Volatile range | | 9 | LL | LH | Rally failure | Bear trend continuation |
Exhaustiveness Proof
All variants satisfy these mandatory constraints:
- L₀ < H₁ (first uptrend exists)
- L₂ < H₁ (retracement doesn't exceed peak)
- H₃ > L₂ (second uptrend exists)
L₂ has exactly 3 relationships to L₀ (higher, equal, lower). H₃ has exactly 3 relationships to H₁ (higher, equal, lower). These dimensions are independent — no constraint eliminates any combination. Therefore 3 × 3 = 9 variants, all feasible, none missing.
Natural Groupings
- Bullish (4): HL+HH, EL+HH, HL+EH, LL+HH
- Neutral (3): HL+LH, EL+EH, LL+EH
- Bearish (2): EL+LH, LL+LH
Regime Assignments
| Regime | Variants | | ------------------- | -------------------------- | | Trend Continuation | HL+HH (bull), LL+LH (bear) | | Range Consolidation | HL+LH, EL+EH, LL+EH | | Bullish Transition | EL+HH, HL+EH | | Bearish Transition | EL+LH | | Reversal | LL+HH |
Part 3: 27-Way Extension
Adding H₃ vs L₀ as a third independent dimension:
- L₂ vs L₀: {HL, EL, LL}
- H₃ vs H₁: {HH, EH, LH}
- H₃ vs L₀: {Above, Equal, Below}
This yields 3×3×3 = 27 sub-variants. Some are mathematically impossible due to constraints (e.g., HL+LH+H₃<L₀ requires H₃ < L₀ < L₂ < H₃, a contradiction).
Analysts often simplify this third dimension to a binary: "reclaims L₀" vs "fails to reclaim L₀".
The Epsilon Tolerance Band
The tolerance band ε determines what "equal" means. It adapts to volatility and microstructure.
Core Formula
ε = min(ε_max, max(ε_min, √[(a·S)² + (b·ATR₁₄)²]))
Where:
- S = rolling median spread (bid-ask)
- ATR₁₄ = 14-bar Average True Range
- a = 2.0 (spread scaling)
- b = 0.05 (M5-M30) or 0.07 (H1-D1)
Bounds (EURUSD defaults)
ε_min = max(3 ticks, 1×S) = max(0.00003, S)
ε_max = min(5 pips, 0.20 × swing) = min(0.00050, 0.20 × W)
Classification Using ε
ε_r = ε / W (relative tolerance)
EL if |z| ≤ ε_r
HL if z > ε_r
LL if z < −ε_r
Practical Fallbacks
If bid-ask spread unavailable:
- ATR-only: ε = 0.05 × ATR₁₄ (M5-M30), 0.07 × ATR₁₄ (H1-D1)
- Fixed band: ε = 3 pips (intraday), 5 pips (swing), 10 pips (daily)
For complete worked examples with sensitivity analysis, read references/epsilon-tolerance-detail.md.
Freedman-Diaconis Binning
The FD rule computes statistically optimal bin edges from data:
h = 2 × IQR(X) × n^(-1/3) (bin width)
K = clip(⌈(max−min) / h⌉, 3, 6) (number of bins)
edges = linspace(min, max, K+1)
Procedure for HL Patterns
- Collect 2-3 years of UP-DOWN triplets
- Filter to HL (z > ε_r)
- Winsorize z at 0.5%-99.5%
- Compute FD bin edges on z ∈ (ε_r, 1)
- Label: HL-FD1 (shallowest) through HL-FDK (deepest)
Procedure for LL Patterns
- Filter to LL (z < −ε_r)
- Compute o = (L₀ − L₂) / ATR₁₄
- Winsorize o at 0.5%-99.5%
- Compute FD bin edges on o ∈ (ε_r, ∞)
- Label: LL-FD1 (micro) through LL-FDK (extreme)
Recompute bin edges monthly or quarterly to track regime drift. Fall back to quantile binning if sample < 400.
Implementation Reference
The qta Rust crate (crates/qta/) implements the core ZigZag state machine that produces the pivots consumed by this classification framework:
ZigZagConfig::new(reversal_depth, epsilon_multiplier, bar_threshold_dbps)ZigZagState::process_bar(&bar) → ZigZagOutputwithcompleted_segmentcontainingbase_class(EL/HL/LL) andzscore- The crate computes τ and ε dynamically per pivot from
bar_threshold_dbps
The classification framework in this skill extends the crate's output with FD-binning, three-pivot analysis, and market regime labeling.
Deep Reference Files
For ASCII visualizations, worked examples, and implementation pseudocode, read these reference files as needed:
| File | Contents |
| ------------------------------------------- | --------------------------------------------------------------------------------- |
| references/notation-definitions.md | Single source of truth: all symbols, formulas, abbreviations, pattern classes |
| references/two-pivot-variants.md | All 9 two-pivot ASCII diagrams, trading rules, flag examples |
| references/three-pivot-variants.md | All 9 three-pivot ASCII diagrams, 27-way extension, HL+LH granular sub-variants |
| references/epsilon-tolerance-detail.md | Complete ε formula, worked calculation, sensitivity analysis, pseudocode |
| references/binning-methodology.md | Freedman-Diaconis algorithm details, FD vs quantile comparison, worked example |
| references/data-pipeline.md | 11-step end-to-end pipeline: raw quotes → OHLC → ATR → pivots → classify → output |
| references/eurusd-validation-scenarios.md | 3 worked market scenarios (Normal, Volatile, Crash) validating ε and τ |