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
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
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Series evaluated on chart updates | Event handlers with explicit buffers |
| Deployment | Runs in TradingView with alerts | Runs in the MT5 terminal or on a VPS |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Strategy Tester for strategy scripts | Strategy Tester for Expert Advisors |
| Code complexity | Simpler, functional syntax | C++-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.