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.
- **Trade management modes** — `fixed` (static SL/TP), `breakeven` (move SL to entry at 1R), `trail` (ATR-based trailing stop), `partial` (close 50% at 1R, trail remainder)
- **Structure-based SL placement** — place stops at pattern invalidation levels (below Hammer low, below Engulfing candle extreme, etc.) instead of generic ATR offsets
- **Equity curve & drawdown** — sequential P&L simulation with max drawdown, Sharpe ratio, Calmar ratio, profit factor, and consecutive win/loss streaks
- **Timeout classification** — choose between `marginal` (Marginal_Win/Loss based on close vs entry) or `expired` (flat 0R for all timeouts) for honest win rate reporting
- **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
- **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
- **Tier-aware sound alerts** (Windows only) — high-Hz triple beep for STRONG BUY, low-Hz triple beep for STRONG SELL; Tier A (Elite) always fires, Tier B only if score ≥ `sound_alert_tier_b_min_score` (default 60), Tier C/D never; starts muted, type `m` + Enter to toggle
- **Auto-detected broker UTC offset** — broker UTC offset is auto-detected at startup by comparing the latest MT5 candle time against true UTC; handles DST transitions automatically; falls back to `broker_utc_offset` config value if detection fails
- **Local time display** — candle close times and "Next close" countdowns are converted from broker time to local machine time for display; log timestamps always use local time
**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.**
- `latest_stats_multitf.json` — the enriched stats cache the live scanner loads at startup (now includes per-TF patterns, sessions, cross-stats, confluence breakdown, and equity curve metrics)
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.
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.
| `sound_alert_tier_b_min_score` | `60.0` | Minimum signal score for Tier B patterns to trigger a sound alert |
---
## v9 Enhancements
### Massively Expanded Pattern Library (50+)
v9 adds 30+ new patterns across all candle counts, bringing the total to 50+:
**New single-candle patterns**: Dragonfly Doji, Gravestone Doji, Bullish Belt Hold, Bearish Belt Hold
**New two-candle patterns**: Near Engulfing, Piercing Line, Dark Cloud Cover, Bullish Kicker, Bearish Kicker, Meeting Lines (Bullish/Bearish), Bullish/Bearish Separating Lines, Bearish Doji Star
**New three-candle patterns**: Three Inside Up, Three Inside Down, Three Outside Up, Three Outside Down, Bullish Abandoned Baby, Bearish Abandoned Baby, Upside Gap Two Crows
**New four-candle patterns**: Bullish/Bearish Three Line Strike, Concealing Baby Swallow
**New five-candle patterns**: Mat Hold (Bullish/Bearish), Ladder Bottom
**TheStrat composite patterns**: 2-2 Continuation/Reversal, 3-1-2 Reversal, 2-1-2 Reversal, 1-2-2 Reversal, 1-3 Reversal — based on Rob Smith's TheStrat candle-type system (Type 1 = inside bar, Type 2 = directional break, Type 3 = outside bar)
New pattern thresholds are configurable in `CFG`:
| Key | Default | Description |
|---|---|---|
| `belt_hold_wick_ratio` | `0.1` | Max wick/body ratio for belt hold patterns |
| `kicker_min_body_ratio` | `0.6` | Min body ratio for kicker candles |
| `separating_lines_tolerance_pips` | `2` | Open price tolerance for separating lines |
| `meeting_lines_tolerance_pips` | `2` | Close price tolerance for meeting lines |
### Tier-Aware Sound Alerts
Sound alerts are now triggered based on pattern tier rather than a flat score threshold:
| Tier | Alert condition |
|---|---|
| A: ELITE | Always fires a sound alert |
| B: TRADEABLE | Fires only if signal score ≥ `sound_alert_tier_b_min_score` (default 60) |
| C: MARGINAL | Never fires |
| D: AVOID | Never fires |
This replaces the old `sound_strong_threshold` (65.0) flat cutoff. Configure via `sound_alert_tier` and `sound_alert_tier_b_min_score` in `CFG`.
### Auto-Detected Broker UTC Offset
At live scanner startup, the broker's UTC offset is automatically detected by comparing the timestamp of the latest MT5 candle against true UTC. This means DST transitions are handled correctly without any manual configuration change.
- The detected offset is logged at startup: `Timestamps: Local time (UTC+3, auto-detected broker UTC+3)`
- If detection fails, falls back to the `broker_utc_offset` value in `CFG` (default: 2)
- To disable auto-detection, set `broker_utc_offset` to `0` in `CFG`
### Local Time Display
Candle close times and "Next close" countdowns in the live scanner are now displayed in **local machine time** rather than broker server time. Log timestamps (`[HH:MM:SS]`) have always used local time — now the candle times match.
The conversion formula is: `local = broker_time − broker_utc_offset + local_utc_offset`
The backtest now supports four trade management modes that control how the stop loss is managed after entry:
| Mode | Behavior |
|---|---|
| `fixed` | Static SL/TP — original behavior, no adjustment (default) |
| `breakeven` | Move SL to entry price (breakeven) when price reaches `breakeven_at_r` R (default: 1.0R) |
| `trail` | After price reaches `trail_at_r` R (default: 1.5R), move SL to breakeven, then trail by `trail_atr_mult` x ATR behind price |
| `partial` | Close `partial_close_pct` (default: 50%) of position at `partial_close_r` R (default: 1.0R), move SL to breakeven for remainder, then trail |
All modes also support **time-based stop tightening**: if `time_stop_pct` (default: 0.7 = 70%) of the forward evaluation window elapses without TP, the SL is tightened to breakeven. This only activates in non-`fixed` modes.
New detection columns track trade management outcomes:
| Column | Description |
|---|---|
| `Exit_R` | Actual R-multiple at trade exit (accounts for BE moves, trailing, partial closes) |
| `SL_Moved_to_BE` | True if SL was moved to breakeven during the trade |
| `Partial_Closed` | True if a partial position was closed |
| `Remaining_Pct` | Fraction of position still open at exit (1.0 = full, 0.5 = half) |
### Structure-Based SL Placement
Instead of using a generic `candle_low - sl_mult * ATR` for every pattern, structure-based SL places the stop at the pattern's **natural invalidation level** — the price level that would invalidate the pattern's signal:
| Pattern | Bullish SL Placement |
|---|---|
| Hammer / Inverted Hammer | Below signal candle's low (the wick IS the pattern) |
| Morning Star | Below the lowest point of the 3-candle pattern |
| Three White Soldiers | Below the first candle's low |
| Bullish Engulfing | Below the engulfing candle's low |
- **Tighter stops** — pattern invalidation is often closer than 1.5x ATR, reducing risk per trade
- **Logical levels** — the stop has a reason (if the Hammer's low breaks, the pattern is invalidated)
- **Pattern-specific** — each pattern type gets its own optimal SL level
### Equity Curve & Drawdown Analysis
Each backtest timeframe now includes a **Section 8: Equity Curve & Drawdown** in the report, simulating sequential trading with 1R risk per trade and tracking cumulative P&L in R-multiples.
| Metric | Description |
|---|---|
| Final Equity | Total cumulative P&L in R-multiples |
| Max Drawdown | Largest peak-to-trough drawdown (R and %) |
| Max Consec Wins/Losses | Longest winning and losing streaks |
| Calmar Ratio | Annualised return / max drawdown |
| Avg Win/Loss R | Average R-multiple for wins and losses separately |
The equity curve uses the `Exit_R` column when available (v8 trade management), giving accurate P&L even with breakeven moves and partial closes. For `fixed` mode, it falls back to deriving R from the outcome type.
### Timeout Classification
By default, trades that reach the end of the forward evaluation window without hitting SL or TP are classified as `Marginal_Win` or `Marginal_Loss` based on whether the close is above or below entry. This inflates win rates by counting tiny gains (e.g. +0.2R) as full "wins".
The `--timeout-mode expired` option reclassifies all timeouts as `Expired` at 0R, giving an **honest win rate** that only counts actual TP vs SL outcomes:
| Mode | Timeout Outcome | Win Rate Meaning |
|---|---|---|
| `marginal` (default) | Marginal_Win (+0.1R to +0.5R) or Marginal_Loss (-0.1R to -0.5R) | Includes near-scratches as wins/losses |
| `expired` | Expired (0R) | Only real TP_Hit vs SL_Hit count |
python mt5_multitf_pattern_scanner.py --mode live --symbols EURUSD GBPUSD
```
By default, only EURUSD is scanned (preserving backward compatibility). The watchlist can also be configured in the `CFG` dict via the `watchlist` key.
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:
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.
> **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`.
| 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).