| .. | ||
| ForwardSimEngien.mq5 | ||
| README.md | ||
ForwardSimEngine.mq5
EMA Crossover Forward Simulation Indicator — Synthetic Candles
This repository contains a custom MQL5 indicator built as a forward simulation engine. It does not claim to reproduce any third-party source code. All logic is original and derived from the accompanying article series.
Overview
This project implements a chart-native forward projection indicator for MetaTrader 5. The system detects EMA crossover signals on closed bars and immediately projects a sequence of synthetic OHLC candles into the future time slots of the chart.
The architecture is built around three independent modules:
- a Signal and Calibration module that detects crossovers, latches state, and measures real candle metrics from history
- a Prediction Engine that generates synthetic OHLC candles using the measured baseline, a sine-wave size envelope, and counter-trend injection
- a Renderer that draws each candle as chart objects and removes the leading projected candle as each new real candle closes
The indicator is designed for the M15 timeframe but adapts automatically to any timeframe via PeriodSeconds().
Original Article
| Field | Value |
|---|---|
| Article Title | Creating an EMA Crossover Forward Simulation Indicator in MQL5 |
| Author | johnhlomohang |
| Publication Date | 2026.05.13 |
| Category | Indicators |
| Article URL | https://www.mql5.com/en/articles/22323 |
| Part 1 URL | "This is part 1" |
Repository Purpose
This repository should be treated as a reference project accompanying the published article. Its purpose is to:
- preserve the full indicator source for study and extension
- document every input parameter and its effect
- serve as a base for replacing the EMA detector with structure-based or volatility-based triggers
- demonstrate the object-lifecycle, calibration, and rendering patterns described in the article series
Key Concepts
- fast and slow EMA crossover detection on fully closed bars
- automatic anchor placement at the crossover bar
- average candle body and wick measurement from recent price history
- EMA slope as a momentum scale factor (0.5× – 1.5×) applied on top of the measured baseline
- sine-wave body-size envelope producing organic variation across the projection
- exponential decay flattening the projection toward the tail
- counter-trend candle injection every N bars for realistic pullbacks
- wick lengths derived from measured wick-to-body ratios
- inter-candle spacing via time-inset OBJ_RECTANGLE bodies
- pip-based signal invalidation with automatic object cleanup
- interactive projection: the leading synthetic candle is removed as each real candle closes
- dual-mode anchoring: automatic (tracks crossover bar) or manual (user-placed OBJ_VLINE)
Algorithm and Architecture Summary
Signal Detection
OnCalculate runs on every tick. The two most recently closed bars (index rates_total-2 and rates_total-3) are compared. A bullish signal is latched when the fast EMA crosses above the slow EMA between those two bars. A bearish signal is latched on the reverse cross. Each new signal resets the drawn state and triggers a calibration refresh.
Calibration
CalcAvgCandleMetrics reads the last AvgLookback closed bars using CopyOpen, CopyHigh, CopyLow, CopyClose starting at shift 1 (skipping the live forming bar). It computes:
g_AvgBody— mean of|close - open|g_AvgUpperWick— mean ofhigh - max(open, close)g_AvgLowerWick— mean ofmin(open, close) - lowg_AvgRange— mean ofhigh - low
All values are floored at 1 pip to prevent collapse in flat markets. The function runs once at OnInit and again on each new crossover signal.
Prediction Engine
GeneratePrediction builds the PredictedCandle[] array. Each candle body size is computed as:
bodySize = avgBody × momentumScale × sin²(phase) × 0.93^i × jitter
where momentumScale maps the EMA slope to the range [0.5, 1.5], the sine-squared term pulses sizes across the projection, 0.93^i is the exponential decay, and jitter adds ±8% noise. Every CounterCandleFreq bars a counter-trend candle is injected at 25–45% of the trend body size. Wick lengths use the avgWick / avgBody ratio with ±25% jitter and a 20% floor.
Rendering
DrawAllCandles places each synthetic candle one bar-width into the future relative to the anchor, inset by CandleGapFraction on each side for visible spacing. Each candle is drawn as:
OBJ_RECTANGLE— filled bodyOBJ_RECTANGLE— body outline (unfilled)OBJ_TREND× 2 — upper and lower wicks, centred on the full bar slot
Supporting objects include a dashed OBJ_VLINE separator at the anchor, an OBJ_TEXT zone label, and an OBJ_TEXT invalidation notice.
Invalidation
On every tick, the live bar's close is compared against the signal price. If a bullish projection's live price drops more than InvalidationPips below the signal price, or a bearish projection's live price rises more than InvalidationPips above it, all objects are deleted, an invalidation label is drawn, and the engine waits silently for the next valid cross.
Interactive Removal
OnCalculate detects when rates_total increases by one, meaning a new real bar has closed. At that point the object group for FutureCandle_0 is deleted and the remaining projected candles shift down by one index. The projection is always anchored exactly one bar ahead of the current live bar.
Attached Files
| File | Description |
|---|---|
ForwardSimEngine.mq5 |
The complete MQL5 custom indicator |
Input Parameters
| Parameter | Default | Description |
|---|---|---|
FastEMA_Period |
9 | Period of the fast EMA |
SlowEMA_Period |
21 | Period of the slow EMA |
FutureBars |
30 | Number of synthetic candles to project |
SpreadMultiplier |
2.0 | Secondary wick size multiplier (used as floor before calibration) |
AutoAnchor |
true | Auto-place anchor at the crossover bar; false = manual OBJ_VLINE |
AnchorLineName |
"FSE_Anchor" | Name of the anchor vertical line chart object |
BullishColor |
DodgerBlue | Body fill color for bullish projected candles |
BearishColor |
Crimson | Body fill color for bearish projected candles |
WickColor |
DimGray | Color for upper and lower wick lines |
ShowZoneLabel |
true | Show the [ BULLISH PROJECTION ] / [ BEARISH PROJECTION ] label |
ShowSeparatorLine |
true | Show a dashed vertical line at the anchor bar |
InvalidationPips |
10 | Pip distance from signal price that triggers projection removal |
CandleGapFraction |
0.08 | Gap between candles as a fraction of bar width (range: 0.04–0.20) |
CounterCandleFreq |
4 | Insert one counter-trend candle every N candles (minimum: 3) |
AvgLookback |
50 | Number of recent closed bars used to measure average candle size |
Chart Object Naming Convention
All drawn objects use consistent prefixes so ObjectsDeleteAll can remove them cleanly in bulk.
| Prefix | Object type |
|---|---|
FutureCandle_N_body |
Filled rectangle — candle body |
FutureCandle_N_bord |
Unfilled rectangle — body outline |
FutureCandle_N_wU |
Trend line — upper wick |
FutureCandle_N_wD |
Trend line — lower wick |
FSE_Sep |
Dashed vertical separator |
FSE_Label |
Projection zone label text |
FSE_Invalid |
Invalidation notice text |
FSE_Anchor |
Gold dash-dot anchor vertical line |
Statistics
| Metric | Value |
|---|---|
| Indicator type | Chart window overlay |
| Plot buffers | 2 (Fast EMA, Slow EMA) |
| Crossover bars evaluated | 2 (last two closed bars) |
| Default projection length | 30 bars |
| Default calibration lookback | 50 bars |
| Exponential decay base | 0.93 per bar |
| Sine envelope range | 0.40× – 1.30× baseStep |
| Momentum scale range | 0.5× – 1.5× avgBody |
| Counter-trend retrace range | 25% – 45% of body |
| Wick minimum floor | 20% of body height |
| Timer interval | 3 seconds (manual anchor) |
| Chart objects per candle | 4 |
Installation
- Copy
ForwardSimEngine.mq5to your MetaTrader 5 data folder:MQL5/Indicators/ForwardSimEngine.mq5 - Open MetaEditor (F4 in MT5) and compile the file (F7).
- In the MT5 Navigator panel under Custom Indicators, drag the indicator onto a chart.
- Recommended timeframe: M15.
- Configure inputs and click OK.
- Open the Experts tab in the terminal to confirm the
[INIT]and[AVG]log lines appear.
Tuning Notes
AvgLookback— increase to 100+ for a smoother long-run average. Lower to 20–30 to react faster to recent volatility shifts such as news events.InvalidationPips— increase on wide-spread instruments (XAUUSD, GBPJPY) to avoid premature removal. Lower on tight instruments (EURUSD, USDJPY) for stricter invalidation.CandleGapFraction— 0.08 works well on M15. Increase to 0.12–0.15 on higher timeframes where bar width appears wider on screen.CounterCandleFreq— set to 3 for more frequent pullbacks. Set to 6–8 for a cleaner directional sequence.FutureBars— keep at or below 60. Above that, the exponential decay reduces later candles to near the floor size and the projection becomes visually flat.- Manual anchor — set
AutoAnchor = falseand draw anOBJ_VLINEnamedFSE_Anchoron any past bar to replay the projection from that point.
Limitations
- The projection is a structured visual scenario, not a price forecast. It does not use volume, order flow, or market microstructure data.
- Signal detection is limited to EMA crossovers on closed bars. Intra-bar crosses are ignored until the bar closes.
- The invalidation threshold is fixed in pips. It does not adapt dynamically to ATR or recent volatility.
- The indicator does not place, manage, or close any trades. It is a visualization tool only.
- Wick and body calibration depends on the quality and quantity of history available on the active symbol and timeframe.
Tags
MQL5 MetaTrader5 CustomIndicator ForwardSimulation EMA Crossover SyntheticCandles ChartObjects Projection Visualization AlgorithmicTrading
Difficulty
Intermediate — Advanced
Requires familiarity with:
- MQL5 indicator development (
OnCalculate,SetIndexBuffer,CopyBuffer) - Chart object creation and lifecycle management (
ObjectCreate,ObjectDelete,ObjectsDeleteAll) - MQL5 array indexing conventions (series vs non-series layout)
- Basic EMA crossover concepts
- MetaTrader 5 Strategy Tester for validation
Reference
Original article series: https://www.mql5.com/en/articles/22323