231 lines
No EOL
12 KiB
Markdown
231 lines
No EOL
12 KiB
Markdown
# 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 of `high - max(open, close)`
|
|
- `g_AvgLowerWick` — mean of `min(open, close) - low`
|
|
- `g_AvgRange` — mean of `high - 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 body
|
|
- `OBJ_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
|
|
|
|
1. Copy `ForwardSimEngine.mq5` to your MetaTrader 5 data folder:
|
|
```
|
|
MQL5/Indicators/ForwardSimEngine.mq5
|
|
```
|
|
2. Open MetaEditor (F4 in MT5) and compile the file (F7).
|
|
3. In the MT5 Navigator panel under Custom Indicators, drag the indicator onto a chart.
|
|
4. Recommended timeframe: **M15**.
|
|
5. Configure inputs and click OK.
|
|
6. 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 = false` and draw an `OBJ_VLINE` named `FSE_Anchor` on 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 |