What We Will Build
In this tutorial, we will build a complete custom indicator from scratch: a Simple Price Channel that draws upper and lower bands around price based on the highest high and lowest low over a configurable period. This is a practical indicator that many traders use for breakout detection.
Indicator Structure
Every MQL5 indicator has three mandatory sections:
- Property declarations — Tell MT5 how to display the indicator (number of buffers, draw types, colors)
- OnInit() — Initialize buffers and settings
- OnCalculate() — Calculate values for each bar
Complete Source Code
//+------------------------------------------------------------------+
//| PriceChannel.mq5 |
//| Custom Price Channel Indicator |
//+------------------------------------------------------------------+
#property indicator_chart_window // draw on main chart
#property indicator_buffers 2 // we need 2 data buffers
#property indicator_plots 2 // we draw 2 lines
// Plot 0: Upper Channel
#property indicator_label1 "Upper Channel"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
// Plot 1: Lower Channel
#property indicator_label2 "Lower Channel"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrOrangeRed
#property indicator_width2 2
// Input parameters (user-configurable)
input int ChannelPeriod = 20; // Channel Period
// Indicator buffers
double upperBuffer[];
double lowerBuffer[];
//+------------------------------------------------------------------+
int OnInit()
{
// Validate inputs
if(ChannelPeriod < 2)
{
Print("Error: Channel Period must be >= 2");
return INIT_PARAMETERS_INCORRECT;
}
// Map buffers to plots
SetIndexBuffer(0, upperBuffer, INDICATOR_DATA);
SetIndexBuffer(1, lowerBuffer, INDICATOR_DATA);
// Set indicator name in the Data Window
IndicatorSetString(INDICATOR_SHORTNAME,
"Price Channel (" + IntegerToString(ChannelPeriod) + ")");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
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[])
{
// Not enough bars to calculate
if(rates_total < ChannelPeriod)
return 0;
// Determine starting point
int start;
if(prev_calculated == 0)
start = ChannelPeriod - 1; // first run: start after enough bars
else
start = prev_calculated - 1; // subsequent: only process new bars
// Calculate for each bar
for(int i = start; i < rates_total; i++)
{
double highestHigh = high[i];
double lowestLow = low[i];
// Find highest high and lowest low over the period
for(int j = 1; j < ChannelPeriod; j++)
{
if(high[i - j] > highestHigh)
highestHigh = high[i - j];
if(low[i - j] < lowestLow)
lowestLow = low[i - j];
}
upperBuffer[i] = highestHigh;
lowerBuffer[i] = lowestLow;
}
return rates_total;
}
//+------------------------------------------------------------------+
Step-by-Step Breakdown
#property Declarations
These tell MT5 how to render the indicator:
indicator_chart_window— Draw on the main price chart (vsindicator_separate_windowfor oscillators)indicator_buffers 2— We need 2 data arraysindicator_plots 2— We draw 2 visible elementsindicator_type1 DRAW_LINE— Plot 0 draws as a line
SetIndexBuffer
This function connects your array to a plot. The first parameter is the buffer index (0-based), the second is your array, and the third specifies the buffer type:
INDICATOR_DATA— Contains values to drawINDICATOR_COLOR_INDEX— Contains color indices for multi-colored plotsINDICATOR_CALCULATIONS— Internal calculation buffer (not drawn)
The Calculation Loop
The key optimization is using prev_calculated. On the first call, it is 0 and we calculate all bars. On subsequent calls, it tells us how many bars were already processed, so we only calculate new bars. This makes the indicator efficient even on charts with thousands of bars.
This tutorial shows the fundamentals. Production-quality indicators need additional features: multiple drawing styles, customizable colors, alert conditions, multi-timeframe support, and robust error handling. Building professional indicators requires deep MQL5 expertise — that is what we offer as a service.
Testing Your Indicator
Fix any errors shown in the output panel. Common mistakes: missing semicolons, undeclared variables, wrong buffer count.
In MT5, find your indicator in Navigator > Indicators > Custom, and drag it onto a chart. Adjust the period in the dialog.
The upper line should touch the highest candle highs, and the lower line should touch the lowest candle lows over the period. Test with different period values.
Common Beginner Mistakes
- Wrong buffer count —
indicator_buffersmust match the total number ofSetIndexBuffer()calls - Forgetting to return rates_total —
OnCalculatemust return how many bars were processed - Array out of bounds — Accessing
high[i - j]wheni - jis negative - Not handling prev_calculated — Recalculating all bars on every tick kills performance