MT4 Indicator Source Code: A Working MQL4 Example
By FXNook Lab team
This complete MQL4 example draws an up arrow when a fast moving average crosses above a slow one, and a down arrow when it crosses below. Save the code as an .mq4 file, compile it in MetaEditor, then load the resulting indicator in MT4. The example also shows how its two indicator buffers hold arrow positions and why a signal on the current, unfinished bar can change.
A simple MT4 indicator source code example
The indicator runs in the main chart window. It calculates two moving averages with MT4's built-in iMA() function, but draws only crossover arrows, not the moving-average lines. The fast and slow periods, calculation method, applied price, and arrow offset are inputs you can change in the indicator settings.
Copy this complete source into a new file named MA_Crossover_Arrows.mq4. It uses the standard MQL4 custom-indicator event functions and does not require an external include file.
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrLime
#property indicator_color2 clrTomato
#property indicator_width1 1
#property indicator_width2 1
input int FastMAPeriod = 10;
input int SlowMAPeriod = 25;
input ENUM_MA_METHOD MaMethod = MODE_EMA;
input ENUM_APPLIED_PRICE AppliedPrice = PRICE_CLOSE;
input int ArrowOffsetPoints = 10;
double BuyBuffer[];
double SellBuffer[];
int OnInit()
{
if(FastMAPeriod <= 0 || SlowMAPeriod <= 0 || ArrowOffsetPoints < 0)
return(INIT_PARAMETERS_INCORRECT);
SetIndexBuffer(0, BuyBuffer);
SetIndexBuffer(1, SellBuffer);
ArraySetAsSeries(BuyBuffer, true);
ArraySetAsSeries(SellBuffer, true);
SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 1, clrLime);
SetIndexStyle(1, DRAW_ARROW, STYLE_SOLID, 1, clrTomato);
SetIndexArrow(0, 233);
SetIndexArrow(1, 234);
SetIndexLabel(0, "MA cross up");
SetIndexLabel(1, "MA cross down");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexEmptyValue(1, EMPTY_VALUE);
IndicatorShortName("MA Crossover Arrows");
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[])
{
int required_bars = (int)MathMax(FastMAPeriod, SlowMAPeriod) + 2;
if(rates_total < required_bars)
return(0);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
BuyBuffer[rates_total - 1] = EMPTY_VALUE;
SellBuffer[rates_total - 1] = EMPTY_VALUE;
int start;
if(prev_calculated == 0)
start = rates_total - 2;
else
start = rates_total - prev_calculated;
if(start < 1)
start = 1;
if(start > rates_total - 2)
start = rates_total - 2;
for(int i = start; i >= 0; i--)
{
BuyBuffer[i] = EMPTY_VALUE;
SellBuffer[i] = EMPTY_VALUE;
double fast_now = iMA(NULL, 0, FastMAPeriod, 0, MaMethod, AppliedPrice, i);
double slow_now = iMA(NULL, 0, SlowMAPeriod, 0, MaMethod, AppliedPrice, i);
double fast_previous = iMA(NULL, 0, FastMAPeriod, 0, MaMethod, AppliedPrice, i + 1);
double slow_previous = iMA(NULL, 0, SlowMAPeriod, 0, MaMethod, AppliedPrice, i + 1);
if(fast_now > slow_now && fast_previous <= slow_previous)
BuyBuffer[i] = low[i] - ArrowOffsetPoints * _Point;
else if(fast_now < slow_now && fast_previous >= slow_previous)
SellBuffer[i] = high[i] + ArrowOffsetPoints * _Point;
}
return(rates_total);
}In MQL4, iMA(symbol, timeframe, period, shift, method, applied_price, bar_shift) returns the moving-average value for a requested bar. Here, NULL and 0 mean the chart's current symbol and timeframe. The last argument, i or i + 1, selects the bar being compared.
MT4 uses series indexing in this calculation: index 0 is the current bar, index 1 is the most recently closed bar, and larger indexes are further back in history. When the fast average is above the slow average at index i, but was at or below it at i + 1, the code records an upward crossover. The downward condition is the reverse.
The buffers contain chart prices, not a simple true/false signal. A buy arrow is placed below the bar's low, and a sell arrow above its high; the offset is measured in points using _Point. The EMPTY_VALUE entries tell MT4 not to draw an arrow on bars without a crossover.
Source code, EX4 files, and what you can edit
The editable source and the compiled indicator are different files. MetaEditor uses the MQL4 source to build the file MT4 loads, but having the compiled file alone normally does not give you the original source or its readable calculations.
| File | What it is for | Can you edit the indicator logic? |
|---|---|---|
.mq4 | MQL4 source code that you can open and compile in MetaEditor. | Yes. Edit the source, then compile again to create an updated compiled file. |
.ex4 | Compiled MT4 indicator file that the terminal can load. | Not as ordinary source code. You normally need the matching .mq4 file to inspect or change the logic. |
If you received only an .ex4, you may be able to install and run it, but you cannot use MetaEditor to make normal source edits to its calculations, inputs, or drawing behavior. Ask the author for the source if you need to maintain or adapt it. A compiled file is not a substitute for the source when you want to change how the indicator works.
How to compile an MQ4 indicator in MetaEditor
In MT4, choose File > Open Data Folder. Open
MQL4, thenIndicators, and saveMA_Crossover_Arrows.mq4in that folder. Saving it there keeps the source and compiled indicator in MT4's standard custom-indicator location.Open MetaEditor from MT4 with Tools > MetaQuotes Language Editor or press
F4. In MetaEditor, open the file from the Navigator or use File > Open to find it in the data folder.Press
F7or select Compile. Read the results in the Errors tab at the bottom. A successful compile reports zero errors; warnings, if present, are also worth reading because they can point to code that may not behave as intended.Locate the generated
MA_Crossover_Arrows.ex4in the same Indicators folder. Switch back to MT4 and refresh the Navigator's Indicators list, or restart the terminal if the new file does not appear.
A clean compile means the source passed the compiler, not that arrows must appear on every chart or that the calculation matches your intended trading rules. The next step is to attach the indicator and inspect its output on the symbol and timeframe you plan to use.
Install the indicator and add it to a chart
In MT4, open View > Navigator or press
Ctrl+N. Right-click the Indicators section and choose Refresh. Expand Custom or the relevant indicator list and look for MA Crossover Arrows.Drag the indicator onto a chart, or double-click its name. In the Inputs tab, choose the moving-average periods, method, applied price, and arrow offset. Select OK to attach it.
Look for green upward arrows and tomato-colored downward arrows. If the chart is too zoomed out to see them clearly, zoom in and inspect the bars around a crossover.
Indicators are attached to a particular chart. If the indicator appears on one chart but not another, compare the chart symbol and timeframe, and make sure you attached the custom indicator to the chart you intended. To remove it, right-click the chart, choose Indicators List, select the indicator, and click Delete.
How indicator buffers and signals work
An indicator buffer is an array MT4 reads as plotted output. This example declares two arrays and registers them with SetIndexBuffer(): buffer zero supplies buy-arrow prices, and buffer one supplies sell-arrow prices. SetIndexStyle() tells MT4 to draw each buffer as an arrow, while SetIndexArrow() selects the Wingdings symbol used for each plot.
ArraySetAsSeries() makes the buffer indexes follow the chart's series direction, with the current bar at zero. The calculation also sets the price arrays used for arrow placement to that direction. It processes the full available range on its first calculation; on later calls, prev_calculated lets it recalculate recent bars rather than looping through all history on every tick.
The example checks the current bar, including index zero. That means an arrow can appear during a bar and disappear before it closes if the moving averages no longer satisfy the crossover condition. If you need signals only on completed bars, base the displayed signal on index 1 and its preceding comparison bar, rather than using index zero as the signal bar. This changes when the arrow is displayed, so make that choice explicit when adapting the code.
For another example of an MT4 chart indicator and its setup, see MT4 support and resistance indicator: levels and setup.
Common compile and display problems
| Symptom | Common cause | What to do |
|---|---|---|
| “Cannot open include file” or an undeclared identifier | The source references an include file that is missing, or uses a name not declared in that file or program. | This example has no external includes. For other code, make sure required files are in the correct MQL4/Include folder and that identifiers are declared with the correct spelling and scope. |
| “OnCalculate function declared with wrong type or/and parameters” | The indicator event function has a signature that does not match the MQL4 custom-indicator form. | Use the MQL4 OnCalculate() signature shown above. Do not copy an MQL5 indicator signature into an MT4 source file. |
| Compile succeeds, but no arrows appear | The chart may not yet have enough bars, no crossover may be present in the visible history, or a buffer may not be connected to a plot or cleared correctly. | Load more history, inspect another visible section, and confirm both buffers are registered, styled as arrows, and assigned values at crossover bars. Empty entries should be set to EMPTY_VALUE. |
| Arrows appear on the wrong bars or at an unexpected price | Buffer and price arrays use different indexing directions, or the code uses the wrong bar index or offset. | Keep the buffer and price arrays in series order, compare bar i with i + 1, and verify that the plotted buffer value is a price above or below the candle. |
| Indicator is missing from Navigator | The file was saved outside the active terminal's data folder, was not compiled, or the Navigator list has not been refreshed. | Use File > Open Data Folder in the terminal you are running, confirm the file is under MQL4/Indicators, compile it, then refresh Navigator or restart MT4. |
MetaEditor error messages usually include a source line number. Start at the first reported error: one missing bracket or undeclared name can cause several misleading errors below it. If you want help identifying compiler errors in existing code, FXNook Lab's MQL4/MQL5 error-fixing page describes its code-fixing and recompilation process.
Check the indicator before relying on its output
Confirm the chart context. Note the symbol and timeframe in the chart title, then make sure the indicator is attached to that chart rather than another open chart.
Inspect historical signals. Scroll through visible history and compare each arrow with the crossover condition: the fast average must cross the slow average between the bar carrying the arrow and the following older bar.
Watch a live bar separately. Index zero is unfinished and can change with incoming prices. Compare its output with the last closed bar so you know whether you are looking at a provisional or completed signal.
Read terminal messages. Open the Experts and Journal tabs at the bottom of MT4 if the indicator fails to load or reports a runtime problem. A compiler success message does not replace these terminal checks.
Test changed settings again. Changing periods, price type, or timeframe changes which bars meet the crossover condition. After editing the source, compile the file again and reattach or refresh the indicator before reviewing the updated output.
These checks establish what the indicator draws and when it draws it; they do not establish that a trading rule is suitable or that past or tested results will continue in the future. If you need a different plot, an alert, or closed-bar-only signals, write down the exact conditions before changing the calculation. FXNook Lab's AI indicator builder is an option for specifying a custom MT4 or MT5 indicator; its page describes code generation and compilation checks. Your practical next step is to compile this example, attach it to a chart, and compare several arrows with the two moving-average values and bar indexes that produced them.
Questions
Where do I put an MQ4 indicator source file in MT4?
In MT4, choose File > Open Data Folder, then place the source file in MQL4/Indicators. Compile it in MetaEditor and refresh the Navigator's Indicators list; the compiled EX4 file is normally created alongside the source.
Can I edit an EX4 indicator without the MQ4 source?
Not as normal MQL4 source code. An EX4 is the compiled file MT4 loads, and it does not normally provide the original readable source needed to change the indicator's logic. Ask the author for the MQ4 file if you need to inspect or adapt it.
Why does my MT4 indicator compile but not appear on the chart?
A successful compile does not guarantee that the indicator is attached or that it has values to draw. Make sure the EX4 is in the active terminal's MQL4/Indicators folder, refresh Navigator, attach the indicator, and check that the chart has enough history and meets the indicator's calculation conditions. The Experts and Journal tabs can show loading or runtime messages.