Skip to content
All library documents

Triple MACD Scalping with Staged Momentum Confirmation

Article Strategy library · Author: geraked

Summary

This scalping system combines three MACD readings with progressively slower fast and slow periods. Its long and short rules look for momentum alignment across the slow indicators, then inspect recent history for zero-line crossings and turning points in faster indicators. Trades are evaluated once per new candle, with position, margin, spread, and optional news filters controlling whether new entries may be opened. The source describes an AUD/USD five-minute strategy and gives a historical period in its metadata, but it supplies no backtest performance figures.

Stops can be based on recent swing structure, while targets are set as a multiple of the stop distance. The implementation also exposes trailing stops, grid trading, position risk, and drawdown controls. Those settings create meaningful dependencies on the included trading framework and chosen configuration; the document does not explain their full behavior or establish that the strategy is profitable. The long historical pattern checks are specific and complex, so their robustness across instruments and market regimes remains unshown.

Key ideas

  • Three MACD configurations provide a hierarchy of slower trend context and faster entry timing.
  • Long and short signals require aligned indicator signs plus historical zero crossings and local turns.
  • The system checks entry conditions on new candles and can apply spread, margin, and open-position limits.
  • Stops use swing-based logic by default, while the profit target is a multiple of stop distance.
  • Grid, trailing, risk, news, and drawdown controls are configurable, but performance evidence is absent.

Tags

Full text
# 3MACD


# 3MACD









## Source (MIT)

