Market-Wide Candlestick Pattern Scanner
Install and import#
npm install fintech-algorithmsimport { scanMarket } from "fintech-algorithms/price-action-and-candlesticks/candlestick-scanning-and-context/market-wide-candlestick-pattern-scanner";Signature#
scanMarket(data)dispatch a frozen registry across injected detector candidates and emit only causal occurrence records with explicit rejection reasons.
Parameters#
| Name | Type | Notes |
|---|---|---|
data | { as_of: string; minimum_geometry_score: number; registry: { pattern_id: string; name: string; direction: string; window: number; detector: string; version: string; enabled: boolean; priority: number }[]; candidates: { instrument_id: string; interval: string; price_basis: string; session: string; pattern_id: string; pattern_name: string; direction: string; start_index: number; end_index: number; start_time: string; end_time: string; detected_at: string; available_at: string; bar_closed: boolean; detector_version: string; geometry_score: number; reason_codes: string[] }[] } | Topic input record; the required fields are fixed by this topic data-contract. |
Returns#
{ state, as_of, candidate_count, occurrence_count, skipped_count, occurrences, skipped }
One ready scan record containing deterministically ordered causal occurrences and reason-coded skipped candidates, with counts for both.
Complexity: time O(n log n) worst case; see README for topic-specific n,
space O(n).
Worked example#
verified This is the worked example published in the article, replayed by the test suite on every run. The output cannot drift.
Input#
{
"as_of": "2026-01-05T10:06:00Z",
"minimum_geometry_score": 0.8,
"registry": [
{
"pattern_id": "D06-F03-A01",
"name": "Bullish Engulfing",
"direction": "bullish",
"window": 2,
"detector": "bullish_engulfing",
"version": "v1",
"enabled": true,
"priority": 2
}
],
"candidates": [
{
"instrument_id": "SYNTH:AAA",
"interval": "5m",
"price_basis": "raw-trades",
"session": "synthetic-utc",
"pattern_id": "D06-F03-A01",
"pattern_name": "Bullish Engulfing",
"direction": "bullish",
"start_index": 10,
"end_index": 11,
"start_time": "2026-01-05T10:00:00Z",
"end_time": "2026-01-05T10:05:00Z",
"detected_at": "2026-01-05T10:05:01Z",
"available_at": "2026-01-05T10:05:01Z",
"bar_closed": true
},
{
"instrument_id": "SYNTH:LIVE",
"interval": "5m",
"price_basis": "raw-trades",
"session": "synthetic-utc",
"pattern_id": "D06-F03-A01",
"pattern_name": "Bullish Engulfing",
"direction": "bullish",
"start_index": 10,
"end_index": 11,
"start_time": "2026-01-05T10:00:00Z",
"end_time": "2026-01-05T10:05:00Z",
"detected_at": "2026-01-05T10:05:01Z",
"available_at": "2026-01-05T10:05:01Z",
"bar_closed": false
},
{
"instrument_id": "SYNTH:WEAK",
"interval": "5m",
"price_basis": "raw-trades",
"session": "synthetic-utc",
"pattern_id": "D06-F03-A01",
"pattern_name": "Bullish Engulfing",
"direction": "bullish",
"start_index": 10,
"end_index": 11,
"start_time": "2026-01-05T10:00:00Z",
"end_time": "2026-01-05T10:05:00Z",
"detected_at": "2026-01-05T10:05:01Z",
"available_at": "2026-01-05T10:05:01Z",
"bar_closed": true
}
]
}Call#
scanMarket(data)Returns#
object with 4 fields: state, candidate_count, occurrence_count, skipped_count
{
"state": "ready",
"candidate_count": 3,
"occurrence_count": 1,
"skipped_count": 2
}Diagrams#
Calculation flow#
Decision flow
flowchart LR
A["Validated point-in-time input"] --> B["Freeze scan cut-off"]
B --> C["Resolve enabled detector"]
C --> D{"Boundary satisfied?"}
D -->|"Yes"| E["Reason-coded ready output"]
D -->|"No"| F["Explicit rejected or unavailable state"]
How it works#
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References#
- TA-Lib function catalog and pattern-recognition group — TA-Lib project
- TA-Lib C/C++ Core API — TA-Lib project
- Binance Spot kline/candlestick stream — Binance
- CME Group chart types and support/resistance lessons — CME Group
- Foundations of Technical Analysis — Andrew W. Lo, Harry Mamaysky, and Jiang Wang
- Evidence and licensing boundary