Page 1 of 1

Free Tool: VWAP + MACD Momentum Scalping Strategy & Custom Indicators (MT4 / MT5 / cTrader)

Posted: Sun Jul 26, 2026 3:38 pm
by PTScalper
Are you getting chopped up trying to scalp M1 and M5 charts during active London and New York sessions? Combining Volume Weighted Average Price (VWAP) with the MACD gives you a professional two-step filter: institutional trend direction plus momentum timing.

Most retail traders rely on exponential moving averages for trend bias, but MAs lag and ignore volume. VWAP acts as the true intraday value equilibrium. When price trades above daily VWAP, institutional buyers are in control; when below, sellers dominate. By forcing your scalp trades to align with this baseline, you immediately eliminate low-probability counter-trend setups.

The Scalping Strategy Rules:

Timeframes: M1 or M5 during high-liquidity windows (London/NY overlap).

Indicators: Daily Session VWAP + MACD (Fast: 6, Slow: 13, Signal: 5 for hyper-responsive execution, or standard 12, 26, 9).

Long Entry: Price must be above the Daily VWAP. Wait for the MACD line to cross above the Signal line (best when occurring below the zero level after a pullback).

Short Entry: Price must be below the Daily VWAP. Wait for the MACD line to cross below the Signal line.

Risk Management: Place protective stop losses 2 pips beyond the recent swing high/low or use a dynamic 1.5x ATR stop. Target a 1.5R to 2.0R risk-to-reward ratio.

To automate the chart reading, I coded custom overlay indicators for MT4, MT5, and IC Trader (cTrader) that print entry arrows when both conditions align. Grab the source code below!

MT4 (MQL4) Custom Indicator
This indicator calculates the daily session VWAP and monitors MACD crossovers, plotting Buy and Sell arrows directly on the main chart window.

Code: Select all

//+------------------------------------------------------------------+
//|                                             VWAP_MACD_Scalper.mq4|
//|                          VWAP + MACD On-Chart Arrow Scalping Tool|
//+------------------------------------------------------------------+
#property copyright "Free Open Source"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1  clrBlue
#property indicator_color2  clrLime
#property indicator_color3  clrRed
#property indicator_width1  1
#property indicator_width2  2
#property indicator_width3  2

//--- Input Parameters
input int      InpFastEMA   = 6;          // MACD Fast EMA
input int      InpSlowEMA   = 13;         // MACD Slow EMA
input int      InpSignalSMA = 5;          // MACD Signal SMA
input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // MACD Applied Price

//--- Indicator Buffers
double         VwapBuffer[];
double         BuyArrowBuffer[];
double         SellArrowBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    SetIndexBuffer(0, VwapBuffer);
    SetIndexStyle(0, DRAW_LINE);
    SetIndexLabel(0, "Daily VWAP");
    
    SetIndexBuffer(1, BuyArrowBuffer);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexArrow(1, 233); // Up arrow
    SetIndexLabel(1, "Buy Signal");
    SetIndexEmptyValue(1, 0.0);
    
    SetIndexBuffer(2, SellArrowBuffer);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexArrow(2, 234); // Down arrow
    SetIndexLabel(2, "Sell Signal");
    SetIndexEmptyValue(2, 0.0);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    if(rates_total < InpSlowEMA) return(0);
    
    int limit = rates_total - prev_calculated;
    if(prev_calculated > 0) limit++;
    else limit = rates_total - 1;
    
    double cumVolume = 0;
    double cumTypPriceVol = 0;
    int currentDay = -1;
    
    // Calculate from oldest to newest
    for(int i = limit; i >= 0; i--)
    {
        int barDay = TimeDay(time[i]);
        
        // Reset VWAP at the start of a new daily session
        if(barDay != currentDay)
        {
            cumVolume = 0;
            cumTypPriceVol = 0;
            currentDay = barDay;
        }
        
        double typPrice = (high[i] + low[i] + close[i]) / 3.0;
        double vol = (double)tick_volume[i];
        if(vol == 0) vol = 1; // Prevent division by zero
        
        cumVolume += vol;
        cumTypPriceVol += typPrice * vol;
        
        VwapBuffer[i] = cumTypPriceVol / cumVolume;
        
        // Clear previous signals
        BuyArrowBuffer[i] = 0.0;
        SellArrowBuffer[i] = 0.0;
        
        // Evaluate MACD Crossover on completed bars (avoid intrabar repainting)
        if(i < rates_total - 1)
        {
            double macdCurrent  = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, InpPrice, MODE_MAIN, i);
            double sigCurrent   = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, InpPrice, MODE_SIGNAL, i);
            double macdPrevious = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, InpPrice, MODE_MAIN, i+1);
            double sigPrevious  = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, InpPrice, MODE_SIGNAL, i+1);
            
            // Long Condition: Price > VWAP and MACD crosses above Signal
            if(close[i] > VwapBuffer[i] && macdPrevious <= sigPrevious && macdCurrent > sigCurrent)
            {
                BuyArrowBuffer[i] = low[i] - (10 * Point);
            }
            // Short Condition: Price < VWAP and MACD crosses below Signal
            else if(close[i] < VwapBuffer[i] && macdPrevious >= sigPrevious && macdCurrent < sigCurrent)
            {
                SellArrowBuffer[i] = high[i] + (10 * Point);
            }
        }
    }
    
    return(rates_total);
}

