{% extends "base.html" %} {% set active = "about" %} {% block title %}How wave-alpha works — wave-alpha{% endblock %} {% block content %}

How wave-alpha works

A deterministic Elliott Wave engine with optional LLM rerank. This page documents what the engine does, how each metric is computed, and what it does not claim.

Pipeline overview

For each request, we fetch OHLCV bars at three intervals (weekly, daily, 4-hour), run the same enumeration on each, score the resulting wave counts for multi-timeframe agreement, optionally rerank with an LLM, and derive a trade signal from the top count. Every step is deterministic given the same inputs and as-of date.

Bars PointInTimeView Pivots Enumerate Signal
Source: src/wave_alpha/pipeline.py:run_analysis · Spec: §5 of 2026-05-03-wave-alpha-design.md

Pivots & degrees

A zigzag detector finds turning points in price scaled by Average True Range (ATR), so the same logic works on a $5 stock and a $5,000 one. Pivots are stratified into degrees: degree-0 captures every micro-turn, higher degrees keep only the more significant ones. The engine counts at degree 2 by default — coarse enough to ignore noise, fine enough to see most actionable patterns.

deg 0 deg 1 deg 2 (default)
Source: src/wave_alpha/pivots/ · Spec: §6

Wave templates

Patterns are defined in YAML, not code. Each template (impulse, zigzag, flat, expanded flat, contracting triangle, ending diagonal) lists its waves and constraints, marked either hard (rejection) or soft (score penalty). Adding a new pattern means dropping a YAML file in src/wave_alpha/elliott/templates_data/ — no code change required unless a new constraint operator is involved.

Source: src/wave_alpha/elliott/templates_data/ · Spec: §7

Enumeration & scoring

For each timeframe, the engine slides every template across the recent pivot stream and records every legal fit. Each candidate is scored on three components: template fit (how cleanly the pivots match the wave skeleton), fib quality (how close wave ratios sit to canonical Fibonacci targets), and recency (how fresh the most recent pivot is). Multiple windows of the same template family deduplicate down to the highest-scoring instance before the global top-K cut, so one template can't crowd out alternates.

Source: src/wave_alpha/elliott/enumerator.py · Spec: §8

Multi-timeframe coherence

Coherence asks: do the weekly, daily, and 4-hour timeframes tell the same story? The engine compares the top counts pairwise (W↔D, W↔4h, D↔4h) and produces a multiplier that scales the engine score. Strong agreement amplifies confidence; weak agreement (or missing-timeframe data) leaves the multiplier at 1.0 or below. High coherence means the count is consistent across horizons; it does not mean the count is correct.

Weekly Daily 4-hour
Source: src/wave_alpha/coherence/score.py · Spec: §9

Right-edge confirmation

The most recent pivot is, by definition, the least confirmed. The right-edge model estimates the probability that this tentative pivot will hold — that future bars won't push past it and invalidate the count. Three implementations exist: a hand-coded heuristic, a heuristic plus per-degree Platt calibration, and a full logistic regression with a feature-order-stable JSON artifact. The active model is selected per configuration; auto prefers logistic, falls back to calibrated heuristic, then heuristic.

Source: src/wave_alpha/right_edge/ · Spec: §10

LLM rerank & α blend

The LLM is strictly optional. When enabled, it reranks the engine's top candidates — it never invents counts. The final score blends both signals as final = α × engine + (1 − α) × llm, then multiplies by the coherence multiplier. The default α = 0.6 leans on the engine; tune toward 1.0 to trust the engine fully, toward 0.0 to trust the LLM fully. There is no formal Sharpe sweep yet, so the default is internal preference rather than a fitted optimum.

Three modes: disabled (no API key needed, fully deterministic; mandatory for backtest comparisons), cached (replays prior responses from the local SQLite cache, raises on miss), live (real API calls, writes to cache).

Source: src/wave_alpha/llm/ · Spec: §11

Trade plan derivation

For the top candidate that meets a minimum-confidence threshold, the engine derives a trade plan: entry at the close of the most recent confirming pivot, stop at the prior wave's structural extreme (with an ATR cushion), and target from a Fibonacci extension of the active count by default. R:R is (target − entry) ÷ (entry − stop). Switch the target source to fixed_R in Settings to use a fixed multiple of the entry-to-stop distance instead.

Source: src/wave_alpha/trades/derive.py · Spec: §12

Lookahead-safety guarantee

Every analysis runs through PointInTimeView, which hard-asserts that no bar with a timestamp after the as-of date is reachable. The backtest harness, the live pipeline, and the right-edge feature extractor all flow through it. A synthetic-leak unit test (tests/backtest/test_lookahead_guard.py) plants a deliberate violation to verify the assertion fires — if you ever see it pass with a leaked bar, the safety net has a hole.

Source: src/wave_alpha/data/point_in_time.py:PointInTimeView · Spec: §13

Privacy contract

When the LLM is enabled, the only payload sent upstream is: ticker symbol, pivot timestamps and prices, candidate count structures, and coherence metrics. No raw OHLCV bars, no API keys (the key is set on the client, never serialised in the payload), no account information. This contract lives in llm/prompts.py and llm/candidates.py:serialize_candidate_set. Tampering with either should require a paired update to this section.

Source: src/wave_alpha/llm/prompts.py, llm/candidates.py · Spec: §14

What this is not

  • This is not financial advice. The engine produces deterministic candidate counts and signals; whether to act on them is your judgment.
  • This is not a real-time backtest of itself. Coherence and right-edge are computed per request, not validated per request.
  • The engine can and does miss patterns. The template set in templates_data/ is finite; price action that doesn't fit a template gets no candidates.
  • High coherence does not mean the count is correct. It means the engine reached the same count across timeframes — more likely to be correct, not certain.
  • LLM rerank is heuristic. With α = 0.6 the engine still dominates; setting α = 0.0 makes the LLM responsible for most of the ranking, which is not validated.
{% endblock %}