Complete MQL5 guide & code

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

Read the built-in Stochastic oscillator through iStochastic and implement a complete alert-first Expert Advisor. The code uses OnTick, not custom indicator plots, and belongs under MQL5/Experts. Optional trading defaults off. No build-wide compatibility test, production-readiness or performance report is supplied.

Implementation details & mechanics

Core implementation pattern

Once per chart bar after successful copies, compare completed K/D values. An up signal requires K crossing above D with both below the oversold input; down requires the opposite cross with both above the overbought input. These are crosses inside a zone, not independent zone-entry alerts. The selected smoothing and price-field settings define the calculation.

Error handling & safety rules

With trading enabled, an opposite qualifying signal requests closure of matching positions, then allows a new opposite entry only if none remain. Failed closes retry on later ticks without repeated entry attempts for that bar. Initial SL uses the supplied FX-style pip convention and TP is a required positive multiple. There is no trailing stop or account-risk sizing.

MQL5 Code Implementation

#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 ulong MagicNumber=20260001;
input bool   InpTradeEA     = false;  // Enable EA order placement

//--- Global handles and state
int    g_stochHandle  = INVALID_HANDLE;
double g_kBuffer[];
double g_dBuffer[];
bool closeLongPending=false,closeShortPending=false;

//+------------------------------------------------------------------+
//| Expert initialisation                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(InpKPeriod<1 || InpDPeriod<1 || InpSlowing<1 || InpOversold<0 || InpOverbought>100 || InpOversold>=InpOverbought || InpLotSize<=0 || InpStopPips<=0 || InpTPMultiply<=0) return INIT_PARAMETERS_INCORRECT;
   //--- 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()
  {
   if(InpTradeEA)
   {
      if(closeLongPending) { CloseType(POSITION_TYPE_BUY); closeLongPending=HasType(POSITION_TYPE_BUY); }
      if(closeShortPending) { CloseType(POSITION_TYPE_SELL); closeShortPending=HasType(POSITION_TYPE_SELL); }
   }
   //--- Only act on a newly completed bar
   static datetime s_lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(currentBarTime == 0 || currentBarTime == s_lastBarTime)
      return;

   //--- 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;
     }

   s_lastBarTime=currentBarTime;
   //--- 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);

   bool buy=bullCross && inOversold,sell=bearCross && inOverbought;
   if(buy || sell)
   {
      string msg=StringFormat("%s completed Stochastic %s K=%.1f D=%.1f",_Symbol,buy?"up signal":"down signal",kCur,dCur);
      if(InpAlerts) Alert(msg); Print(msg);
   }
   if(!InpTradeEA) return;
   if(sell && HasType(POSITION_TYPE_BUY)) { CloseType(POSITION_TYPE_BUY); closeLongPending=HasType(POSITION_TYPE_BUY); }
   if(buy && HasType(POSITION_TYPE_SELL)) { CloseType(POSITION_TYPE_SELL); closeShortPending=HasType(POSITION_TYPE_SELL); }
   if(closeLongPending || closeShortPending || HasType(POSITION_TYPE_BUY) || HasType(POSITION_TYPE_SELL)) return;
   if(buy) OpenMarketOrder(ORDER_TYPE_BUY);
   if(sell) OpenMarketOrder(ORDER_TYPE_SELL);
  }
bool HasType(ENUM_POSITION_TYPE type)
{
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(PositionGetTicket(i)>0 && PositionGetString(POSITION_SYMBOL)==_Symbol &&
         PositionGetInteger(POSITION_MAGIC)==(long)MagicNumber && PositionGetInteger(POSITION_TYPE)==type) return true;
   return 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 * ((digits==3 || digits==5)?10:1);
   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        = MagicNumber;
   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) || res.retcode!=TRADE_RETCODE_DONE)
      Print("OrderSend ERROR: ", res.retcode, " — ", res.comment);
   else
     {
      Print("Order completed: order=", res.order, " type=",
            EnumToString(orderType), " price=", req.price);
     }
  }

void CloseType(ENUM_POSITION_TYPE type)
{
   for(int i=PositionsTotal()-1;i>=0;i--)
   {
      ulong ticket=PositionGetTicket(i);
      if(ticket==0 || PositionGetString(POSITION_SYMBOL)!=_Symbol || PositionGetInteger(POSITION_MAGIC)!=(long)MagicNumber ||
         PositionGetInteger(POSITION_TYPE)!=type) continue;
      MqlTradeRequest req={}; MqlTradeResult res={};
      req.action=TRADE_ACTION_DEAL; req.symbol=_Symbol; req.position=ticket;
      req.volume=PositionGetDouble(POSITION_VOLUME); req.magic=MagicNumber;
      req.type=type==POSITION_TYPE_BUY?ORDER_TYPE_SELL:ORDER_TYPE_BUY;
      req.price=type==POSITION_TYPE_BUY?SymbolInfoDouble(_Symbol,SYMBOL_BID):SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      req.type_filling=ORDER_FILLING_FOK; req.deviation=10;
      if(!OrderSend(req,res) || res.retcode!=TRADE_RETCODE_DONE) Print("Close failed: ",ticket," retcode=",res.retcode);
   }
}

Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.

Generate custom MQL5 code with Pineify AI

Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify generates editable MQL5 source code. Review its logic, request a syntax check, and compile and test the final file 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 accessStrategy orders are simulated; live automation needs a separate 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 reference guide before porting logic between them.

Frequently Asked Questions

Related MQL5 pages

Risk and testing note

These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.