Image notes: the charts are drawn by the Python reference on broker price history (the same marks the indicator shows);
the rules and settings sheets are illustrations, not terminal captures. MT4 versions are in
[`docs/images/mt4/`](docs/images/mt4).
## Why it was built
Candlestick patterns are the most-read chart method there is, and the market for them is crowded. The motivations, stated
with the evidence we actually have:
- **A readable definition.** Many pattern indicators are closed boxes whose rules cannot be checked. Here every rule is a
line of arithmetic in [`tests/reference.py`](tests/reference.py) and in the `.mqh` engine.
- **Trust in the marks.** A mark is only drawn on a bar that has closed and never moves afterwards. Our market research
(demand scan of MQL5 Market, forums, freelance boards and book and course audiences, October 2026) found repeated
complaints about indicators that repaint.
- **Honest scale of demand.** The same research counted roughly 170 candlestick-pattern indicators on the MQL5 Market
(about 54 of them free) and the largest dedicated reading audience of any method, but concluded that patterns alone
are a crowded, low-differentiation product. This is a free tool with a clean, tested reference implementation, not a
claim of unmet demand.
- **Provable behaviour.** Every number in this README comes from an executed check, listed below.
```mermaid
mindmap
root((Candlestick Signal Alerts))
Problem
Pattern indicators with hidden rules
Marks that move or vanish after the bar closes
Alerts that fire twice or during history load
Design rules
13 patterns, each a few lines of arithmetic
Marks on closed bars only
One alert per bar
Same rules on MT5 MT4 and Python
Proof
Python reference
Bar by bar parity
Tester repaint probe
Market validation
```
## How it works
### The measures, step by step
Let `O, H, L, C` be a bar's open, high, low, close and `k` the bar being decided (the bar that just closed). Bars are
numbered oldest first.
| Measure | Formula |
|---|---|
| body | `|C - O|` |
| range | `H - L` |
| upper wick | `H - max(O, C)` |
| lower wick | `min(O, C) - L` |
| average body, average range | simple average of the body / range of the **10 bars before**`k` (`k-10 ... k-1`) |
| trend at bar `j` | `+1` if `C[j] > EMA20[j]`, `-1` if below, `0` otherwise. `EMA20` is seeded with the average of the first 20 closes, then `EMA[i] = EMA[i-1] + 2/21 * (C[i] - EMA[i-1])` |
| tie tolerance | comparisons treat values within `1e-9 x price` as equal (see [the tie lesson](#the-tie-lesson)) |
A bar is *bullish* if `C > O`, *bearish* if `C < O`. Nothing is decided before bar 10 (the averages) or bar 3.
### The 13 patterns
`b` = body of `k`, `r` = range of `k`, `u` / `w` = upper / lower wick of `k`, `p = k-1`, `q = k-2`, `ab` = average body,
`ar` = average range, `t1, t2, t3` = trend at `k-1, k-2, k-3`.
All 13 together: 260.7 marks per 1,000 bars, so roughly one closed bar in four carries a mark. Common patterns (doji,
engulfing) appear often; the three-bar stars are rare. This is why the arrows are best used as context, not as entries.
### The tie lesson
Rule thresholds sit on derived values (`2 x body`, `0.05 x range`, a midpoint). On five-digit prices, exact decimal ties
happen, for example a wick that is exactly twice the body. MT5 and Python rounded those ties differently and disagreed
on 73 bars until both engines were changed to compare with a tolerance of `1e-9 x price`. The same tolerance is in
`Cdl.mqh` (`GE`, `LE`, `GT`, `LT`) and in `tests/reference.py`. Any ratio-threshold engine needs it.
## Non-repainting: the proof and how it was tested
"Non-repainting" is easy to claim. Here is what was actually run. Raw result files are in [`tests/results/`](tests/results).
**1. Implementations compared bar by bar.** The Python reference ([`tests/reference.py`](tests/reference.py)) holds the rules; it was written first and the MQL engines were compared with it. The MT5 and MT4 indicators were dumped bar by bar (every buffer) in the MetaTrader Strategy Tester (MT4) or by a script (MT5), and [`tests/check_parity.py`](tests/check_parity.py) compared each dump with the reference: pattern marks must be identical on every closed bar.
Run on this exact code: compile 0 errors, 0 warnings (both editions); MT5 24 dumps and MT4 25 dumps (EURUSD, GBPJPY, XAUUSD, BTCUSD on M15, H1 and H4 with the repository's input sets; MT4 adds an every-tick run on EURUSD H1), all identical to the reference on every closed bar; the repaint probes found 0 closed bars that changed afterwards.
**The wider matrix**, made with the Market builds before this repository was cut from them (the same calculation; four symbols EURUSD, GBPJPY, XAUUSD, BTCUSD, M15, H1 and H4, the repository's input sets), checked here against the same reference:
| | MT5 | MT4 |
|---|---|---|
| dumps compared | 24 | 25 |
| bars compared | 1,059,555 | 624,737 |
| failures | 0 | 0 |
| result | ALL PASS | ALL PASS |
Sources: [`tests/results/parity-wide-run-mt5.txt`](tests/results/parity-wide-run-mt5.txt), [`tests/results/parity-wide-run-mt4.txt`](tests/results/parity-wide-run-mt4.txt). MT5 history starts later than MT4's test history on some pairs, which is why the bar counts differ.
**2. Repaint probe.** An EA records which signal buffers are set on each bar *at the moment it closes*, then reads the same bars again at the end and counts any value that changed. It also counts any signal ever shown on the still-forming bar.
| Run | Closed bars checked | Signals seen at close | Changed afterwards | Signals on the live bar |
Source: [`tests/results/repaint-summary.md`](tests/results/repaint-summary.md). The MT5 probe was run once per build on one symbol and timeframe; the MT4 probe ran on every dump run.
**3. Market validation.** Both Market builds passed the MQL5 Market's automated product validation before publication (this is the Market's own check, not part of this repository).
```mermaid
flowchart LR
R[reference.py<br/>Python rules] --> P
S5[MT5 indicator] --> T5[Tester script<br/>DumpIndicator<br/>every bar to CSV]
headings also count as string parameters when you build a handle with `IndicatorCreate` (see
`tests/mql5/Include/IndTest/Params.mqh` and the strings in `tests/check_parity.py`).
## Inputs, alerts, install and compile
| Input | Default | Meaning |
|---|---|---|
| Engulfing, Hammer and Hanging Man, Inverted Hammer and Shooting Star, Doji, Morning/Evening Star, Harami, Piercing and Dark Cloud | all on | Switch a group of patterns on or off |
| Closed bars to scan on the chart | 2000 (100-20000) | How far back marks are drawn |
| Short labels | true | Show the label text next to each arrow |
| Bullish colour, Bearish colour, Label font size | green, red, 7 | Look only |
| Arrow distance from the candle (MT4 only) | 0.5 x ATR(14) | MT4 cannot shift arrows by pixels |
| Pop-up alert | true | Terminal alert window |
| Play a sound / sound file | false / alert.wav | File from the terminal's Sounds folder |
| Push notification | false | Needs your MetaQuotes ID in Options |
| E-mail | false | Needs e-mail set up in Options |
**Install from source.** Copy `mql5/Indicators/CandlestickSignalAlerts/` into `<terminal data folder>/MQL5/Indicators/` (MT5) or
`mql4/Indicators/CandlestickSignalAlerts/` into `<data folder>/MQL4/Indicators/` (MT4), open the `.mq5` or `.mq4` in
MetaEditor and press Compile (F7). Both compile with 0 errors and 0 warnings (checked on a Windows machine with MetaEditor, from a clean scratch folder that holds only these files; the compiled files are not in
the repository). Keep the three files of each edition together: the indicator includes `Cdl.mqh` and `SignalAlerts.mqh`
from its own folder. The debug log needs the Chart Kit file as well: copy `mql5/Include/ChartKit/` (MT5) or `mql4/Include/ChartKit/` (MT4) into the `Include` folder of the data folder.
1. Compile the indicator and the test tool for your platform (`tests/mql5/Scripts/DumpIndicator`, or
`tests/mql4/CandlesDump.mq4` with `tests/mql4/Include/IndTest4/Dump4.mqh` in your `MQL4/Include/IndTest4/`; MT5 also
needs `tests/mql5/Include/IndTest/Params.mqh`).
2. Run it in the Strategy Tester (MT4) or as a script (MT5) for each symbol and timeframe, with the input sets in
`tests/configs.tsv` (MT5; the exact `InpParams` strings are in `tests/check_parity.py`) and `tests/mql4/configs.tsv`
(MT4). The tool writes one CSV per symbol and timeframe into a `dump` folder.
3.`python3 tests/check_parity.py <folder that contains dump>` (add `--mt4` for MT4 dumps). It prints PASS or FAIL per
file and an overall result.
4. Repaint: run `tests/mql5/Experts/RepaintProbe` in the MT5 Strategy Tester (every tick); the MT4 test EA writes its
repaint log with the dump.
The price dumps used for the published numbers are not in this repository (they are broker price data).
## Honest limits
- **A pattern is not a strategy.** No stop-loss, position sizing or exit rules are provided or implied, and the rules
were not optimised or back-tested for profit. In the author's own check of how price moved after these patterns, the
moves were close to what follows any bar: no edge is claimed anywhere.
- **No profit or accuracy claim is made.** The only numbers here are about *consistency* (the implementations agree,
marks do not move) and *frequency* (marks per 1,000 bars).
- **The definitions are one reading.** Candlestick names have several textbook definitions. These are the thresholds
above (for example a hammer's lower wick of at least twice the body); other tools differ, so counts will differ.
- **The trend test is simple.** "Trend before" is the close against its 20-period EMA, not a swing analysis.
- **Frequent marks.** About one closed bar in four carries a mark at default settings. Switch groups off to cut noise.
- **Scope of the tests.** Four symbols on M15, H1 and H4 for the Market builds (the same calculation), the repository's input sets, one MT5 repaint run; the code in this repository has so far been compile-checked only, and the MT5 build was not run on a live chart as part of these numbers. Other symbols and timeframes are not covered by the published numbers.
## Licence
Copyright 2026 Allan Niñal (<https://www.allanninal.dev/mql5>). Licensed under the
[PolyForm Noncommercial License 1.0.0](LICENSES/PolyForm-Noncommercial-1.0.0.md): source-available, free for personal
and other noncommercial use, not for commercial use. Each source file has an `SPDX-License-Identifier` line. Text:
[`LICENSE`](LICENSE). The candlestick patterns are textbook definitions; the code is original. The licence applies to this
source, not to anything you build or trade with the indicator. Trading involves risk; the software is provided as is.