Harmonic Patterns Scanner — Panel FxMath_Harmonic_Hunter_Scanner_Panel(MT5)
The Panel version of the Scanner. Same detection engine and settings as the classic Scanner, but the result table is a scrollable + sortable + filterable panel: mouse-wheel / ▲▼ scrolling, click-to-sort on any data column, and a filter toolbar (Type / Pattern / Time Frame / Acc / Age). Use this when there are more patterns than fit on screen.
#Overview
Unlike the classic Scanner (which draws one edit-box row per signal and can run out of
screen space), the Panel version stores every found signal as a row in
memory (g_rows[]) and draws only the visible slice inside a scroll window.
Filters and sorting operate on the stored results instantly — no re-scan needed —
and combine with scrolling.
The scan loop runs from OnTimer() on a minutes-based interval with a
g_scanBusy re-entry guard, so the timer and the Scan Market button never
overlap — and it works with zero ticks.
#Classic Scanner vs Panel
| Feature | Classic Scanner | Panel Scanner |
|---|---|---|
| Row storage | Fixed edit boxes, one per signal | Rows stored in memory, visible slice drawn |
| More signals than screen | Rows overlap / get overwritten | Scroll through all results |
| Sorting | — | Click any column header (asc/desc toggle) |
| Filtering | — | Type / Pattern / TF / Acc / Age toolbar |
| Scan trigger | OnTick + OnTimer | Pure OnTimer (minutes) + button |
| Header redraw | Every tick (slower) | Once on init + inside run() |
| View buttons | Name per pair+tf | Unique per row (view,<idx>,<pair>,<tf>) |
| Settings / engine | Identical (see Scanner docs) | |
#The signal table
The table has 12 columns, 10 of which are data columns + an "Open Chart" action column:
| # | Column | Sort | Notes |
|---|---|---|---|
| 0 | Pair | Alphabetical | e.g. EURUSD |
| 1 | Time Frame | By minutes | Stored as minutes ("60","240"…), sorted numerically → M5 < H1 < H4 |
| 2 | Pattern | Alphabetical | "Bullish Bat", "Bearish Crab"… |
| 3 | Order Type | Alphabetical | BUY (blue) / SELL (red) |
| 4 | Open Price | Numeric | Entry at 23.8% of CD |
| 5 | StopLoss | Numeric | 5% beyond CD (or ATR × mult) |
| 6 | TakeProfit 1 | Numeric | 38% of XA (or ATR × mult) |
| 7 | TakeProfit 2 | Numeric | 61.8% of XA |
| 8 | TakeProfit 3 | Numeric | 78.6% of XA |
| 9 | Acc | Numeric | Accuracy % (0–100), graded vs unscaled bounds |
| 10 | Age | Numeric | Bars since the D point |
| 11 | Open Chart | — | View button per row |
Row cells are named pnl_row<slot>_<col> with fixed slots 0–9, so
scrolling and filtering update text in place instead of recreating ~110 edit objects
every time.
#Sorting
- Click any column header (
pnl_hdr_<col>) to sort by that column. - Click again to toggle ascending ↔ descending; the active column shows
▲/▼. - Time Frame sorts by minutes (stored as
"60","240"…), so M5 comes before H1 before H4. - Price / Acc / Age sort numerically; the rest alphabetically
(
Panel_Less). - Implementation is a simple insertion sort (
Panel_Sort) on the row store — rows are few, so it's instant. Sorting resets the scroll offset to 0.
#Scrolling
- Mouse wheel over the table area scrolls (
CHARTEVENT_MOUSE_WHEELgated by a hover flag set inCHARTEVENT_MOUSE_MOVE). - Or click the
▲/▼buttons at the right edge of the table (pnl_up/pnl_dn). - The scroll offset is clamped to the filtered row count
(
maxOff = nf − PANEL_ROW_VIS), so you can never scroll past the last visible row. PANEL_ROW_VIS = 10rows visible at once,PANEL_ROW_H = 25px pitch.
#Filter toolbar
The filter bar sits above the table (FILTER_Y = 175) and has four rows:
| Row | Control | Behaviour |
|---|---|---|
| 1 | Type — ALL / BUY / SELL | Single select. Active button is highlighted (dodger blue). |
| 2 | Pattern — Bat, Gartley, Crab, Butterfly, Cypher, Shark, ABCD | Multi-select toggle. Any ON base name matches (the "Bullish/Bearish" prefix is ignored via Panel_BasePat). Wolfe is disabled, so it's not listed. |
| 3 | Time Frame — ALL + distinct scanned TFs | Multi-select of the TFs actually scanned (normalized to minute labels, e.g. "60", "240"). |
| 4 | Acc ≥ / Age ≤ edit boxes + Apply / Clear | Numeric limits. Press Enter in the box or click Apply. Clear resets everything. |
Sleep(100) was removed from every
filter/sort/scroll click so the panel feels instant.
#Filter logic details
Every row passes through Panel_Matches(r):
- Type:
g_fType == "ALL"or row's order type matches. - Pattern: if any pattern is toggled, the row's base pattern (prefix stripped) must match at least one toggled name.
- Time Frame: if any TF is toggled, the row's TF label (minute string) must match at least one toggled value.
- Acc ≥:
acc ≥ g_fAccMin(0 = no minimum). - Age ≤:
age ≤ g_fAgeMax(0 = no maximum).
The Clear button resets: g_fType="ALL", empty pattern/TF sets,
AccMin=0, AgeMax=0. Filters are kept across scans
(Panel_Reset only clears the sort), so your view persists after an auto-update.
CHARTEVENT_OBJECT_ENDEDIT: pressing Enter (or
losing focus) applies the value immediately — no need to click Apply.
#Timer-driven scanning
This version fixes the classic Scanner's tick-driven behaviour:
OnTick()does nothing — no header redraw, no scan gating.- Everything runs from
OnTimer(): ifAuto_UpdateandUpdate_Interval_Minutes > 0andTimeCurrent() − tTimer ≥ interval, a fullrun()executes. g_scanBusyis set at the start ofrun()and cleared at the end — the timer and the Scan Market button can never overlap.Update_Interval_Minutes = 0→ manual only (no timer armed).EventSetTimeris capped at 32767 s; intervals above are clamped.
#Settings (identical to the Scanner)
All inputs are the same as the classic Scanner (47 inputs),
with one rename: Uodate_Interval_Minute → Update_Interval_Minutes
(correct spelling). The same 14-entry pattern table, accuracy grading, SL/TP modes, trading
mode, notifications and .Pouya writing apply. A quick reference:
| Group | Key inputs | Defaults |
|---|---|---|
| Scanner Settings | Pairs, Read_MarketWatch_Pairs, TFs, Auto_Update, Update_Interval_Minutes, TakeProfit_Level | 30 pairs / 18 TFs / false / 15 / 2 |
| Trading Mode | Close_Partial_Trade, Close_Partial_Ratio, Breakeven_Enable, BE_Ratio_Distance | true / 0.6 / true / 0.6 |
| SL/TP Mode | SLTP_Use_ATR, SLTP_ATR_Period, SLTP_ATR_SL_Mult, SLTP_TP1_Mult, SLTP_TP2_Mult, SLTP_TP3_Mult | false / 14 / 2.0 / 4.0 / 6.0 / 9.0 |
| Pattern Settings | Pattern_Accuracy, Maximum_Market_Bar_Scan, Minimum_Market_Depth, Maximun_Market_Depth, ExpirationTime_Candle, Maximum_Pattern_Age + 7 toggles | 80 / 20 / 25 / 50 / 15 / 15 / all true |
| Notifications | Alert_Enable, Email_Enable, PushNotification_Enable, Telegram_Enable, Telegram_Bot_Token, Telegram_Chat_ID | all false |
| Other | MagicNumber, TradeComment, Helper_Text_Color, Pattern_Body_Color, ZigZag_Window_Bars | 3017 / FxMath_Harmonic_Hunter / white / yellow / 1000 |
#View / Open All Charts
- Each row has a View button named
view,<idx>,<pair>,<tf>— the index makes rows unique even when the same pair+tf appears with different patterns, and filtered rows open exactly what you see. - Clicking View opens the chart for that pair at that timeframe and applies the
Harmonic_Hunter_Scanner(MT5)template. - Open All Charts iterates only the currently visible
view,*buttons (the filter already removed the rest) and opens each. - Old View buttons are deleted at the start of each draw (
Panel_ClearRows) and recreated for the visible rows — a bug that made buttons disappear on some filter changes was fixed by scoping the cleanup to theview,prefix.
#Panel internals
| Constant / var | Value | Purpose |
|---|---|---|
| PANEL_ROW_H | 25 | Row pitch (px) |
| PANEL_ROW_VIS | 10 | Visible rows without scrolling |
| PANEL_TOP | 307 | Y of the first row |
| PANEL_COL_X[12] | {40,121,207,338,419,500,581,662,743,824,905,986} | Column X positions |
| PANEL_COL_W[12] | {72,77,117,67,67,67,67,67,67,67,32,117} | Column widths |
| STATUS_Y | 152 | "Scanning…" status line (below Open All Charts) |
| FILTER_Y | 175 | Top of the filter toolbar |
| g_rows[] / g_rowCount | dynamic | Stored signal rows |
| g_scrollOff / g_sortCol / g_sortAsc | 0 / -1 / true | Scroll + sort state |
| g_fType / g_fPats[] / g_fTfs[] / g_fAccMin / g_fAgeMax | "ALL" / [] / [] / 0 / 0 | Filter state |
| g_scanBusy | false | Re-entry guard for run() |
| g_mouseOverPanel | false | Hover flag for wheel scrolling |
#FAQ & troubleshooting
Why is a pattern not in the filter list?
Wolfe Waves are disabled (code kept, default false), so they're intentionally
not listed. The other 7 families cover all 14 built-in table entries.
My filter buttons did nothing in an old version — is that fixed?
Yes. There were off-by-one bugs parsing the Pattern (pnl_f_pat_ = 10 chars)
and Time Frame (pnl_f_tf_ = 9 chars) button names which silently made those two
filters no-ops. Fixed in the current code.
The table rows overlap / look wrong after sorting
Rows are drawn into fixed slots 0–9; sorting only changes which stored row index each slot shows. If you see stale text, re-run a scan (Scan Market) — the reset clears the sort and redraws cleanly.
Scans are slow
Trim Pairs / TFs, reduce ZigZag_Window_Bars, or
narrow the depth range. The panel redraws only the visible 10 rows, so UI cost is constant
regardless of result count.
Does the panel still write the .Pouya file?
Yes — identical to the classic Scanner, so either version can feed the Helper.