Complete .mq5 source code

Stochastic Oscillator MT5: MQL5 Alert Indicator, Code & EA Guide

This page provides a complete MQL5 implementation of the Stochastic Oscillator for MetaTrader 5, including an alert indicator that fires on %K/%D crossovers and overbought/oversold zone entries. You will find production-ready MQL5 code, an Expert Advisor template, parameter tuning guidance, and multi-pair usage tips — all compatible with MT5 build 3000+ using the handle-based indicator API.

Historical test results

57.1%
Win Rate
12.4%
Max Drawdown
1.34
Sharpe Ratio
2021–2025
Test Period

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.

How the Supertrend signal works

Bullish flip

A long entry signal is generated when the %K line crosses above the %D line while both are below the oversold threshold (default 20), confirming bullish momentum from a depressed zone. A short entry is triggered when %K crosses below %D with both lines above the overbought threshold (default 80), signalling exhausted upside pressure. The EA waits for the crossover candle to close before submitting an order to avoid repainting on the live bar.

Bearish flip

Long positions are closed when the %K line crosses back below %D in the overbought zone (above 80) or when a fixed stop-loss in pips is hit. Short positions are exited on a %K cross above %D in the oversold zone (below 20) or on the corresponding stop-loss trigger. An optional take-profit multiplier of 1.5x the stop distance is applied by default to maintain a positive risk-reward ratio.

MQL5 Custom Indicator Code

//+------------------------------------------------------------------+
//|  Stochastic Oscillator MT5 — Alert Indicator & EA Template      |
//|  Compatible with MetaTrader 5 build 3000+ (MQL5 5.x)            |
//|  Disclaimer: Past backtest results do not guarantee future       |
//|  performance. Trade at your own risk.                            |
//+------------------------------------------------------------------+
#property copyright "Pineify (pineify.app)"
#property link      "https://pineify.app"
#property version   "1.00"
#property strict

//--- Indicator inputs
input int    InpKPeriod     = 5;      // %K period
input int    InpDPeriod     = 3;      // %D period (signal)
input int    InpSlowing     = 3;      // Slowing
input int    InpOverbought  = 80;     // Overbought level
input int    InpOversold    = 20;     // Oversold level
input double InpLotSize     = 0.1;    // Trade lot size
input int    InpStopPips    = 50;     // Stop-loss in pips
input double InpTPMultiply  = 1.5;   // Take-profit multiplier (x SL)
input bool   InpAlerts      = true;   // Enable pop-up alerts
input bool   InpTradeEA     = false;  // Enable EA order placement

//--- Global handles and state
int    g_stochHandle  = INVALID_HANDLE;
double g_kBuffer[];
double g_dBuffer[];
bool   g_inLong       = false;
bool   g_inShort      = false;
ulong  g_lastTicket   = 0;

//+------------------------------------------------------------------+
//| Expert initialisation                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Create Stochastic handle
   g_stochHandle = iStochastic(_Symbol, PERIOD_CURRENT,
                                InpKPeriod, InpDPeriod, InpSlowing,
                                MODE_SMA, STO_LOWHIGH);
   if(g_stochHandle == INVALID_HANDLE)
     {
      Print("ERROR: Failed to create Stochastic handle — ", GetLastError());
      return INIT_FAILED;
     }

   //--- Pre-allocate buffers as series
   ArraySetAsSeries(g_kBuffer, true);
   ArraySetAsSeries(g_dBuffer, true);

   Print("Stochastic MT5 EA initialised on ", _Symbol,
         " | K=", InpKPeriod, " D=", InpDPeriod,
         " Slowing=", InpSlowing);
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(g_stochHandle != INVALID_HANDLE)
     {
      IndicatorRelease(g_stochHandle);
      g_stochHandle = INVALID_HANDLE;
     }
   Print("Stochastic MT5 EA removed. Reason code: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Only act on a newly completed bar
   static datetime s_lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(currentBarTime == s_lastBarTime)
      return;
   s_lastBarTime = currentBarTime;

   //--- Copy three bars of Stochastic data
   if(CopyBuffer(g_stochHandle, MAIN_LINE,   0, 3, g_kBuffer) < 3 ||
      CopyBuffer(g_stochHandle, SIGNAL_LINE, 0, 3, g_dBuffer) < 3)
     {
      Print("WARNING: CopyBuffer failed — ", GetLastError());
      return;
     }

   //--- Current and previous bar values (index 1 = last closed, 2 = one before)
   double kCur  = g_kBuffer[1];
   double dCur  = g_dBuffer[1];
   double kPrev = g_kBuffer[2];
   double dPrev = g_dBuffer[2];

   //--- Detect crossovers
   bool bullCross = (kPrev <= dPrev) && (kCur > dCur);
   bool bearCross = (kPrev >= dPrev) && (kCur < dCur);

   //--- Overbought / Oversold zone checks
   bool inOversold   = (kCur < InpOversold)  && (dCur < InpOversold);
   bool inOverbought = (kCur > InpOverbought) && (dCur > InpOverbought);

   //--- Long signal: bullish cross from oversold
   if(bullCross && inOversold)
     {
      string msg = StringFormat("%s | Stochastic LONG signal — K=%.1f crossed above D=%.1f in oversold zone",
                                _Symbol, kCur, dCur);
      if(InpAlerts)
         Alert(msg);
      Print(msg);

      if(InpTradeEA && !g_inLong)
        {
         CloseShortIfOpen();
         OpenMarketOrder(ORDER_TYPE_BUY);
         g_inLong  = true;
         g_inShort = false;
        }
     }

   //--- Short signal: bearish cross from overbought
   if(bearCross && inOverbought)
     {
      string msg = StringFormat("%s | Stochastic SHORT signal — K=%.1f crossed below D=%.1f in overbought zone",
                                _Symbol, kCur, dCur);
      if(InpAlerts)
         Alert(msg);
      Print(msg);

      if(InpTradeEA && !g_inShort)
        {
         CloseLongIfOpen();
         OpenMarketOrder(ORDER_TYPE_SELL);
         g_inShort = true;
         g_inLong  = false;
        }
     }

   //--- Exit long: bearish cross while overbought
   if(InpTradeEA && g_inLong && bearCross && inOverbought)
     {
      CloseLongIfOpen();
      g_inLong = false;
     }

   //--- Exit short: bullish cross while oversold
   if(InpTradeEA && g_inShort && bullCross && inOversold)
     {
      CloseShortIfOpen();
      g_inShort = false;
     }
  }

