MT5 Multi-Timeframe Candlestick Pattern Scanner & Backtester v7
A comprehensive tool to scan M5, M15, H1, H4, D1 charts for classical candlestick patterns, backtest their performance with realistic entry/exit simulation, and run a live scanner that scores and alerts when a new pattern appears.
Features
- 20+ patterns: Doji, Hammer, Shooting Star, Engulfing, Morning/Evening Star, Three White Soldiers, Three Black Crows, Marubozu, Harami, Tweezers, Rising/Falling Three Methods, Inverted Hammer, and more
- Multi-timeframe backtesting — backtest all 5 timeframes in a single run with per-TF statistics
- Pattern tier system — patterns auto-classified as A:ELITE, B:TRADEABLE, C:MARGINAL, or D:AVOID based on historical win rate
- Session quality classification — sessions ranked as PRIME, FAVORABLE, NEUTRAL, or UNFAVORABLE
- Signal scoring (0-100) — each live signal scored using TF-specific pattern WR, session gradient, confluence bonus, tier bonus, and MFE bonus
- Confluence scoring (0-6 with D1 filter, 0-7 without) — each backtest detection gets a confluence score based on trend alignment, volume, S/R context, RSI extreme, swing level, and session quality (D1 trend factor is skipped when the D1 trend filter is active, since it's already guaranteed)
- Support/Resistance context — swing high/low detection tags each signal as near_support, near_resistance, at_swing_low, or at_swing_high
- RSI context — RSI(14) computed at each detection; oversold/overbought contributes to confluence
- Variable R:R by pattern — configurable
rr_by_patterndict overrides TP multiplier per pattern - MAE/MFE tracking — Max Adverse Excursion and Max Favorable Excursion in R-multiples per trade
- Time-to-SL/TP — bars until SL or TP hit, enabling trade management optimization
- Open-proximity SL/TP resolution — when both SL and TP are within a candle's range, the level closer to the open price is assumed hit first (replaces the old candle-direction heuristic)
- Wilder's ATR smoothing — standard industry ATR method (alpha = 1/period), matching MT5's built-in indicator
- Enriched stats JSON —
latest_stats_multitf.jsonnow includes per-TF patterns, sessions, cross-stats, and confluence breakdown (scanner starts instantly, no CSV re-parse) - D1 forward window extended — D1 forward evaluation increased from 5 to 20 candles (4 trading weeks) for meaningful D1 stats
- Historical edge dashboard — displayed at scanner startup showing top setups, pattern x session combos, Tier D avoid list, and recommended live setups
- Per-timeframe WR columns — pattern table shows win rate broken down by M5/M15/H1/H4/D1 so you can see which TF each pattern performs best on
- Stop Loss / Take Profit based on ATR (configurable multiplier, R:R ratio)
- Higher-timeframe ATR for fast timeframes (M5/M15 automatically use H1 ATR for realistic SL/TP)
- Entry verification (stop orders only filled if price touches entry on the next candle)
- Forward evaluation with intra-candle path simulation — avoids look-ahead bias
- R-level tracking (up to R5) and hit-rate analysis
- Volume confirmation (optional)
- D1 trend filter (enabled by default) — requires the daily SMA 20 trend to align with the pattern direction
- Deduplication — picks the highest-priority pattern per candle
- Session classification (Asia, Pacific, London Open, London Morning, London/NY Overlap, NY Afternoon)
- Full backtests over date ranges — CSV reports, summary tables, JSON stats cache, and text reports
- Live scanner — monitors all active timeframes and prints formatted alerts when a new candle closes
- Sound alerts (Windows only) — high-Hz triple beep for STRONG BUY, low-Hz triple beep for STRONG SELL; starts muted, type
m+ Enter to toggle - Position sizing (risk-based, standard lots) displayed in alerts
- Auto-reconnect with exponential backoff if MT5 connection drops
Installation
-
Install MetaTrader 5
-
Install Python dependencies:
pip install MetaTrader5 pandas numpy colorama python-dotenv -
Copy
mt5_multitf_pattern_scanner.pyinto your project folder. -
Create a
.envfile in the same directory as the script:MT5_PATH=C:\Program Files\Broker\terminal64.exe MT5_ACCOUNT=12345678 MT5_PASSWORD=YourPassword MT5_SERVER=YourBrokerServer1
Quick Start
Step 1 — Run the Backtest
The backtest generates the probability data that powers the live scanner's pattern tiers, signal scores, and historical edge display. Always run the backtest first.
python mt5_multitf_pattern_scanner.py --mode fullbacktest --from 2025-06-01 --to 2026-05-15
This scans all 5 timeframes (M5, M15, H1, H4, D1) over the date range and saves:
- Per-TF CSV files (detections, pattern summary, session summary) in
./backtest_results/ latest_stats_multitf.json— the enriched stats cache the live scanner loads at startup (now includes per-TF patterns, sessions, cross-stats, and confluence breakdown)
With D1 trend filter enabled (default), only signals that aligned with the daily trend are counted. This gives the most accurate stats for live trading.
Step 2 — Run the Live Scanner
python mt5_multitf_pattern_scanner.py --mode live
The scanner starts, loads the backtest stats, and displays the Historical Setups Dashboard:
- Overall and per-timeframe win rates
- Pattern tiers with per-TF WR columns (M5 | M15 | H1 | H4 | D1)
- Session quality rankings
- Top pattern x session combos
- Tier D patterns to avoid
- Recommended live setups with signal scores
Then it monitors all timeframes and alerts on every new candle close when a pattern is detected, showing:
- Pattern name, tier, direction, session, D1 trend alignment
- Entry, SL, TP with pip distances and R:R ratio
- Prob(TP) percentage based on historical SL/TP hit rates
- Historical edge breakdown (pattern WR, session WR, cross-stat WR, signal score)
- Risk-based position sizing
Sound alerts start muted by default. Type m + Enter in the terminal to unmute and hear audio alerts for strong signals. See Sound Alerts for details.
Press Ctrl+C to stop.
Usage
Full Backtest (date-ranged)
Runs a complete backtest across all active timeframes over a specified date range. This is the primary way to generate stats for the live scanner.
# All timeframes, Jan 2025 to May 2026
python mt5_multitf_pattern_scanner.py --mode fullbacktest --from 2025-01-01 --to 2026-05-14
# Specific timeframes only
python mt5_multitf_pattern_scanner.py --mode fullbacktest --timeframes H4 D1 --from 2025-01-01 --to 2026-05-14
# With D1 trend filter ON (default) and volume filter
python mt5_multitf_pattern_scanner.py --mode fullbacktest --from 2025-01-01 --to 2026-05-14 --d1-trend-filter --volume-filter
# Without D1 trend filter
python mt5_multitf_pattern_scanner.py --mode fullbacktest --from 2025-01-01 --to 2026-05-14 --no-d1-trend-filter
Output: ./backtest_results/ (change with --output)
Quick Backtest (last N bars)
Fast snapshot on the most recent N candles (default 500) for a single timeframe.
python mt5_multitf_pattern_scanner.py --mode backtest --bars 500
Live Scanner
# All timeframes (default)
python mt5_multitf_pattern_scanner.py --mode live
# Specific timeframes
python mt5_multitf_pattern_scanner.py --mode live --timeframes H1 H4 D1
# Without D1 trend filter (must match how backtest was run)
python mt5_multitf_pattern_scanner.py --mode live --no-d1-trend-filter
One-Shot Scan
Scan the latest closed candle on all active timeframes and exit.
python mt5_multitf_pattern_scanner.py --mode scan
Test Sound Alerts
Play both the STRONG BUY and STRONG SELL test beeps to verify audio is working, then exit.
python mt5_multitf_pattern_scanner.py --test-sound
Sound Alerts
The scanner includes Windows-only sound alerts so you don't have to stare at the screen waiting for strong signals.
How it works
- STRONG BUY (Bullish signal with score >= 65) — triple high-Hz beep (1200 Hz by default)
- STRONG SELL (Bearish signal with score >= 65) — triple low-Hz beep (400 Hz by default)
- The scanner starts muted — you must explicitly unmute to hear alerts
- Type
m+ Enter in the terminal to toggle mute/unmute at any time - The keyboard listener runs in a background thread, so there is no delay — it responds instantly
Startup message
When the live scanner starts with sound enabled, you will see:
Sound Alerts: ENABLED | Buy: 1200Hz | Sell: 400Hz | Threshold: 65
Sound is MUTED — Type "m" + Enter to unmute
Toggling mute
Type m and press Enter at any time while the scanner is running:
Sound UNMUTED | Type 'm' + Enter to toggle
Sound MUTED | Type 'm' + Enter to toggle
Testing sound
Before relying on alerts, verify your audio works:
python mt5_multitf_pattern_scanner.py --test-sound
This temporarily unmutes, plays both test beeps, then restores the muted state.
Sound configuration
These settings are in the CFG dict at the top of the script (not exposed as CLI args):
| Key | Default | Description |
|---|---|---|
sound_enabled |
True |
Master switch — set False to disable all sound |
sound_buy_hz |
1200 |
Frequency in Hz for STRONG BUY triple beep |
sound_sell_hz |
400 |
Frequency in Hz for STRONG SELL triple beep |
sound_beep_duration |
150 |
Duration of each individual beep in milliseconds |
sound_beep_pause |
100 |
Pause between beeps in milliseconds |
sound_strong_threshold |
65.0 |
Signal score must be >= this to trigger a sound alert |
v7 Enhancements
Open-Proximity SL/TP Resolution
When both SL and TP fall within a single candle's range, the old heuristic used the candle's direction (bullish/bearish close) to decide which was hit first — this is look-ahead bias. The new heuristic uses open-proximity: whichever level is closer to the candle's open price was likely hit first. This is more realistic and corrects a 2-5% WR distortion.
Confluence Scoring (0-6 with D1 filter, 0-7 without)
Each backtest detection receives a confluence score based on how many confirming factors align:
| Factor | +1 When |
|---|---|
| Trend alignment | Local trend agrees with trade direction |
| D1 trend alignment | Daily trend agrees with trade direction (skipped when --d1-trend-filter is active) |
| Volume confirmation | Signal candle has above-average volume |
| S/R context | Near support (bullish) or near resistance (bearish) |
| RSI extreme | RSI < 35 for bullish, RSI > 65 for bearish |
| At swing level | At swing low (bullish) or swing high (bearish) |
| Session quality | London/NY Overlap or London Open session |
Why skip D1 trend when the filter is active? When
--d1-trend-filteris on (the default), every signal already has D1 trend alignment guaranteed by the filter. Counting it as a confluence factor would inflate every score by +1 and destroy score differentiation. With the filter active, the effective range is 0-6; without the filter, it's 0-7.
The backtest report and JSON include confluence breakdowns, e.g. "Confluence >= 4: 72% WR vs Confluence 0-2: 48% WR".
Variable R:R by Pattern
Different patterns have different optimal R:R profiles. Configure overrides in CFG:
'rr_by_pattern': {
'Bullish Engulfing': 1.5, # Quick scalp
'Morning Star': 2.5, # Larger move expected
'Three White Soldiers': 3.0, # Strong continuation
},
When a pattern is listed here, its TP multiplier is overridden. The RR_Override column in the detections CSV shows which patterns used overrides.
MAE/MFE Tracking
Every trade now records:
- MAE (Max Adverse Excursion) — worst drawdown in R-multiples before the trade closed
- MFE (Max Favorable Excursion) — best profit in R-multiples before the trade closed
This enables trade management optimization like: "Move SL to breakeven after price reaches 1R" or "If MAE exceeds 0.8R, the trade has low probability of reaching TP".
Time-to-SL/TP
Each trade records Bars_to_SL and Bars_to_TP — the number of forward candles until SL or TP was hit. This enables:
- Early exit strategies: "If not in profit after 8 M5 candles, close for breakeven"
- Trailing stop timing: "Move SL to breakeven after 4 H4 candles"
Support/Resistance Context
The backtest now detects swing highs and lows (using a 5-bar local extreme window over the last 50 bars) and tags each detection with:
Near_Support— price within 1 ATR of a swing lowNear_Resistance— price within 1 ATR of a swing highAt_Swing_Low— candle low is the lowest in the lookback windowAt_Swing_High— candle high is the highest in the lookback window
Patterns near support/resistance have dramatically different win rates.
RSI Context
RSI(14) is computed at each detection using Wilder's smoothing method. The value is stored in the RSI column and contributes to confluence scoring (oversold for bullish, overbought for bearish).
Enriched Stats JSON
latest_stats_multitf.json now includes per-TF breakdown of:
{
"timeframes": {
"H4": {
"overall": { "win_rate": 53.6, "total_signals": 252, "avg_mae_r": 0.45, "avg_mfe_r": 0.72, "avg_bars_to_tp": 5.2 },
"patterns": { "Bullish Engulfing": { "win_rate": 58.2, "total": 312 } },
"sessions": { "London/NY Overlap": { "win_rate": 55.1, "signals": 89 } },
"cross": { "Bullish Engulfing|London/NY Overlap": { "win_rate": 62.3, "signals": 14 } },
"confluence": { "3": { "win_rate": 68.2, "signals": 42 }, "0": { "win_rate": 44.1, "signals": 31 } }
}
}
}
The live scanner now loads all data from JSON — no CSV re-parsing at startup, so the scanner starts instantly.
Improved Signal Scoring
The v7 score formula fixes the old formula's problems:
| Factor | v6 (old) | v7 (new) |
|---|---|---|
| Base | WR * confidence (low-sample patterns got lower base) |
Raw WR as base (no multiplication) |
| Sample size | Confidence multiplier | Sample penalty (-15 for small samples, 0 for 30+) |
| Session | Binary +10/-10 | Proportional gradient based on session WR |
| R-factor | min(amr, 2.0) * 10 (up to +20, too large) |
MFE bonus +1/+3 for amr >= 0.5/0.8 |
| Confluence | Not used | +5 if high-confluence signals have WR >= 55% |
| TF-specific | Used merged stats | Prefers TF-specific stats when available |
D1 Forward Window Fix
D1 forward evaluation was only 5 candles (5 trading days). Since D1 ATR-based SL/TP often needs 2-4 weeks to resolve, this produced meaningless D1 stats (avg_max_r = 0.12R was an artifact). Now set to 20 candles (4 trading weeks).
Wilder's ATR Smoothing
ATR now uses Wilder's exponential smoothing (alpha = 1/period) instead of simple moving average. This matches MT5's built-in ATR indicator and the industry standard. The difference from SMA can be 5-15% on SL/TP sizing.
How Backtest Stats Flow Into the Live Scanner
- Backtest creates per-TF CSV files and the enriched
latest_stats_multitf.json(includes per-TF patterns, sessions, cross-stats, confluence breakdown) - Live scanner calls
load_latest_backtest_stats()at startup, which:- Reads
latest_stats_multitf.json— if it has per-TF pattern/session/cross data (v7+), loads directly without CSV parsing - Falls back to CSV parsing only for older JSON formats
- Caches results for 4 hours (configurable via
stats_cache_hours)
- Reads
- Dashboard displays: overall WR, per-TF WR table, pattern tiers with per-TF columns, session quality, top cross-stats, avoid list, recommended setups
- Each live signal is enriched with: pattern tier badge, quality summary line, Prob(TP), historical edge breakdown, TF-specific signal score, and confluence context
Important
: The D1 trend filter setting must match between backtest and live mode. If you run the backtest with
--d1-trend-filter(default), run live with--mode live(also default). If you run backtest with--no-d1-trend-filter, run live with--no-d1-trend-filter.
Configuration
Command-Line Arguments
| Argument | Description | Default |
|---|---|---|
--symbol |
Trading symbol | EURUSD |
--timeframes |
Active timeframes | M5 M15 H1 H4 D1 |
--atr |
ATR period | 14 |
--sl |
Stop loss multiplier (x ATR) | 1.5 |
--tp |
Take profit multiplier (x ATR) | 1.5 |
--forward |
Forward evaluation candles | Scaled per TF |
--d1-trend-filter |
Require D1 SMA trend alignment | True |
--no-d1-trend-filter |
Disable D1 trend filter | |
--d1-sma-period |
D1 trend SMA period | 20 |
--volume-filter |
Enable volume confirmation | False |
--no-volume-filter |
Disable volume filter (default) | |
--volume-ma-period |
Volume MA period | 20 |
--volume-threshold |
Volume threshold ratio | 1.0 |
--account-balance |
Account size for position sizing | 100000 |
--risk-percent |
Risk % of account per trade | 1.0 |
--min-signal-score |
Minimum signal score to display (0-100) | 0 |
--alert-only-strong |
Only alert on strong signals | False |
--test-sound |
Play STRONG BUY and STRONG SELL test beeps, then exit | |
--output |
Backtest output directory | ./backtest_results |
CFG Config (in script)
These are set in the CFG dict at the top of the script:
| Key | Default | Description |
|---|---|---|
rr_by_pattern |
{} |
Variable R:R overrides — map pattern name to TP multiplier |
sound_enabled |
True |
Master switch for sound alerts |
sound_buy_hz |
1200 |
Hz for STRONG BUY triple beep |
sound_sell_hz |
400 |
Hz for STRONG SELL triple beep |
sound_beep_duration |
150 |
Duration per beep in ms |
sound_beep_pause |
100 |
Pause between beeps in ms |
sound_strong_threshold |
65.0 |
Min signal score to trigger sound |
Pattern Thresholds
| Argument | Description | Default |
|---|---|---|
--doji-body-ratio |
Max body/shadow ratio for Doji | 0.1 |
--spinning-top-body-ratio |
Max body ratio for Spinning Top | 0.33 |
--marubozu-wick-ratio |
Max wick ratio for Marubozu | 0.05 |
--hammer-lower-wick-ratio |
Min lower wick ratio for Hammer | 0.6 |
--hammer-upper-wick-ratio |
Max upper wick ratio for Hammer | 0.33 |
--long-candle-ratio |
Min body/shadow ratio for long candle | 0.6 |
--small-candle-ratio |
Max body/shadow ratio for small candle | 0.3 |
--tweezer-tolerance |
Tweezer tolerance in pips | 0.5 |
See --help for the full list of arguments.
Signal Scoring System (v7)
Each live signal is scored 0-100 based on:
| Factor | Description |
|---|---|
| Base score | Raw pattern win rate (0-100) |
| Sample penalty | -15 to 0 based on sample size (0 at 30+ signals, -20 below minimum) |
| Session gradient | Proportional bonus/penalty based on session WR (e.g., +8 at 60% WR, -8 at 40% WR) |
| Confluence bonus | +5 if high-confluence signals (score >= 3) have WR >= 55% |
| Tier bonus | +5 for Tier A, +3 for Tier B |
| MFE bonus | +1 for avg_max_r >= 0.5, +3 for >= 0.8 |
Per-TF scoring: When tf_label is available (live scanner), the score prefers TF-specific pattern stats over merged aggregate stats. A Bullish Engulfing on H4 (58% WR) gets a different score than the same pattern on M5 (52% WR).
Patterns below --min-signal-score are filtered out (default: 0, i.e. show all).
Pattern Tiers
| Tier | WR Range | Meaning |
|---|---|---|
| A: ELITE | >= 58% AND n >= 30 AND avg_max_r >= 0.35 | Highest edge, trade with confidence |
| B: TRADEABLE | >= 50% AND n >= 10 AND avg_max_r >= 0.25 | Solid edge, reliable setups |
| C: MARGINAL | >= 40% | Use only with strong confluence |
| D: AVOID | < 40% OR insufficient data | Negative edge, skip these |
Output Files
Backtest Results (./backtest_results/)
| File | Description |
|---|---|
EURUSD_{TF}_{date}_to_{date}_detections.csv |
Every pattern detected with entry, SL, TP, outcome, R-levels, MAE/MFE, RSI, S/R context, confluence score |
EURUSD_{TF}_{date}_to_{date}_pattern_summary.csv |
Per-pattern stats: WR, signals, SL/TP hit %, R-level hit rates, avg MAE/MFE, avg confluence |
EURUSD_{TF}_{date}_to_{date}_session_summary.csv |
Per-session stats: WR, signals, avg SL, TP hit % |
EURUSD_{TF}_{date}_to_{date}_report.txt |
Human-readable text report |
latest_stats_multitf.json |
Enriched per-TF stats cache: overall, patterns, sessions, cross, confluence breakdown |
New Detection CSV Columns (v7)
| Column | Description |
|---|---|
Bars_to_SL |
Number of forward candles until SL hit (None if not hit) |
Bars_to_TP |
Number of forward candles until TP hit (None if not hit) |
MAE_R |
Max Adverse Excursion in R-multiples |
MFE_R |
Max Favorable Excursion in R-multiples |
RSI |
RSI(14) value at the signal candle |
Near_Support |
True if price within 1 ATR of a swing low |
Near_Resistance |
True if price within 1 ATR of a swing high |
At_Swing_Low |
True if candle low is the lowest in lookback window |
At_Swing_High |
True if candle high is the highest in lookback window |
Confluence_Score |
0-7 confluence score |
Confluence_Factors |
Pipe-separated list of contributing factors (e.g., trend|d1_trend|support) |
RR_Override |
Pattern name if variable R:R was applied, empty string otherwise |
Session Classification
| Session | Broker Time (UTC+2/3) | Description |
|---|---|---|
| Pacific | 00:00 - 07:00 | Low liquidity, Sydney/Tokyo overlap |
| Asia | 07:00 - 00:00 | Tokyo session |
| London Open | 07:00 - 09:00 | High volatility London open |
| London Morning | 09:00 - 12:00 | Active London morning |
| London/NY Overlap | 12:00 - 17:00 | Highest liquidity window |
| NY Afternoon | 17:00 - 21:00 | NY afternoon, declining volume |
Timezone Notes
- Log timestamps (
[HH:MM:SS]) use your local computer time - Candle close times and "Next:" candle times use broker server time
- Session classification uses broker server time hours
- This means candle times will differ from your local clock by your timezone offset