Generate code in 3 minutes
Enter your idea and AI generates runnable code.
To call a custom indicator from an Expert Advisor (EA) in MQL4 and retrieve its buffer values, you use the iCustom() function. This function allows access to any compiled indicator (.ex4 file) located in the MQL4\Indicators folder.
iCustom Function SyntaxThe function signature is as follows:
double iCustom(
string symbol, // Symbol name (NULL for current)
int timeframe, // Timeframe (0 for current)
string name, // Name of the custom indicator file (without extension)
... // Input parameters of the indicator (if any)
int mode, // Line index (Buffer index, 0-7)
int shift // Shift relative to the current bar (0 is current)
);
To successfully retrieve data, you must identify two specific details about the custom indicator before writing the code:
mode): You need to know which buffer holds the data you want. You can find this by looking at the "Data Window" (Ctrl+D) in MetaTrader 4 while the indicator is on the chart. The first value listed is usually Buffer 0, the second is Buffer 1, and so on.Below is a complete example of an Expert Advisor that calls a hypothetical custom indicator named "MyCustomIndicator".
Assumptions for this example:
MyCustomIndicator.ex4int (Period) and a double (Multiplier).0 is the Main Line, and Buffer 1 is the Signal Line.//+------------------------------------------------------------------+
//| CustomIndCall_EA.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input parameters for the EA (to pass to the indicator)
input int IndPeriod = 14; // Period for the custom indicator
input double IndMulti = 2.0; // Multiplier for the custom indicator
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Check if the indicator file exists to prevent runtime errors
// Note: This check is logical; MQL4 doesn't have a direct "FileExists" for indicators
// outside the sandbox easily, but iCustom will return 0 or Empty value if not found.
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// --- 1. Define the Indicator Name ---
string indicatorName = "MyCustomIndicator";
// --- 2. Call iCustom for Buffer 0 (Main Line) ---
// We retrieve the value for the PREVIOUS bar (shift 1) to ensure the bar is closed
double mainLineValue = iCustom(
NULL, // Symbol: NULL means current chart symbol
0, // Timeframe: 0 means current chart timeframe
indicatorName, // Exact name of the ex4 file
IndPeriod, // 1st Input Parameter of the indicator
IndMulti, // 2nd Input Parameter of the indicator
0, // Buffer Index: 0 (The first line/buffer)
1 // Shift: 1 (Previous bar)
);
// --- 3. Call iCustom for Buffer 1 (Signal Line) ---
double signalLineValue = iCustom(
NULL,
0,
indicatorName,
IndPeriod,
IndMulti,
1, // Buffer Index: 1 (The second line/buffer)
1 // Shift: 1
);
// --- 4. Error Handling and Validation ---
// Check if the indicator returned an error or empty value
if(GetLastError() > 0)
{
Print("Error calling iCustom: ", GetLastError());
return;
}
// Many indicators return EMPTY_VALUE (approx 2147483647) when nothing is drawn
if(mainLineValue == EMPTY_VALUE || signalLineValue == EMPTY_VALUE)
{
// Data is not valid for this bar, do not trade
return;
}
// --- 5. Trading Logic Example ---
// Example: Buy if Main Line crosses above Signal Line
// To check a cross, we need values from 2 bars ago as well
double mainLinePrev = iCustom(NULL, 0, indicatorName, IndPeriod, IndMulti, 0, 2);
double signalLinePrev = iCustom(NULL, 0, indicatorName, IndPeriod, IndMulti, 1, 2);
// Crossover Logic
if(mainLinePrev < signalLinePrev && mainLineValue > signalLineValue)
{
Print("Crossover Detected: BUY Signal");
// OrderSend logic would go here...
}
}
//+------------------------------------------------------------------+
iCustom (after the indicator name and before the mode/shift) must match the extern or input variables in the custom indicator's source code exactly. If the indicator has 5 inputs, you should pass 5 values, or pass none to use defaults.2147483647 (constant EMPTY_VALUE) to represent "no drawing" or "no data" for a specific bar (e.g., an arrow indicator that only appears on specific bars). Always check against EMPTY_VALUE before using the data in calculations.iCustom on every tick can be resource-intensive if the indicator code is heavy. If your strategy only runs on bar close, consider checking Volume[0] == 1 or tracking Time[0] to run the logic only once per new bar.shift=1 (closed bar) rather than shift=0 (current forming bar) unless you specifically intend to trade intra-bar price action.Q: How do I find the correct Buffer Index (mode) for a compiled indicator?
A: Attach the indicator to a chart in MetaTrader 4. Open the "Data Window" (View -> Data Window or Ctrl+D). Hover your mouse over a bar where the indicator draws a line or arrow. The values shown in the Data Window correspond to buffers. The top value is usually Buffer 0, the next is Buffer 1, etc.
Q: Why does iCustom return a huge number like 2147483647?
A: This is the value of the constant EMPTY_VALUE. Indicators use this to signify that nothing is drawn on that specific bar (for example, a Buy Arrow indicator will return this value on candles where there is no buy signal). You should filter these out using if(value != EMPTY_VALUE).
Q: Can I call an indicator located in a subfolder?
A: Yes. If your indicator is in MQL4\Indicators\MyFolder\MyInd.ex4, you pass the name as "MyFolder\\MyInd" (note the double backslash to escape the directory separator).
Q: Do I have to pass all input parameters to iCustom?
A: No. You have two choices:
mode and shift). The indicator will use its default settings.mode and shift as input parameters.