Problem Description
Solution
Here is the complete code for a basic MQL4 indicator. This example creates a Median Price Indicator, which draws a line representing the average of the High and Low prices (High + Low) / 2 for each bar.
MQL4 Indicator Structure
//+------------------------------------------------------------------+
//| SimpleLineIndicator.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Your Name"
#property link "https://www.yourwebsite.com"
#property version "1.00"
#property strict
//--- 1. INDICATOR PROPERTIES
// Display the indicator in the main chart window (overlay on price)
#property indicator_chart_window
// We need 1 buffer to store the data for our line
#property indicator_buffers 1
// Define the color of the line (Index 0)
#property indicator_color1 clrDodgerBlue
// Define the width of the line
#property indicator_width1 2
//--- 2. INPUT PARAMETERS
// Allow the user to shift the line forward/backward
input int InputShift = 0;
//--- 3. GLOBAL VARIABLES (BUFFERS)
// This dynamic array will hold the calculated values to be drawn
double LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 4. MAPPING BUFFERS
// Associate the dynamic array 'LineBuffer' with indicator buffer index 0
SetIndexBuffer(0, LineBuffer);
//--- 5. STYLING
// Set the drawing style to a Line
SetIndexStyle(0, DRAW_LINE);
// Apply the shift defined in inputs
SetIndexShift(0, InputShift);
// Set the label that appears in the Data Window
SetIndexLabel(0, "Median Price");
// Return initialization success
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//--- 6. OPTIMIZATION (Do not recalculate all bars every tick)
int limit;
// If prev_calculated is 0, it means it's the first run. Calculate all bars.
if(prev_calculated == 0)
limit = rates_total - 1;
else
// Otherwise, only calculate the new bars (and re-calculate the current open bar)
limit = rates_total - prev_calculated;
//--- 7. CALCULATION LOOP
// Iterate from the oldest necessary bar to the current bar (0)
for(int i = 0; i <= limit; i++)
{
// Calculate the Median Price: (High + Low) / 2
double medianPrice = (High[i] + Low[i]) / 2.0;
// Store the result in the buffer.
// The terminal automatically draws whatever is in this array.
LineBuffer[i] = medianPrice;
}
// Return the total number of bars to be used as 'prev_calculated' in the next tick
return(rates_total);
}
//+------------------------------------------------------------------+
Explanation of the Structure
1. Properties (#property)
These directives tell the MetaTrader terminal how to handle the indicator before the code even runs.
indicator_chart_window: Draws the line directly over the candlesticks. If you wanted a separate window (like RSI or MACD), you would useindicator_separate_window.indicator_buffers: Allocates memory for the data arrays. We used 1 because we are drawing one line.indicator_color1: Sets the default color for the first buffer.
2. Input Parameters (input)
Variables declared with input appear in the "Inputs" tab when you attach the indicator to a chart. This allows users to change settings without editing the code.
3. Global Variables (Buffers)
We declared double LineBuffer[]. This is a dynamic array. However, we do not set its size manually using ArrayResize. The terminal handles the size automatically because we link it as an indicator buffer in OnInit.
4. OnInit() Function
This runs once when you attach the indicator.
SetIndexBuffer(0, LineBuffer): This is the most critical line. It links the arrayLineBufferto the chart's drawing engine. Any value you put intoLineBufferwill be drawn on the screen.SetIndexStyle: Defines that we want to draw a Line (as opposed to a Histogram, Arrow, or Section).
5. OnCalculate() Function
This function runs every time a new price tick is received.
rates_total: The total number of bars on the chart.prev_calculated: The number of bars the indicator has already calculated in previous ticks.- The Optimization Logic: We calculate
limit. If the indicator has already run, we don't want to loop through 100,000 history bars again. We only want to calculate the newest bar (index 0) and perhaps the one just closed. - The Loop: We iterate through the bars. In MQL4,
High[0]is the current bar, andHigh[10]is 10 bars ago. - The Assignment:
LineBuffer[i] = ...assigns the math result to the array. The visual line on the chart updates automatically based on these values.
How to Install and Run
- Open MetaTrader 4.
- Press F4 to open the MetaEditor.
- Click New -> Custom Indicator -> Next.
- Name it
SimpleLineIndicatorand click Finish. - Paste the code above into the file (replace everything).
- Press F7 to Compile.
- Go back to the main MetaTrader 4 window.
- Find
SimpleLineIndicatorin the Navigator panel (under Indicators) and drag it onto a chart.
Q&A
Q: How do I make the line appear in a separate window below the chart?
A: Change #property indicator_chart_window to #property indicator_separate_window.
Q: How do I draw a Moving Average instead of Median Price?
A: Inside the for loop, replace the math with the built-in MA function:
LineBuffer[i] = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, i);
Q: Why does the loop use rates_total - prev_calculated?
A: This is for performance. Calculating thousands of bars on every single tick (millisecond) would freeze the computer. This logic ensures we only calculate new data as it arrives.