Files
mt5-candlestick-scanner-bac…/README.md
T
2026-05-17 15:16:12 +01:00

491 lines
22 KiB
Markdown

# 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_pattern` dict 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.json` now 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
1. **Install MetaTrader 5**
2. **Install Python dependencies**:
```bash
pip install MetaTrader5 pandas numpy colorama python-dotenv
```
3. Copy `mt5_multitf_pattern_scanner.py` into your project folder.
4. Create a `.env` file in the same directory as the script:
```ini
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.**
```bash
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
```bash
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](#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.
```bash
# 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.
```bash
python mt5_multitf_pattern_scanner.py --mode backtest --bars 500
```
### Live Scanner
```bash
# 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.
```bash
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.
```bash
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:
```bash
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-filter` is 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`:
```python
'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 low
- `Near_Resistance` — price within 1 ATR of a swing high
- `At_Swing_Low` — candle low is the lowest in the lookback window
- `At_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:
```json
{
"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
1. **Backtest** creates per-TF CSV files and the enriched `latest_stats_multitf.json` (includes per-TF patterns, sessions, cross-stats, confluence breakdown)
2. **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`)
3. **Dashboard** displays: overall WR, per-TF WR table, pattern tiers with per-TF columns, session quality, top cross-stats, avoid list, recommended setups
4. **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