MQL5 SMC Confluence Filter
A confluence filter does not create a new structure event. It decides whether an existing break deserves display, an alert or an EA signal. The filter must be computed from the same closed bar as the break, otherwise it can repaint the decision.
1. Candle confluence compares wick lengths
The reference confluence filter compares the upper wick with the lower wick. It is not a prediction; it rejects a break when the rejection wick on the wrong side dominates. The comparison is strict, so equal wicks fail.
bool BullishConfluence(const MqlRates &r[], int i)
{
double upper = r[i].high - MathMax(r[i].open, r[i].close);
double lower = MathMin(r[i].open, r[i].close) - r[i].low;
return upper < lower;
}
bool BearishConfluence(const MqlRates &r[], int i)
{
double upper = r[i].high - MathMax(r[i].open, r[i].close);
double lower = MathMin(r[i].open, r[i].close) - r[i].low;
return upper > lower;
}
Use the same function on the closed break bar for history and for the live decision. Do not compute a different proxy in the EA.
2. Level equality must match the structure definition
A break is stronger when the level has already been tested. But “equal” needs a tolerance. A fixed price tolerance fails across instruments; an ATR-normalised tolerance adapts to volatility.
bool NearLevel(double a, double b, double tolerance)
{
return MathAbs(a - b) < tolerance;
}
double tolerance = atr * 0.10;
The reference uses ATR(200) and a strict < comparison. A difference exactly equal to the tolerance is not equal. The same boundary rule must appear in drawing, alerts and tests.
3. Internal/swing agreement is a context filter
A swing bullish BOS while the internal trend is bearish can still be valid, but it means the market is pulling back inside a larger move. The filter can require internal alignment, or it can display both states without rejecting the event.
- Strict: swing event only when internal trend agrees.
- Contextual: draw the event but label the conflict.
- Never: silently replace the swing trend with the internal trend.
For an EA, expose both trends. A strategy can require alignment; a research tool should not hide the conflict.
4. A filter should not change the event timestamp
Keep the break event on its original bar. If the confluence filter fails, mark the event as filtered; do not move it to a later bar. Moving events makes parity tests fail and makes historical charts look better than real-time behaviour.
if(bullishBreak && !BullishConfluence(rates, bar))
{
event.filtered = true;
event.reason = "weak bullish confluence";
}
else if(bullishBreak)
{
event.filtered = false;
event.reason = "confirmed break";
}
5. Test cases
| Case | Expected |
|---|---|
| Lower wick larger than upper wick | Bullish confluence passes |
| Upper wick larger than lower wick | Bearish confluence passes |
| Upper and lower wicks equal | Both comparisons fail because they are strict |
| Level difference exactly at tolerance | Rejected under the strict < rule |
| Internal and swing conflict | Do not silently overwrite swing trend |
| Filter fails | Event remains on its original bar and is marked filtered |
Test the filter with the Order Block Filter and the Object Parity Checker before wiring it to an EA.
FAQ
Is confluence necessary?
No. It is a design choice. It reduces event count and changes the historical distribution.
Should filtered events still alert?
Only if the alert is explicitly labelled as a filtered event. Otherwise the alert stream becomes inconsistent.
What is the safest default?
Closed-bar break, strict wick comparison and ATR(200)-relative level tolerance.
Previous: Internal vs SwingNext: Trend ColoringSMC Lab
Educational content. Test thresholds on fixed fixtures.