Pattern detection had two recurring defects: a fallback that quietly
substituted different data than the caller asked for, and metadata that
asserted a point-in-time or guarantee the computation could not support.
Data substitution:
- Denoising on the classic/harmonic/elliott/fractal path smoothed only
`close`, so the smoothed close routinely fell outside its own raw candle
and ~68% of rows were reverted to raw -- preferentially at the local
extremes pivot detection keys on. Require the full OHLC set, matching the
candlestick path, and reject an explicitly partial column list.
- A failed denoise still echoed the requested spec with
`preprocessing_causality: "causal"`. Report `denoise_applied: false`,
`denoise_error` and `preprocessing_causality: "raw_prices"` instead.
- One non-finite OHLC value makes the aggregate candlestick dispatcher
throw, leaving only the few directly-attached detectors. The failure was
unrecorded because `dispatch_names` is the string "all", not a list. Add a
`detector_coverage` block plus a warning, and surface names the installed
backend does not provide (`outside` is absent from pandas-ta-classic).
Untrue claims:
- Elliott `available_at_index` was 67% irreproducible when re-running over a
window truncated at that index, because pivot spacing and (under the
default `scale_mode="auto"`) the swing scale are whole-window statistics.
Report the right edge as the guarantee and demote the confirmation-derived
figure to `earliest_possible_index_estimate` with a caveat, matching the
harmonic contract. Also track when a min-distance choice was settled so a
pivot surviving a later challenge is not claimed knowable at its own bar.
- The "no patterns detected in N bars" note omitted `observed_bars` outside
candlestick mode, asserting absence over bars never fetched.
- `df.attrs["pattern_ohlc_fallback"]` was written for the API layer to
disclose and never read, and was written after a slice so it could not
reach the caller. Wire it into warnings and report `analyzed_bars` when a
detector caps its own input window.
- `data_freshness` emitted the literal string "None", which is truthy and
then broke the year parse that would have raised a staleness warning.
Silent no-ops and misattribution:
- The documented `mode="all"` namespacing (`{"harmonic": {...}}`) reported
the section name as an invalid key and failed the fractal and harmonic
sections. Validate a section's contents against that detector, and
attribute an unknown top-level key to every detector that could own it
rather than only fractal and harmonic.
- `detail="summary"` dropped `warnings`, `data_quality`, `candles` and
`effective_window` -- exactly the fields that say not to trust a result.
- `min_strength`, `min_gap` and `robust_only` were accepted and ignored
outside candlestick mode; reject a non-default value like the adjacent
`engine` and `whitelist` guards do.
- Fractal `include_stale_levels` was discarded by the visibility allowlist
unless `include_completed` was also set, and stale rows were hidden
without being counted.
- Six Elliott config knobs were unread: the four rule/classifier blend
weights (no blend exists; an existing test pinned that) and two additive
unconfirmed-pattern penalties superseded by the confidence cap. Remove
them so they become explicit unknown-key errors.
Scoring correctness:
- Candlestick geometry keyed its body-size expectation off the deprioritize
set, so hammers, shooting stars and harami were scored as if a large body
confirmed them, while marubozu was scored as if a small one did. Classify
the expectation per pattern.
- A zero-range bar scored `body_ratio = 0.5` ("unknown"), making a perfect
doji rank below an imperfect one; it has a zero body by construction.
- `min_gap` spaced candidates selected at threshold 0.0, so a weak hit could
consume the slot and erase a qualifying signal one bar away. Space among
rows that meet `min_strength`.
- `inside` was signed by candle colour, contradicting the harami detected on
the identical bars and defeating the dedupe that exists to replace it.
Report it as non-directional and let the specific form suppress it.
- A hikkake confirmation bar (magnitude 200) was given the three-bar setup
span, putting `start_index` inside the setup.
- Candlestick `recency` used the reported bar count while `end_index` indexes
the warmup-inclusive frame, clamping `bars_ago` to 0 for every pattern in
the warmup span and biasing the cross-detector ranking.
- Volume-confirmation warmup ignored pattern span, so a multi-bar pattern on
the first visible bar had a short baseline.
Verified: ruff clean, 10115 backend tests pass, schemas 83/83.
Co-authored-by: Cursor <cursoragent@cursor.com>
Completed harmonics now track post-completion OHLC so target_reached and expired structures are historical, not current long/short setups. Compact output still keeps target and invalidation prices.
Add User/Operator/Contributor tags, Web UI and MCP tours, and market/news/wait guides. Correct stale Web API trading claims and simplify first-hour paths.