```mql5
//+------------------------------------------------------------------+
//|                                                        3MACD.mq5 |
//|                                          Copyright 2023, Geraked |
//|                                       https://github.com/geraked |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2023, Geraked"
#property link        "https://github.com/geraked"
#property version     "1.4"
#property description "A strategy using triple MACDs for scalping"
#property description "AUDUSD-5M  2021.02.22 - 2023.09.26"

#include <EAUtils.mqh>

input group "Indicator Parameters"
input int M1Fast = 5; // MACD1 Fast
input int M1Slow = 8; // MACD1 Slow
input int M2Fast = 13; // MACD2 Fast
input int M2Slow = 21; // MACD2 Slow
input int M3Fast = 34; // MACD3 Fast
input int M3Slow = 144; // MACD3 Slow

input group "General"
input double TPCoef = 2.0; // TP Coefficient
input ENUM_SL SLType = SL_SWING; // SL Type
input int SLLookback = 7; // SL Look Back
input int SLDev = 60; // SL Deviation (Points)
input int BuffSize = 32; // Buffer Size
input bool Reverse = true; // Reverse Signal

input group "Risk Management"
input double Risk = 0.5; // Risk
input ENUM_RISK RiskMode = RISK_DEFAULT; // Risk Mode
input bool IgnoreSL = true; // Ignore SL
input bool IgnoreTP = true; // Ignore TP
input bool Trail = true; // Trailing Stop
input double TrailingStopLevel = 50; // Trailing Stop Level (%) (0: Disable)
input double EquityDrawdownLimit = 0; // Equity Drawdown Limit (%) (0: Disable)

input group "Strategy: Grid"
input bool Grid = true; // Grid Enable
input double GridVolMult = 1.0; // Grid Volume Multiplier
input double GridTrailingStopLevel = 0; // Grid Trailing Stop Level (%) (0: Disable)
input int GridMaxLvl = 50; // Grid Max Levels

input group "News"
input bool News = false; // News Enable
input ENUM_NEWS_IMPORTANCE NewsImportance = NEWS_IMPORTANCE_MEDIUM; // News Importance
input int NewsMinsBefore = 60; // News Minutes Before
input int NewsMinsAfter = 60; // News Minutes After
input int NewsStartYear = 0; // News Start Year to Fetch for Backtesting (0: Disable)

input group "Open Position Limit"
input bool OpenNewPos = true; // Allow Opening New Position
input bool MultipleOpenPos = false; // Allow Having Multiple Open Positions
input double MarginLimit = 300; // Margin Limit (%) (0: Disable)
input int SpreadLimit = -1; // Spread Limit (Points) (-1: Disable)

input group "Auxiliary"
input int Slippage = 30; // Slippage (Points)
input int TimerInterval = 30; // Timer Interval (Seconds)
input ulong MagicNumber = 5000; // Magic Number
input ENUM_FILLING Filling = FILLING_DEFAULT; // Order Filling

GerEA ea;
datetime lastCandle;
datetime tc;

int M1_handle, M2_handle, M3_handle;
double M1[], M2[], M3[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool BuySignal() {
    if (M3[1] > 0 && M2[1] > 0 && M2[2] > 0 && M2[3] > 0 && M2[1] > M2[2] && M2[2] < M2[3]) {
        int j = 0;
        int k = 0;

        for (int i = 2; i < BuffSize - 1; i++) {
            if (M3[i] <= 0 || M3[i + 1] <= 0) return false;
            if (M2[i] <= 0 || M2[i + 1] <= 0) return false;
            if (M1[i] < 0 && M1[i + 1] > 0) {
                j = i + 1;
                break;
            }
        }

        if (j == 0) return false;

        for (int i = j; i < BuffSize - 2; i++) {
            if (M3[i] <= 0 || M3[i + 1] <= 0 || M3[i + 2] <= 0) return false;
            if (M2[i] <= 0 || M2[i + 1] <= 0 || M2[i + 2] <= 0) return false;
            if (M2[i] < M2[i + 1] && M2[i + 1] > M2[i + 2]) {
                k = i + 1;
                break;
            }
        }

        if (k == 0) return false;
    }

    else if (M3[1] > 0 && M3[2] > 0 && M3[3] > 0 && M3[1] > M3[2] && M3[2] < M3[3]) {
        int j = 0;
        int k = 0;
        int m = 0;

        for (int i = 2; i < BuffSize - 1; i++) {
            if (M3[i] <= 0 || M3[i + 1] <= 0) return false;
            if (M2[i] < 0 && M2[i + 1] > 0) {
                j = i + 1;
                break;
            }
        }

        if (j == 0) return false;

        for (int i = j; i < BuffSize - 1; i++) {
            if (M3[i] <= 0 || M3[i + 1] <= 0) return false;
            if (M2[i] <= 0 || M2[i + 1] <= 0) return false;
            if (M1[i] < 0 && M1[i + 1] > 0) {
                k = i + 1;
                break;
            }
        }

        if (k == 0) return false;

        for (int i = k; i < BuffSize - 2; i++) {
            if (M3[i] <= 0 || M3[i + 1] <= 0 || M3[i + 2] <= 0) return false;
            if (M2[i] <= 0 || M2[i + 1] <= 0 || M2[i + 2] <= 0) return false;
            if (M2[i] < M2[i + 1] && M2[i + 1] > M2[i + 2]) {
                m = i + 1;
                break;
            }
        }

        if (m == 0) return false;
    }

    else {
        return false;
    }

    double in = Ask();
    double sl = BuySL(SLType, SLLookback, in, SLDev, 1);
    double tp = in + TPCoef * MathAbs(in - sl);
    ea.BuyOpen(in, sl, tp, IgnoreSL, IgnoreTP);
    return true;
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool SellSignal() {
    if (M3[1] < 0 && M2[1] < 0 && M2[2] < 0 && M2[3] < 0 && M2[1] < M2[2] && M2[2] > M2[3]) {
        int j = 0;
        int k = 0;

        for (int i = 2; i < BuffSize - 1; i++) {
            if (M3[i] >= 0 || M3[i + 1] >= 0) return false;
            if (M2[i] >= 0 || M2[i + 1] >= 0) return false;
            if (M1[i] > 0 && M1[i + 1] < 0) {
                j = i + 1;
                break;
            }
        }

        if (j == 0) return false;

        for (int i = j; i < BuffSize - 2; i++) {
            if (M3[i] >= 0 || M3[i + 1] >= 0 || M3[i + 2] >= 0) return false;
            if (M2[i] >= 0 || M2[i + 1] >= 0 || M2[i + 2] >= 0) return false;
            if (M2[i] > M2[i + 1] && M2[i + 1] < M2[i + 2]) {
                k = i + 1;
                break;
            }
        }

        if (k == 0) return false;
    }

    else if (M3[1] < 0 && M3[2] < 0 && M3[3] < 0 && M3[1] < M3[2] && M3[2] > M3[3]) {
        int j = 0;
        int k = 0;
        int m = 0;

        for (int i = 2; i < BuffSize - 1; i++) {
            if (M3[i] >= 0 || M3[i + 1] >= 0) return false;
            if (M2[i] > 0 && M2[i + 1] < 0) {
                j = i + 1;
                break;
            }
        }

        if (j == 0) return false;

        for (int i = j; i < BuffSize - 1; i++) {
            if (M3[i] >= 0 || M3[i + 1] >= 0) return false;
            if (M2[i] >= 0 || M2[i + 1] >= 0) return false;
            if (M1[i] > 0 && M1[i + 1] < 0) {
                k = i + 1;
                break;
            }
        }

        if (k == 0) return false;

        for (int i = k; i < BuffSize - 2; i++) {
            if (M3[i] >= 0 || M3[i + 1] >= 0 || M3[i + 2] >= 0) return false;
            if (M2[i] >= 0 || M2[i + 1] >= 0 || M2[i + 2] >= 0) return false;
            if (M2[i] > M2[i + 1] && M2[i + 1] < M2[i + 2]) {
                m = i + 1;
                break;
            }
        }

        if (m == 0) return false;
    }

    else {
        return false;
    }

    double in = Bid();
    double sl = SellSL(SLType, SLLookback, in, SLDev, 1);
    double tp = in - TPCoef * MathAbs(in - sl);
    ea.SellOpen(in, sl, tp, IgnoreSL, IgnoreTP);
    return true;
}


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    ea.Init();
    ea.SetMagic(MagicNumber);
    ea.risk = Risk * 0.01;
    ea.reverse = Reverse;
    ea.trailingStopLevel = TrailingStopLevel * 0.01;
    ea.grid = Grid;
    ea.gridVolMult = GridVolMult;
    ea.gridTrailingStopLevel = GridTrailingStopLevel * 0.01;
    ea.gridMaxLvl = GridMaxLvl;
    ea.equityDrawdownLimit = EquityDrawdownLimit * 0.01;
    ea.slippage = Slippage;
    ea.news = News;
    ea.newsImportance = NewsImportance;
    ea.newsMinsBefore = NewsMinsBefore;
    ea.newsMinsAfter = NewsMinsAfter;
    ea.filling = Filling;
    ea.riskMode = RiskMode;

    if (RiskMode == RISK_FIXED_VOL || RiskMode == RISK_MIN_AMOUNT) ea.risk = Risk;
    if (News) fetchCalendarFromYear(NewsStartYear);

    M1_handle = iMACD(NULL, 0, M1Fast, M1Slow, 1, PRICE_CLOSE);
    M2_handle = iMACD(NULL, 0, M2Fast, M2Slow, 1, PRICE_CLOSE);
    M3_handle = iMACD(NULL, 0, M3Fast, M3Slow, 1, PRICE_CLOSE);

    if (M1_handle == INVALID_HANDLE || M2_handle == INVALID_HANDLE || M3_handle == INVALID_HANDLE) {
        Print("Runtime error = ", GetLastError());
        return INIT_FAILED;
    }

    EventSetTimer(TimerInterval);
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    EventKillTimer();
}

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {
    datetime oldTc = tc;
    tc = TimeCurrent();
    if (tc == oldTc) return;

    if (Trail) ea.CheckForTrail();
    if (EquityDrawdownLimit) ea.CheckForEquity();
    if (Grid) ea.CheckForGrid();
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    if (lastCandle != Time(0)) {
        lastCandle = Time(0);

        if (CopyBuffer(M1_handle, 0, 0, BuffSize, M1) <= 0) return;
        if (CopyBuffer(M2_handle, 0, 0, BuffSize, M2) <= 0) return;
        if (CopyBuffer(M3_handle, 0, 0, BuffSize, M3) <= 0) return;

        ArraySetAsSeries(M1, true);
        ArraySetAsSeries(M2, true);
        ArraySetAsSeries(M3, true);

        if (!OpenNewPos) return;
        if (SpreadLimit != -1 && Spread() > SpreadLimit) return;
        if (MarginLimit && PositionsTotal() > 0 && AccountInfoDouble(ACCOUNT_MARGIN_LEVEL) < MarginLimit) return;
        if ((Grid || !MultipleOpenPos) && ea.OPTotal() > 0) return;

        if (BuySignal()) return;
        SellSignal();
    }
}

//+------------------------------------------------------------------+

```

Shown in full with attribution under the source's licence. Licence: MIT

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.