Harmonic Patterns Scanner FxMath_Harmonic_Hunter_Scanner(MT5)
The market scanner EA. It scans a grid of Pairs × Timeframes, detects
harmonic patterns with an in-EA ZigZag engine and displays the results in an on-chart
table, keeping only the highest-accuracy pattern per symbol+timeframe.
On attach it writes the shared <AccountLogin>.Pouya settings file used
by the Helper EA.
#Overview
The Scanner is a pure-MQL5 Expert Advisor. It needs no external indicators: the ZigZag
pivot engine is implemented inside the EA (a faithful port of MetaQuotes'
Examples\ZigZag, deviation = 5 × point, backstep = 3) and cached per
symbol/timeframe/depth. The only external dependency is the standard
<Trade\Trade.mqh> in the Helper and the WinInet DLL import used by
httpGET() (Telegram / version check).
The scan loop runs on a real timer (EventSetTimer), so results stay fresh even
when the market is closed or the chart is quiet. Every found signal can trigger
Alert / Email / Push / Telegram notifications.
#User interface
The panel is drawn on the chart it is attached to (any chart — the Scanner scans its configured list, not the chart itself):
| Element | Description |
|---|---|
| Header | Account Balance, Equity, Total Profit, Risk %, Lot Size and EA Version. |
| Scan Market button | Triggers a full scan of all Pairs × TFs manually. |
| Open All Charts button | Opens a chart for every row in the table and applies the Harmonic_Hunter_Scanner(MT5) template. |
| Column headers | Pair · Time Frame · Pattern · Order Type · Open Price · StopLoss · TakeProfit 1/2/3 · Acc · Age. |
| Result rows | One row per detected pattern — read-only edit boxes with the trade levels. |
| View button (per row) | Opens the chart of that pair/timeframe and applies the template. |
| Status label | "Scanning(pair(TF))… Please Wait" while a scan is running. |
Harmonic_Hunter_Scanner(MT5) template is normally just the Helper EA pre-attached
to the chart. Create it once by attaching the Helper to a chart and saving the template
with that name.
#Scanner Settings
| Input | Type | Default | Description |
|---|---|---|---|
| Version | string | "1.0" | Displayed in the header. Informational only. |
| Section_1 | string | "Scanner Settings" | Group separator in the Inputs tab (F7). |
| Pairs | string | 30 majors/crosses/metals | Comma-separated symbol list to scan (e.g. EURUSD,GBPUSD,XAUUSD). Prefix/suffix is auto-detected from the chart symbol. |
| Read_MarketWatch_Pairs | bool | false | When true, scan every symbol currently visible in Market Watch instead of the Pairs list. |
| TFs | string | "1,2,3,4,5,10,15,20,30,60,120,180,240,360,480,720,1440" | Comma-separated timeframes in minutes (M1=1 … D1=1440). Any subset works. |
| Auto_Update | bool | false | Enable the timer-driven re-scan. Works without ticks (closed market). |
| Uodate_Interval_Minute | int | 15 | Auto re-scan interval in minutes (0 = manual only via the Scan Market button). Capped at the 32767 s timer limit. |
| TakeProfit_Level | int | 2 | Which TP level the Helper uses when opening orders: 1 = TP1 (38%), 2 = TP2 (61.8%), 3 = TP3 (78.6% of XA). Forwarded via .Pouya. |
#Trading Mode
These settings are forwarded to the Helper through the shared settings file and control the automatic position management:
| Input | Type | Default | Description |
|---|---|---|---|
| Close_Partial_Trade | bool | true | Close a percentage of the position volume when the price travels BE_Ratio_Distance of the entry→TP distance. |
| Close_Partial_Ratio | double | 0.6 | Fraction of the volume to close (0.6 = 60%). Snapped to the broker's volume step and clamped by min volume. |
| Breakeven_Enable | bool | true | Move the Stop Loss to the entry price (+10 points buffer) at the same trigger distance. |
| BE_Ratio_Distance | double | 0.6 | Trigger as a fraction of the entry→TP distance (0.6 = when 60% of the way to TP). Both actions fire at once. |
#SL/TP Mode (shared with the Helper)
Two distinct ways of computing Stop Loss and Take Profit levels:
With SLTP_Use_ATR = false (default), levels are derived from the pattern legs:
| Stop Loss | SL = D ± 0.05 × CD (5% beyond the CD leg) |
| TP1 | TP1 = D ± 0.38 × XA (38% of the XA leg) |
| TP2 | TP2 = D ± 0.618 × XA (61.8% of the XA leg) |
| TP3 | TP3 = D ± 0.786 × XA (78.6% of the XA leg) |
TakeProfit_Level (1/2/3) still selects which TP the Helper uses for the trade.
With SLTP_Use_ATR = true, SL and TP become multiples of ATR
measured at the D point. The defaults give R:R 1:2 / 1:3 / 1:3:
| Input | Type | Default | Description |
|---|---|---|---|
| SLTP_Use_ATR | bool | false | Master switch. false = harmonic-ratio SL/TP above; true = ATR-based SL/TP. |
| SLTP_ATR_Period | int | 14 | ATR period used for the ATR-based levels. |
| SLTP_ATR_SL_Mult | double | 2.0 | SL = ATR × 2.0 |
| SLTP_TP1_Mult | double | 4.0 | TP1 = ATR × 4.0 → R:R 1:2 |
| SLTP_TP2_Mult | double | 6.0 | TP2 = ATR × 6.0 → R:R 1:3 |
| SLTP_TP3_Mult | double | 9.0 | TP3 = ATR × 9.0 → R:R 1:4.5 |
All multipliers are free-form — e.g. TP1 1.5×, TP2 2.5×, TP3 4× gives a custom R:R ladder.
The Helper respects TakeProfit_Level and draws a cyan badge showing the active
multipliers + the R:R of the selected level:
ATR(14) SL 2.0x TP1 4.0x TP2 6.0x TP3 9.0x RR 1:2.
#Harmonic Patterns Settings
| Input | Type | Default | Description |
|---|---|---|---|
| Pattern_Accuracy | double | 80 | Ratio tolerance in % (clamped to 60–100). 100 = ratios must match the table exactly; 80 = ±20% tolerance around each bound. |
| Maximum_Market_Bar_Scan | int | 20 | How many recent bars to scan for the D-point window (the "lookback" of the scan). |
| Minimum_Market_Depth | int | 25 | Lowest ZigZag depth tried. |
| Maximun_Market_Depth | int | 50 | Highest ZigZag depth tried (note the historic spelling "Maximun"). |
| ExpirationTime_Candle | int | 15 | Pending-order expiry in candles (used by the Helper's stop/limit orders; 0 = GTC). |
| Maximum_Pattern_Age | int | 15 | Only show patterns whose D point is newer than this many candles (0 = no age filter). Forwarded to the Helper and applied in both find() functions. |
Pattern toggles
Each pattern family has an enable switch. Disabled families are skipped entirely:
| Input | Default | Controls |
|---|---|---|
| Bat_Pattern_Enable | true | Bat, Max Bat, Alt Bat |
| Gartley_Pattern_Enable | true | Gartley, Max Gartley |
| Butterfly_Pattern_Enable | true | Butterfly, Max Butterfly |
| Crab_Pattern_Enable | true | Crab, Deep Crab |
| Cypher_Pattern_Enable | true | Cypher, Deep Cypher |
| Shark_Pattern_Enable | true | Shark 1, Shark 2 |
| ABCD_Pattern_Enable | true | AB=CD |
| Wolfe_Pattern_Enable | false | Temporarily disabled (code kept, call site commented out). See Known limitations. |
#Notification Settings
| Input | Type | Default | Description |
|---|---|---|---|
| Alert_Enable | bool | false | Terminal alert on every emitted signal. |
| Email_Enable | bool | false | E-mail notification (configure the terminal's mail settings). |
| PushNotification_Enable | bool | false | Mobile push via the MT5 app. |
| Telegram_Enable | bool | false | Send signals to a Telegram bot chat. Needs Allow DLL imports (WinInet httpGET). |
| Telegram_Bot_Token | string | "" | Bot token from @BotFather. |
| Telegram_Chat_ID | string | "" | Chat id (numeric, may start with -). |
Each signal message includes the full details (pair, TF, pattern, order type, open, SL, TP1–3) plus the signature line "Powered by FxMath Harmonic Hunter Scanner".
#Other Settings
| Input | Type | Default | Description |
|---|---|---|---|
| MagicNumber | int | 3017 | Magic number for orders placed by the Helper (also written to .Pouya). |
| TradeComment | string | "FxMath_Harmonic_Hunter" | Order comment used by the Helper. |
| Helper_Text_Color | color | clrWhite | Text color of the Helper's on-chart labels (forwarded via .Pouya). |
| Pattern_Body_Color | color | clrYellow | Color of the drawn pattern body (triangles/channels, forwarded via .Pouya). |
| ZigZag_Window_Bars | int | 1000 | History window in bars for the in-EA ZigZag cache (should be ≥ Maximum_Market_Bar_Scan + 500). |
#Detection engine
In-EA ZigZag
The EA contains a faithful port of MetaQuotes' Examples\ZigZag indicator
with the same parameters the old iCustom calls used: depth (from
the settings), deviation = 5 × point, backstep = 3. The
buffer is series-indexed ([0] = current bar, 0.0 = not a pivot).
- Per-depth caching: depths 2…100 are cached per (symbol, timeframe,
last-bar time) in a flat buffer, rebuilt only when the session changes
(
ZZ_Session→ZZ_BuildDepth→ZZ_Price). - Scan window:
scanBars = Maximum_Market_Bar_Scan + Maximun_Market_Depth. For each bariand each depth in the configured range, the 5 most recent alternating pivots are collected (find()). - Degenerate legs (zero-length XA/AB/BC/CD) are rejected.
Detection flow
(tolerance-scaled bounds)"] G --> H{"All 4 ratios inside?"} H -->|yes| I["Grade accuracy vs unscaled bounds"] I --> J{"Better than current best?"} J -->|yes| K["Keep as best for this pair+TF"] K --> L["After all depths: EmitBestPattern"]
Order direction
If D < C the pattern is Bullish → BUY; if
D > C it is Bearish → SELL. The Scanner also
filters by the current market price: bullish patterns require
Ask > op23 (the entry is still below market), bearish patterns require
Bid < op23 — stale patterns whose entry has already been passed are skipped.
#Built-in pattern table
14 entries (ratios verified against the reference sheet). Tolerances are applied as
bound × (1 ± tol) where tol = (100 − Pattern_Accuracy) / 100.
| # | Pattern | XAB | ABC | BCD | XAD | Family toggle |
|---|---|---|---|---|---|---|
| 1 | Bat | 0.382–0.5 | 0.382–0.886 | 1.618–2.618 | 0.886 | Bat |
| 2 | Max Bat | 0.382–0.618 | 0.382–0.886 | 1.272–2.618 | 0.886 | Bat |
| 3 | Gartley | 0.618 | 0.382–0.886 | 1.128–2.236 | 0.618–0.786 | Gartley |
| 4 | Max Gartley | 0.382–0.618 | 0.382–0.886 | 1.128–2.236 | 0.618–0.786 | Gartley |
| 5 | Crab | 0.382–0.618 | 0.382–0.886 | 2.24–3.618 | 1.618 | Crab |
| 6 | Butterfly | 0.786 | 0.382–0.886 | 1.618–2.618 | 1.272–1.618 | Butterfly |
| 7 | Max Butterfly | 0.618–0.886 | 0.382–0.886 | 1.272–2.618 | 1.272–1.618 | Butterfly |
| 8 | Deep Crab | 0.886 | 0.382–0.886 | 2.618–3.618 | 1.618 | Crab |
| 9 | Alt Bat | 0.382 | 0.382–0.886 | 1.618–2.618 | 1.13 | Bat |
| 10 | Cypher | 0.382–0.618 | 1.13–1.414 | 1.272–2.0 | 0.786 | Cypher |
| 11 | Shark 1 | 1.13–1.618 | 1.618–2.24 | 0.886–1.13 | 0.886–1.13 | Shark |
| 12 | Shark 2 | 1.13–1.618 | 1.618–2.24 | 1.618–2.24 | 0.886–1.13 | Shark |
| 13 | Deep Cypher | 0.618 | 1.13–1.618 | 1.618–2.618 | 0.886 | Cypher |
| 14 | AB=CD | 0.382–0.786 | 0.382–0.786 | 1.13–2.24 | 0.618–0.786 | ABCD |
Custom CSV patterns are disabled for now — the built-in 14-entry table is
always used. The ReadCSV() call in OnInit is commented out;
Custom_Patterns / Patterns_File_Name were removed from the
Inputs tab (kept as plain variables so the code compiles).
#Accuracy scoring (the Acc column)
Every candidate is graded with AccuracyScore(xb, ac, bd, xd) — the average of
four ratio-fit scores. A ratio inside its unscaled table range scores 1.0;
outside, the score decays linearly from the range centre:
FitRatio(r, lo, hi):
if lo ≤ 0 → 1.0
if lo ≤ r ≤ hi → 1.0
d = 1 − |r − mid| / mid (clamped ≥ 0)
→ d
Because the score uses the unscaled bounds (snapshotted into
acc_* globals before tolerance scaling), the Acc column varies: 100
for an exact table match, lower as ratios drift toward the tolerance edges. Among multiple
candidates, the highest score wins; ties are broken by the newest D point
(p_d < g_bestPd).
#The .Pouya settings file
On every attach the Scanner writes <AccountLogin>.Pouya into
MQL5\Files\ — the bridge between Scanner and Helper. Contents:
# File: 3017.Pouya (example, key=value lines, comma-separated CSV mode)
License=<account-check-response>
accuracy=80.0
Maximum_Market_Bar_Scan=20
Minimum_Market_Depth=25
Maximun_Market_Depth=50
Maximum_Pattern_Age=15
TakeProfit_Level=2
TradeComment=FxMath_Harmonic_Hunter
MagicNumber=3017
ExpirationTime_Candle=15
Close_Partial_Trade=1
Close_Partial_Ratio=0.60
Breakeven_Enable=1
BE_Ratio_Distance=0.60
SLTP_Use_ATR=0
SLTP_ATR_Period=14
SLTP_ATR_SL_Mult=2.00
SLTP_TP1_Mult=4.00
SLTP_TP2_Mult=6.00
SLTP_TP3_Mult=9.00
Helper_Text_Color=16777215
Pattern_Body_Color=65535
Custom_Patterns=false
Patterns_File_Name=Harmonic_Pattern.csv
The Helper parses these keys in read() on attach, so both EAs stay in sync.
#Auto symbol prefix/suffix detection
The Scanner auto-detects the broker's symbol prefix/suffix from the chart symbol
(AutoDetectSymbolPrefixSuffix()) — there are no manual
Prefix/Suffix inputs anymore:
- Suffix: strip a known base pair (19 FX/crypto/metals bases, e.g.
XAUUSD,BTCUSD) at the start of the chart symbol, or walk currency codes at positions 0 and 3–6.EURUSD→ no suffix;EURUSD.m→ suffix.m. - Prefix: whatever precedes a Pairs-list entry inside the base-only
symbol.
fxEURUSD→ prefixfx.
bases[] / codes[] arrays
in the source or add a broker mapping.
#Recommended workflow
1. Attach the Scanner
Attach it to any chart (e.g. EURUSD M15). Adjust the Pairs, TFs, accuracy, depth range and SL/TP mode in F7, then re-attach so the .Pouya file is rewritten.
2. Scan the market
Press Scan Market (or enable Auto_Update). Review the rows: pair, TF, pattern, order type, open, SL, TP1–3, Acc, Age.
3. Open a chart
Click View on an interesting row (or Open All Charts) — the chart opens with the Harmonic_Hunter_Scanner(MT5) template applied (Helper attached).
4. Trade from the Helper
Use the Helper's Trading Options: Instant, Stop or Limit order. SL/TP come from the pattern (or ATR mode), the TP level from TakeProfit_Level.
5. Let it manage
The Helper auto-closes a % at the trigger distance and moves SL to breakeven, per the Scanner's Trading Mode settings.
#Tuning tips
- Too many signals? Raise
Pattern_Accuracytoward 90–95, lowerMaximum_Pattern_Ageto ~5–10, or disable pattern families you don't trade. - Too few? Lower accuracy to 60–70, raise
Maximum_Market_Bar_Scanand widen the depth range (e.g. 20–80). - Faster scans: trim the
Pairs/TFslists and lowerZigZag_Window_Bars. - ATR mode makes SL/TP market-aware (volatility-based) instead of ratio-based — useful in news-heavy or high-volatility sessions.
- Age column = bars since the D point. Fresh patterns (age 0–3) are generally more actionable.
#Known limitations
- Wolfe Waves disabled — to re-enable, set
Wolfe_Pattern_Enable = trueand uncomment//if(valid==0 && Wolfe_Pattern_Enable)WolfeScan(sym,tf,dep,point);infind(). - Custom CSV patterns disabled — uncomment
ReadCSV()inOnInitand restore the inputs to re-enable. - WinInet httpGET requires Allow DLL imports in the terminal and in the EA properties (license check is currently bypassed, so this is non-critical).
- License check is present but bypassed (
License = true). - Settings are read once at Helper attach — change Scanner settings while the Helper is running requires re-attaching the Helper.
OnTickin the classic Scanner still callsStart()(redraws the header on every tick). The Panel version fixes this by driving everything from the timer.