Re: Free Tool: VWAP + MACD Momentum Scalping Strategy & Custom Indicators (MT4 / MT5 / cTrader)

Posted: Sun Jul 26, 2026 3:39 pm
by PTScalper
MT5 (MQL5) Custom Indicator
The MQL5 version uses indicator handles for optimized memory execution and handles real exchange volume if provided by your broker.

Code: Select all

//+------------------------------------------------------------------+
//|                                             VWAP_MACD_Scalper.mq5|
//|                          VWAP + MACD On-Chart Arrow Scalping Tool|
//+------------------------------------------------------------------+
#property copyright "Free Open Source"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

//--- Plot 1: VWAP Line
#property indicator_label1  "Daily VWAP"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- Plot 2: Buy Arrow
#property indicator_label2  "Buy Signal"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrLime
#property indicator_width2  2

//--- Plot 3: Sell Arrow
#property indicator_label3  "Sell Signal"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrRed
#property indicator_width3  2

//--- Input Parameters
input int      InpFastEMA   = 6;          // MACD Fast EMA
input int      InpSlowEMA   = 13;         // MACD Slow EMA
input int      InpSignalSMA = 5;          // MACD Signal SMA
input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // Applied Price

//--- Indicator Buffers
double         VwapBuffer[];
double         BuyArrowBuffer[];
double         SellArrowBuffer[];

//--- Global Variables
int            g_macdHandle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    SetIndexBuffer(0, VwapBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, BuyArrowBuffer, INDICATOR_DATA);
    SetIndexBuffer(2, SellArrowBuffer, INDICATOR_DATA);
    
    PlotIndexSetInteger(1, PLOT_ARROW, 233);
    PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
    
    PlotIndexSetInteger(2, PLOT_ARROW, 234);
    PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, 0.0);
    
    g_macdHandle = iMACD(_Symbol, _Period, InpFastEMA, InpSlowEMA, InpSignalSMA, InpPrice);
    if(g_macdHandle == INVALID_HANDLE)
    {
        Print("Failed to create MACD handle.");
        return(INIT_FAILED);
    }
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    if(rates_total < InpSlowEMA) return(0);
    
    int start = (prev_calculated > 0) ? prev_calculated - 1 : 0;
    
    double macdMain[], macdSignal[];
    ArraySetAsSeries(macdMain, false);
    ArraySetAsSeries(macdSignal, false);
    
    if(CopyBuffer(g_macdHandle, 0, 0, rates_total, macdMain) <= 0) return(0);
    if(CopyBuffer(g_macdHandle, 1, 0, rates_total, macdSignal) <= 0) return(0);
    
    static double cumVolume = 0;
    static double cumTypPriceVol = 0;
    static int currentDay = -1;
    
    for(int i = start; i < rates_total; i++)
    {
        MqlDateTime dt;
        TimeToStruct(time[i], dt);
        
        if(dt.day != currentDay)
        {
            cumVolume = 0;
            cumTypPriceVol = 0;
            currentDay = dt.day;
        }
        
        double typPrice = (high[i] + low[i] + close[i]) / 3.0;
        double vol = (volume[i] > 0) ? (double)volume[i] : (double)tick_volume[i];
        if(vol == 0) vol = 1.0;
        
        cumVolume += vol;
        cumTypPriceVol += typPrice * vol;
        
        VwapBuffer[i] = cumTypPriceVol / cumVolume;
        
        BuyArrowBuffer[i] = 0.0;
        SellArrowBuffer[i] = 0.0;
        
        if(i > 0)
        {
            double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
            
            // Long Trigger
            if(close[i] > VwapBuffer[i] && macdMain[i-1] <= macdSignal[i-1] && macdMain[i] > macdSignal[i])
            {
                BuyArrowBuffer[i] = low[i] - (10 * point);
            }
            // Short Trigger
            else if(close[i] < VwapBuffer[i] && macdMain[i-1] >= macdSignal[i-1] && macdMain[i] < macdSignal[i])
            {
                SellArrowBuffer[i] = high[i] + (10 * point);
            }
        }
    }
    
    return(rates_total);
}

