Learning Center

Colour-changing lines and histograms in MQL5 indicators

Convert Pine plot(color=cond ? green : red) into DRAW_COLOR_LINE and DRAW_COLOR_HISTOGRAM with a colour index buffer.

The Pine Script original

In Pine you pass a colour expression to plot and it changes per bar:

Pine Script

//@version=5
indicator("Colored MA", overlay=true)
ma = ta.ema(close, 20)
plot(ma, color = ma > ma[1] ? color.green : color.red, linewidth=2)

How MQL5 colours a plot

A colour plot needs two buffers: the values (INDICATOR_DATA) and a colour index (INDICATOR_COLOR_INDEX). The colour index buffer holds 0, 1, 2... pointing into the colour list declared with indicator_color1. Both buffers must be double arrays and the counts in indicator_buffers and indicator_plots must match.

MQL5

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrLimeGreen, clrRed
#property indicator_width1  2

double MaBuf[], ClrBuf[];
int hMa;

int OnInit(){
   SetIndexBuffer(0, MaBuf,  INDICATOR_DATA);
   SetIndexBuffer(1, ClrBuf, INDICATOR_COLOR_INDEX);
   ArraySetAsSeries(MaBuf, true); ArraySetAsSeries(ClrBuf, true);
   hMa = iMA(_Symbol, _Period, 20, 0, MODE_EMA, PRICE_CLOSE);
   return hMa == INVALID_HANDLE ? INIT_FAILED : INIT_SUCCEEDED;
}
void OnDeinit(const int r){ IndicatorRelease(hMa); }

int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]){
   if(BarsCalculated(hMa) < rates_total) return 0;
   int toCopy = (prev_calculated == 0) ? rates_total : rates_total - prev_calculated + 1;
   if(CopyBuffer(hMa, 0, 0, toCopy, MaBuf) != toCopy) return 0;
   int limit = MathMin(toCopy, rates_total - 1) - 1;
   for(int i = limit; i >= 0; i--)
      ClrBuf[i] = (MaBuf[i] > MaBuf[i + 1]) ? 0 : 1;
   return rates_total;
}

Histograms and several plots

DRAW_COLOR_HISTOGRAM works the same way (value buffer plus colour index). With several plots, buffers are assigned in order: plot 1 takes buffers 0 and 1, plot 2 starts at buffer 2. Getting this order wrong is the most common reason a converted indicator shows an empty window or the wrong line.

Calculation-only arrays that are not drawn should be registered with INDICATOR_CALCULATIONS after all drawn buffers, and still counted in indicator_buffers.

Related code snippets