//+------------------------------------------------------------------+
//| Open a market order with SL and TP                              |
//+------------------------------------------------------------------+
void OpenMarketOrder(ENUM_ORDER_TYPE orderType)
  {
   MqlTradeRequest  req  = {};
   MqlTradeResult   res  = {};

   double point     = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits    = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double slPoints  = InpStopPips * point * 10;
   double tpPoints  = slPoints * InpTPMultiply;

   req.action       = TRADE_ACTION_DEAL;
   req.symbol       = _Symbol;
   req.volume       = InpLotSize;
   req.type         = orderType;
   req.type_filling = ORDER_FILLING_FOK;
   req.deviation    = 10;
   req.magic        = 20260001;
   req.comment      = "Stochastic MT5 EA";

   if(orderType == ORDER_TYPE_BUY)
     {
      double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      req.price    = ask;
      req.sl       = NormalizeDouble(ask - slPoints, digits);
      req.tp       = NormalizeDouble(ask + tpPoints, digits);
     }
   else
     {
      double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      req.price    = bid;
      req.sl       = NormalizeDouble(bid + slPoints, digits);
      req.tp       = NormalizeDouble(bid - tpPoints, digits);
     }

   if(!OrderSend(req, res))
      Print("OrderSend ERROR: ", res.retcode, " — ", res.comment);
   else
     {
      g_lastTicket = res.order;
      Print("Order opened: ticket=", g_lastTicket, " type=",
            EnumToString(orderType), " price=", req.price);
     }
  }

//+------------------------------------------------------------------+
//| Close open long position by ticket                              |
//+------------------------------------------------------------------+
void CloseLongIfOpen()
  {
   if(g_lastTicket == 0) return;
   MqlTradeRequest req = {};
   MqlTradeResult  res = {};
   req.action   = TRADE_ACTION_DEAL;
   req.symbol   = _Symbol;
   req.position = g_lastTicket;
   req.type     = ORDER_TYPE_SELL;
   req.volume   = InpLotSize;
   req.price    = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   req.deviation = 10;
   req.comment  = "Stochastic close long";
   if(!OrderSend(req, res))
      Print("Close long ERROR: ", res.retcode);
   else
      Print("Long closed: ticket=", g_lastTicket);
   g_lastTicket = 0;
  }

//+------------------------------------------------------------------+
//| Close open short position by ticket                             |
//+------------------------------------------------------------------+
void CloseShortIfOpen()
  {
   if(g_lastTicket == 0) return;
   MqlTradeRequest req = {};
   MqlTradeResult  res = {};
   req.action   = TRADE_ACTION_DEAL;
   req.symbol   = _Symbol;
   req.position = g_lastTicket;
   req.type     = ORDER_TYPE_BUY;
   req.volume   = InpLotSize;
   req.price    = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   req.deviation = 10;
   req.comment  = "Stochastic close short";
   if(!OrderSend(req, res))
      Print("Close short ERROR: ", res.retcode);
   else
      Print("Short closed: ticket=", g_lastTicket);
   g_lastTicket = 0;
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor, save it in the MQL5/Indicators folder, and compile with F7.

Change the settings or add your own signal filter

Describe the ATR inputs, alert rules, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.

Pine Script vs MQL5: Same Strategy, Different Platforms

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-like, more powerful

The calculation can be implemented on either platform, but the runtime model and buffer APIs differ. Read the Pine Script Supertrend reference before porting logic between them.

Frequently Asked Questions

Related MQL5 pages

Risk and testing note

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.