Re: Free Tool: VWAP + MACD Momentum Scalping Strategy & Custom Indicators (MT4 / MT5 / cTrader)

Posted: Sun Jul 26, 2026 3:39 pm
by PTScalper
IC Trader / cTrader (C# cAlgo) Implementation
For IC Markets traders utilizing cTrader, indicators are developed in C# using the cAlgo.API framework. Below is a complete, structured custom indicator class that renders the session VWAP line and plots entry arrows directly on the chart overlay.

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class VwapMacdScalper : Indicator
    {
        [Parameter("Fast EMA", DefaultValue = 6, Group = "MACD Settings")]
        public int FastEma { get; set; }

        [Parameter("Slow EMA", DefaultValue = 13, Group = "MACD Settings")]
        public int SlowEma { get; set; }

        [Parameter("Signal SMA", DefaultValue = 5, Group = "MACD Settings")]
        public int SignalSma { get; set; }

        [Output("Daily VWAP", LineColor = "DodgerBlue", Thickness = 1, PlotType = PlotType.Line)]
        public IndicatorDataSeries VwapLine { get; set; }

        [Output("Buy Signal", LineColor = "Lime", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries BuySignals { get; set; }

        [Output("Sell Signal", LineColor = "Red", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries SellSignals { get; set; }

        private MacdCrossOver _macd;
        private double _cumVolume;
        private double _cumTypPriceVol;
        private int _currentDay = -1;

        protected override void OnStart()
        {
            // Initialize the built-in MACD Crossover indicator
            _macd = Indicators.MacdCrossOver(Bars.ClosePrices, FastEma, SlowEma, SignalSma);
        }

        public override void Calculate(int index)
        {
            if (index < SlowEma) return;

            // Check if a new daily session has started (in UTC)
            int barDay = Bars.OpenTimes[index].Day;
            if (barDay != _currentDay)
            {
                _cumVolume = 0;
                _cumTypPriceVol = 0;
                _currentDay = barDay;
            }

            // Calculate Typical Price and Volume
            double typicalPrice = (Bars.HighPrices[index] + Bars.LowPrices[index] + Bars.ClosePrices[index]) / 3.0;
            double volume = Bars.TickVolumes[index];
            if (volume == 0) volume = 1;

            _cumVolume += volume;
            _cumTypPriceVol += typicalPrice * volume;

            // Assign VWAP output
            VwapLine[index] = _cumTypPriceVol / _cumVolume;

            // Ensure we check previous bar crossover to prevent intrabar repainting
            if (index < 1) return;

            bool macdCrossedAbove = _macd.MACD[index] > _macd.Signal[index] && _macd.MACD[index - 1] <= _macd.Signal[index - 1];
            bool macdCrossedBelow = _macd.MACD[index] < _macd.Signal[index] && _macd.MACD[index - 1] >= _macd.Signal[index - 1];

            double pipSize = Symbol.PipSize;

            // Long Condition: Price above VWAP + MACD Bullish Cross
            if (Bars.ClosePrices[index] > VwapLine[index] && macdCrossedAbove)
            {
                BuySignals[index] = Bars.LowPrices[index] - (2 * pipSize);
                Chart.DrawIcon("BuyArrow_" + index, ChartIconType.UpArrow, index, BuySignals[index], Color.Lime);
            }
            // Short Condition: Price below VWAP + MACD Bearish Cross
            else if (Bars.ClosePrices[index] < VwapLine[index] && macdCrossedBelow)
            {
                SellSignals[index] = Bars.HighPrices[index] + (2 * pipSize);
                Chart.DrawIcon("SellArrow_" + index, ChartIconType.DownArrow, index, SellSignals[index], Color.Red);
            }
        }
    }
}