Custom MT5 Indicator Development
Your concept built as a native MetaTrader indicator — custom buffers, on-chart drawing, alerts and an optional das…
Read moreBuffers are the one concept that separates an indicator that works from one that redraws itself, eats CPU, or quietly returns zeros.
A buffer is an array, one element per bar, that the terminal manages for you. Element 0 is
the oldest bar by default, and the terminal keeps the array sized as new bars arrive. You fill
it; the terminal draws it or hands it to whoever calls CopyBuffer().
Two separate counts, and confusing them is a common source of "my indicator shows nothing":
// Three arrays exist; only one is drawn
#property indicator_buffers 3
#property indicator_plots 1
double SignalBuf[]; // drawn
double FastBuf[]; // working value, hidden
double SlowBuf[]; // working value, hidden
int OnInit()
{
SetIndexBuffer(0, SignalBuf, INDICATOR_DATA);
SetIndexBuffer(1, FastBuf, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, SlowBuf, INDICATOR_CALCULATIONS);
return INIT_SUCCEEDED;
}
INDICATOR_DATA buffers are drawn and are visible to
CopyBuffer() from an EA. INDICATOR_CALCULATIONS buffers are
intermediate working storage — kept per bar, never drawn. Use them rather than recomputing, and
never rather than a plain local array, because locals do not survive between ticks.
For bars where your indicator has no value — the first 20 bars of a 20-period average — do not leave 0.0 in the buffer. Zero is a real number and will be drawn as a line running to the bottom of the chart. Set the empty value explicitly:
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod);
PLOT_DRAW_BEGIN tells the terminal how many bars to skip entirely, which is
cleaner than filling them with anything.
OnCalculate() receives rates_total (how many bars exist) and
prev_calculated (how many you had already processed). Recalculating everything on
every tick works and will bring a chart to its knees on a long history.
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < InpPeriod) return 0;
int start = (prev_calculated > 0) ? prev_calculated - 1 : InpPeriod;
for(int i = start; i < rates_total; i++)
SignalBuf[i] = Compute(close, i);
return rates_total; // becomes prev_calculated next time
}
Three rules that cover almost every case. Start from prev_calculated - 1, not
prev_calculated, so the last bar is recalculated as it finishes forming. Return
rates_total on success and 0 when you could not calculate, which forces
a full recalculation next tick. And handle prev_calculated == 0 separately — it means
first run, history reload, or timeframe change.
Inside OnCalculate(), index 0 is the oldest bar. Everywhere else in MQL5
— CopyBuffer(), iClose(), and the way people naturally think — index 0
is the newest. Mixing the two produces an indicator that looks almost right, which is
far harder to spot than one that looks wrong. If you prefer the newest-first convention, call
ArraySetAsSeries() on every array you touch, and do it consistently.
int handle = iCustom(_Symbol, PERIOD_CURRENT, "MyIndicator", InpPeriod);
if(handle == INVALID_HANDLE)
{
Print("iCustom failed: ", GetLastError());
return INIT_FAILED;
}
double buf[];
ArraySetAsSeries(buf, true);
if(CopyBuffer(handle, 0, 0, 3, buf) < 3) return; // not ready yet
Create handles once in OnInit(), never per tick — a handle created every tick is
a resource leak that degrades the terminal over hours. And always check the
CopyBuffer() return count; on the first ticks after attaching, the data genuinely is
not there yet, and treating that as a value of zero is how an EA trades on nothing.
void OnDeinit(const int reason)
{
if(handle != INVALID_HANDLE) IndicatorRelease(handle);
ObjectsDeleteAll(0, g_prefix);
}
Prefix every chart object you create with something unique to your indicator, so
ObjectsDeleteAll() removes yours and leaves the user's own drawings alone. Deleting
a client's trendlines is a memorable way to lose a client.
Your concept built as a native MetaTrader indicator — custom buffers, on-chart drawing, alerts and an optional das…
Read moreA TradingView indicator or strategy ported to MetaTrader, with every condition mapped line by line and the output compar…
Read moreSend your rules, your script or your existing file on WhatsApp and we will reply with a written scope, price and timeline.