Quick Answer
ta.stoch(close, high, low, 14) in Pine Script returns the raw %K, with no smoothing. In MQL5, the matching indicator is iStochastic, which returns a handle, and you read the values with CopyBuffer. Buffer 0 is the %K (main) line and buffer 1 is the %D (signal) line.
The smoothing is where conversions go wrong. Pine code usually smooths the raw value itself, for example k = ta.sma(ta.stoch(...), 3) and d = ta.sma(k, 3). The iStochastic indicator has a Slowing parameter that also smooths %K, and it does it in a different way. The cleanest match is to set Slowing to 1, so buffer 0 is the raw %K, and let the D period do the first smoothing.
Key Facts
| Pine Script | MQL5 |
|---|---|
| ta.stoch(close, high, low, 14) (raw %K) | iStochastic(_Symbol, _Period, 14, 3, 1, MODE_SMA, STO_LOWHIGH), buffer 0 |
| k = ta.sma(ta.stoch(...), 3) | Buffer 1 of the same handle (the D period works as this first smoothing) |
| d = ta.sma(k, 3) | Average of 3 values of buffer 1, calculated in code |
| high and low as the range | STO_LOWHIGH |
| close used as the high and low | STO_CLOSECLOSE |
| ta.crossover(k, d) | k1 > d1 && k2 <= d2 on closed bars |
| Shift 0 is the live bar | Use shift 1 for closed-bar logic |
The Pine Script Version
//@version=5
strategy("Stochastic cross", overlay = false)
lengthK = input.int(14, "K length")
smoothK = input.int(3, "K smoothing")
smoothD = input.int(3, "D smoothing")
k = ta.sma(ta.stoch(close, high, low, lengthK), smoothK)
d = ta.sma(k, smoothD)
if ta.crossover(k, d) and k < 20
strategy.entry("Long", strategy.long)
The strategy enters long when %K crosses above %D while %K is below 20. Here ta.stoch gives the raw value, and the two ta.sma calls do all the smoothing.
What iStochastic Does
The parameters are the symbol, the timeframe, the %K period, the %D period, the slowing, the moving average method of %D, and the price field. The MT5 stochastic smooths %K with the slowing value, and then makes %D as a moving average of that smoothed %K.
That is why a direct copy of the numbers (14, 3, 3) is risky. In Pine, the first smoothing is a simple average of the raw values. In MT5, the slowing is calculated from the sums of the price ranges over the slowing bars, which is close to an average but not the same formula. The difference is small, and it is enough to move a cross by a bar.
The Match: Slowing = 1
With Slowing set to 1, no smoothing is applied to the main line, so buffer 0 is the raw %K, like ta.stoch. The D period then becomes the first smoothing, and buffer 1 is a simple average of the raw %K, like ta.sma(ta.stoch(...), smoothK):
// Pine: lengthK = 14, smoothK = 3
// MQL5: K period = 14, D period = smoothK = 3, Slowing = 1, SMA, low/high
int stochHandle = iStochastic(_Symbol, _Period, 14, 3, 1, MODE_SMA, STO_LOWHIGH);
- Buffer 0 is the raw %K:
ta.stoch(close, high, low, 14). - Buffer 1 is the smoothed %K: Pine's
k. - Pine's
dis the SMA ofk, so calculate it from buffer 1 values.
STO_LOWHIGH uses the highest high and lowest low for the range, which matches ta.stoch(close, high, low, ...). If the Pine code passes close as the high and low, use STO_CLOSECLOSE.
Read the Values
input int LengthK = 14;
input int SmoothK = 3;
input int SmoothD = 3;
int stochHandle = INVALID_HANDLE;
int OnInit()
{
if(LengthK < 1 || SmoothK < 1 || SmoothD < 1)
{
Print("All stochastic lengths must be 1 or more");
return INIT_PARAMETERS_INCORRECT;
}
stochHandle = iStochastic(_Symbol, _Period, LengthK, SmoothK, 1, MODE_SMA, STO_LOWHIGH);
if(stochHandle == INVALID_HANDLE)
return INIT_FAILED;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(stochHandle != INVALID_HANDLE)
IndicatorRelease(stochHandle);
}
// k = smoothed %K (buffer 1), d = SMA of k over SmoothD bars, at 'shift'
bool GetStoch(int shift, double &k, double &d)
{
double kBuf[];
ArraySetAsSeries(kBuf, true); // kBuf[0] = value at 'shift'
if(CopyBuffer(stochHandle, 1, shift, SmoothD, kBuf) != SmoothD)
return false;
double sum = 0.0;
for(int i = 0; i < SmoothD; i++)
sum += kBuf[i];
k = kBuf[0];
d = sum / SmoothD;
return true;
}
For the details of CopyBuffer, including what to do when it returns -1, see MQL5 CopyBuffer guide.
Full MQL5 Example
This EA detects ta.crossover(k, d) and k < 20 on the last closed bar, once per bar, and prints it. It does not place trades.
input int LengthK = 14;
input int SmoothK = 3;
input int SmoothD = 3;
int stochHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
int OnInit()
{
if(LengthK < 1 || SmoothK < 1 || SmoothD < 1)
{
Print("All stochastic lengths must be 1 or more");
return INIT_PARAMETERS_INCORRECT;
}
stochHandle = iStochastic(_Symbol, _Period, LengthK, SmoothK, 1, MODE_SMA, STO_LOWHIGH);
if(stochHandle == INVALID_HANDLE)
return INIT_FAILED;
g_lastBarTime = iTime(_Symbol, _Period, 0);
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(stochHandle != INVALID_HANDLE)
IndicatorRelease(stochHandle);
}
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == 0 || currentBarTime == g_lastBarTime)
return false;
g_lastBarTime = currentBarTime;
return true;
}
bool GetStoch(int shift, double &k, double &d)
{
double kBuf[];
ArraySetAsSeries(kBuf, true);
if(CopyBuffer(stochHandle, 1, shift, SmoothD, kBuf) != SmoothD)
return false;
double sum = 0.0;
for(int i = 0; i < SmoothD; i++)
sum += kBuf[i];
k = kBuf[0];
d = sum / SmoothD;
return true;
}
void OnTick()
{
if(!IsNewBar())
return;
double k1, d1, k2, d2;
// shift 1 = last closed bar, shift 2 = the bar before it
if(!GetStoch(1, k1, d1)) return;
if(!GetStoch(2, k2, d2)) return;
// ta.crossover(k, d) and k < 20, on the closed bar
if(k1 > d1 && k2 <= d2 && k1 < 20.0)
PrintFormat("Stochastic cross up. K %.2f, D %.2f", k1, d1);
}
The cross rule is explained in Pine Script ta.crossover in MQL5, and the new-bar check with the shift 1 rule in Pine Script close[1] in MQL5.
If You Use the Default MT5 Stochastic
Many EAs use iStochastic(_Symbol, _Period, 5, 3, 3, MODE_SMA, STO_LOWHIGH) and read buffers 0 and 1 as they are. That is a valid MT5 stochastic, but it is not the same calculation as the Pine code above, because the slowing and the signal line smooth in the MT5 way. If the goal is the same signals as Pine, use the Slowing = 1 setup. If the goal is to use the MT5 stochastic as it is, keep the default setup and adjust the conditions after testing.
Common Mistakes
- Expecting
ta.stochto be smoothed. It is the raw %K. The smoothing in Pine code comes from theta.smacalls around it. - Copying 14, 3, 3 straight into
iStochastic. The Slowing value smooths in a different way. Use Slowing 1 to match. - Using the wrong price field.
STO_LOWHIGHuses highs and lows.STO_CLOSECLOSEuses closes only. - Swapping the buffers. Buffer 0 is %K (main), buffer 1 is %D (signal).
- Forgetting that %D in Pine is a second
ta.sma. With Slowing 1, buffer 1 is the first smoothing, so the second one is yours to calculate. - Reading shift 0. The live bar changes on every tick. Use closed bars.
- Creating the handle on every tick. Create it once in
OnInit().
FAQ
Related Guides
- Pine Script ta.macd in MQL5: another oscillator where the signal line is smoothed differently.
- Pine Script ta.bb and ta.stdev in MQL5: another multi-buffer indicator with a formula detail to match.
- Pine Script ta.rsi and ta.ema vs MQL5: why indicator values can differ.
- Pine Script ta.crossover in MQL5: detect a cross on closed bars.
- MQL5 CopyBuffer guide: read indicator buffers safely.
- Pine Script close[1] in MQL5: closed-bar values and the new-bar check.
- cTrader C# Error CS1061: building the same strategy in cTrader? Reading an indicator the wrong way gives this error.
- Why a Pine Script Strategy Gives Different Results in MQL5: indicator differences are one of the causes.
Convert Indicator Logic Without Surprises
Smoothing is easy to mismatch: the same three numbers can mean different calculations in two platforms. CodeFlowOS translates Pine Script into MQL5 and lets you review the generated code before you test it in the MT5 Strategy Tester. The platform compile check is optional, and outputs are not guaranteed, so always review the result. For the full process, see the Pine Script to MQL5 guide, or try the converter page. If the code does not compile, the Error Fixer can suggest a fix, and the free early-bird Code Review checks an EA for common mistakes.
This article is educational. It does not describe trading performance and is not financial advice. Always compile and test code in MetaEditor and the Strategy Tester before using it on a live account.