The code
An Expert Advisor that trades nothing: on each new bar it prints the last closed bar's close, moving average and RSI in the Experts tab.
Save it as MQL5/Experts/read-indicator-values-copybuffer.mq5 and compile it in MetaEditor (F7): 0 errors, 0 warnings.
input int InpMaPeriod = 50; // Moving average period
input ENUM_MA_METHOD InpMaMethod = MODE_EMA; // Moving average method
input int InpRsiPeriod = 14; // RSI period
int maHandle = INVALID_HANDLE;
int rsiHandle = INVALID_HANDLE;
int OnInit()
{
// Create each indicator once. The handle is a reference to it, not a value.
maHandle = iMA(_Symbol, PERIOD_CURRENT, InpMaPeriod, 0, InpMaMethod, PRICE_CLOSE);
rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, InpRsiPeriod, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE || rsiHandle == INVALID_HANDLE)
{
PrintFormat("Indicator creation failed: error %d", GetLastError());
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
if(rsiHandle != INVALID_HANDLE)
IndicatorRelease(rsiHandle);
}
// Copies `count` values of buffer `buffer`, starting at bar `shift`, newest first: values[0] is bar `shift`.
bool ReadBuffer(const int handle, const int buffer, const int shift, const int count, double &values[])
{
if(BarsCalculated(handle) < shift + count) // still calculating, or not enough bars
return false;
ArraySetAsSeries(values, true);
ResetLastError();
int copied = CopyBuffer(handle, buffer, shift, count, values);
if(copied != count)
{
PrintFormat("CopyBuffer copied %d of %d values, error %d", copied, count, GetLastError());
return false;
}
return true;
}
void OnTick()
{
static datetime lastBar = 0;
datetime bar = iTime(_Symbol, PERIOD_CURRENT, 0);
if(bar == 0 || bar == lastBar)
return;
double ma[], rsi[];
// Bars 1 and 2: the last two closed bars. Bar 0 is still forming and its value moves with every tick.
if(!ReadBuffer(maHandle, 0, 1, 2, ma) || !ReadBuffer(rsiHandle, 0, 1, 2, rsi))
return; // lastBar isn't updated, so the next tick tries again
lastBar = bar;
double close1 = iClose(_Symbol, PERIOD_CURRENT, 1);
PrintFormat("Last closed bar: close %s, %s(%d) %s, RSI(%d) %.1f (bar before: %.1f)",
DoubleToString(close1, _Digits), StringSubstr(EnumToString(InpMaMethod), 5), InpMaPeriod,
DoubleToString(ma[0], _Digits), InpRsiPeriod, rsi[0], rsi[1]);
if(close1 > ma[0] && rsi[1] < 50.0 && rsi[0] >= 50.0)
Print("Close above the moving average and RSI back above 50");
}How it works
- Handles in
OnInit().iMA()andiRSI()start an indicator and return a number that refers to it. Checking forINVALID_HANDLEthere, and refusing to start, is better than failing on every tick. BarsCalculated(handle). How many bars the indicator has calculated; -1 or a small number while it's still working, typically on the first ticks after start. Copying before that fails.ArraySetAsSeries(values, true). Makes index 0 the newest value copied. Without it,CopyBuffer()fills the array oldest first andvalues[0]is the older bar.CopyBuffer(handle, buffer, shift, count, values). Buffer 0 is the main line of single-line indicators. The return value is the number of values copied; anything other thancountmeans try again later.- Shift 1 and 2. Bar 0 is still forming: its moving average and RSI change with every tick. Values of closed bars don't, so a decision made on them is the same live and in the Strategy Tester.
lastBarset after the read. If the read fails, the bar isn't marked as done and the next tick retries it.
Pitfalls
- Expecting a value, as in MQL4.
if(iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE) > iClose(_Symbol, PERIOD_CURRENT, 1))compiles in MQL5 without a warning, and compares the handle number with a price. The MQL4 call with a shift argument doesn't compile at all: wrong parameters count. - Creating the handle in
OnTick(). The indicator needs time to calculate after it's created, so the first copies fail with 4806 requested data not found, and handles that are never released keep indicators loaded. - An invalid handle. A wrong period, a symbol not in Market Watch or a missing custom indicator gives
INVALID_HANDLEand 4802 indicator cannot be created. - The wrong buffer. Multi-line indicators have several buffers:
iBands()0 middle, 1 upper, 2 lower;iMACD()0 main, 1 signal;iStochastic()0 main, 1 signal;iADX()0 ADX, 1 +DI, 2 -DI. Reading the wrong one gives plausible but wrong numbers. - Reading past what was copied. Copy 1 value and read
values[1], and the EA stops with array out of range. A timeframe kept in anintinput from MQL4 code fails to compile with cannot convert enum.
Variations
- Another timeframe.
iRSI(_Symbol, PERIOD_H4, 14, PRICE_CLOSE)on an M15 chart works the same way; shift 1 is then the last closed H4 bar. - ATR, Bollinger Bands, MACD. Same pattern with
iATR(),iBands()oriMACD()and the buffer numbers above. The RSI and ATR guides explain what the values mean. - A custom indicator.
iCustom()returns a handle too, read with the sameCopyBuffer(): see reading a custom indicator. - A signal from the values. The moving average crossover EA turns two of these reads into entries and exits.
Questions
Why does CopyBuffer() return -1?
Most often because the indicator hasn't finished calculating, right after the EA starts or after a timeframe change (error 4806). Return and try again on the next tick. If it never succeeds, check that the handle isn't INVALID_HANDLE and that the chart has enough history for the period.
How do I get the RSI value of the previous candle in MQL5?
Copy one value starting at shift 1: CopyBuffer(rsiHandle, 0, 1, 1, rsi) with rsi set as series, then read rsi[0]. Shift 0 would be the candle still forming.
Why are my EA's indicator values different from the chart's?
Check the shift (bar 0 or 1), the timeframe, the method and the applied price first. Exponential averages can also differ slightly in the last decimals when the EA and the chart start from a different amount of history.
This program is a minimal example written to show one technique, not a trading system, and none of it is a recommendation to trade. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.