- 1 1. What Is iMA?
- 2 2. Basic iMA Syntax
- 3 3. Correct Usage of iMA (Handle Acquisition and Management)
- 4 4. How to Retrieve Moving Average Values with CopyBuffer
- 5 5. Common Errors and Solutions (Typical Problems with iMA / CopyBuffer)
- 5.1 5.1 Basic Strategy for Isolating Errors
- 5.2 5.2 array out of range (Array Out-of-Bounds Access)
- 5.3 5.3 INVALID_HANDLE (Handle Creation Failure)
- 5.4 5.4 CopyBuffer Failed (Cannot Retrieve Values / Returns 0 or Less)
- 5.5 5.5 The Value Becomes 0 or an Impossible Value
- 5.6 5.6 Dangerous Pitfalls That Cause Differences in Real Operation
- 6 6. Practical Considerations (Performance and Safety Design)
- 7 7. Example Integration into an EA (Golden Cross Detection and Pitfalls)
- 7.1 7.1 Basic Concept of Golden Cross Detection
- 7.2 7.2 Create Two MA Handles (OnInit)
- 7.3 7.3 Retrieve Two Confirmed Bars Using CopyBuffer (Only on a New Bar)
- 7.4 7.4 Cross Detection Logic (Confirmed Bar Based)
- 7.5 7.5 Common Pitfalls (Where Many People Get Stuck)
- 7.6 7.6 Additional Safety Measures for Practical Trading
- 8 8. Related Topics (Planned Future Extensions)
- 9 9. Frequently Asked Questions (FAQ)
1. What Is iMA?
1.1 The Role and Basic Concept of iMA
iMA (Moving Average) is a standard MQL5 function used to obtain a moving average (MA: an indicator that smooths the average price over a fixed period).
A moving average is one of the most basic technical indicators used to determine market direction (trend), and it is widely used for the following purposes.
- Trend identification (uptrend / downtrend)
- Golden cross and dead cross detection
- Support for pullback and rebound analysis
- Filter conditions (enter trades only in the trend direction)
In MQL5, you do not need to implement the moving average calculation yourself.
By using the iMA function, you can obtain an internally calculated moving average indicator.
However, one important point is that iMA in MQL5 is not a function that directly returns a value.
In MQL4, calling iMA() returned the value immediately, but in MQL5 it was changed to an indicator handle model.
1.2 How iMA Works in MQL5 (Handle-Based Model)
In MQL5, calling iMA follows this process.
- Create an indicator handle (identifier) with iMA
- Use CopyBuffer to retrieve the actual moving average values
In other words, iMA returns not the moving average value itself, but a reference ID (handle) for the moving average indicator.
If you do not understand this structure, misunderstandings like the following will occur.
❌ Common Misunderstandings
- Assuming iMA returns the value directly
- Creating iMA on every tick inside OnTick
- Writing comparison logic without using CopyBuffer
All of these are typical beginner mistakes.
1.3 Types of Moving Averages (ENUM_MA_METHOD)
With iMA, you can specify multiple moving average types.
| Type | Description |
|---|---|
| MODE_SMA | Simple Moving Average |
| MODE_EMA | Exponential Moving Average |
| MODE_SMMA | Smoothed Moving Average |
| MODE_LWMA | Linear Weighted Moving Average |
EMA is commonly used in trend-following strategies, but the appropriate choice depends on the strategy.
1.4 When You Should Use iMA
Use iMA in cases like the following.
- When you want an EA to determine the trend direction
- When you want to use whether the price is above or below a moving average as a condition
- When you want to perform multi-timeframe analysis (for example, referencing an H1 MA on an M5 chart)
Especially in EA development, this is a very frequently used function as a trend filter.
1.5 Common Stumbling Points
⚠ Not Understanding the Difference from MQL4
In MQL5, you cannot retrieve the value directly.
You must always follow the flow: handle → CopyBuffer.
⚠ Creating the Indicator in the Wrong Place
- Creating iMA on every tick in OnTick increases the processing load
- The correct approach is to create it in OnInit
⚠ Insufficient Data
If there are not enough bars, CopyBuffer may not work correctly.
This is especially important immediately after starting the tester.
To use iMA correctly, you first need to accurately understand its syntax and the meaning of its arguments.
2. Basic iMA Syntax
2.1 iMA Function Definition
The basic iMA syntax in MQL5 is as follows.
int iMA(
string symbol, // Symbol
ENUM_TIMEFRAMES period, // Timeframe
int ma_period, // Moving average period
int ma_shift, // Display shift
ENUM_MA_METHOD ma_method, // MA type
ENUM_APPLIED_PRICE applied_price // Applied price
);
This function returns the handle (identifier) of the moving average indicator.
If the return value is INVALID_HANDLE, indicator creation has failed.
2.2 Detailed Explanation of Each Argument
① symbol (symbol)
- Using
_Symbolis common - Example: you can also explicitly specify
"EURUSD"
_Symbol
⚠ In multi-currency EAs, explicit symbol specification may be required.
② period (timeframe)
Specifies the timeframe.
Examples:
PERIOD_M1PERIOD_M5PERIOD_H1PERIOD_D1PERIOD_CURRENT(the current chart timeframe)
PERIOD_CURRENT
⚠ In multi-timeframe analysis, getting this wrong will break the logic.
③ ma_period (moving average period)
This is the calculation period for the moving average.
Examples:
- 20 (short-term)
- 50 (medium-term)
- 200 (long-term)
20
⚠ It cannot be calculated if there are not enough bars.
Be especially careful immediately after starting the tester.
④ ma_shift (display shift)
This is the value used to shift the moving average to the right.
Usually, 0 is used.
0
⚠ This is not a calculation shift, but a display position shift.
For logic evaluation, using 0 is generally fine.
⑤ ma_method (moving average type)
Specify an enumeration value (ENUM_MA_METHOD).
MODE_EMA
Main types:
- MODE_SMA (Simple Moving Average)
- MODE_EMA (Exponential)
- MODE_SMMA (Smoothed)
- MODE_LWMA (Weighted)
You need to choose appropriately depending on the strategy.
⑥ applied_price (applied price)
Specifies which price to use as the basis for calculation.
Main options:
- PRICE_CLOSE (close price)
- PRICE_OPEN (open price)
- PRICE_HIGH (high price)
- PRICE_LOW (low price)
- PRICE_MEDIAN (median price)
- PRICE_TYPICAL (typical price)
Usually, PRICE_CLOSE is used.
PRICE_CLOSE
2.3 Minimal iMA Example
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
The important points here are:
- Create it in OnInit
- Always include an INVALID_HANDLE check
2.4 Common Mistakes
❌ Calling iMA Inside OnTick
Creating it on every tick causes unnecessary memory consumption and performance degradation.
❌ Forgetting to Release the Handle
If you do not call IndicatorRelease() when the EA ends, memory may remain allocated.
❌ Using the Wrong ENUM Type
If you force it with int, the code may still compile, but readability becomes worse.
Even if you understand the iMA syntax, you still cannot retrieve the moving average value yet.
3. Correct Usage of iMA (Handle Acquisition and Management)
3.1 The Correct Timing for Handle Creation
In MQL5, iMA is not a function that retrieves a value, but a function that creates an indicator handle.
Because of this, if you create it at the wrong time, you may run into performance and stability problems.
The correct basic structure is as follows.
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
Why Create It in OnInit?
- An indicator can be reused once it has been created
- Creating it on every tick is unnecessary processing
- It has a major impact on tester speed
❌ Common Mistake
void OnTick()
{
int handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
}
This means a new indicator is being created on every tick.
It makes backtesting slower.
3.2 Checking Handle Validity
Immediately after creating the handle, always check for INVALID_HANDLE.
if(maHandle == INVALID_HANDLE)
{
Print("Error creating iMA handle");
return(INIT_FAILED);
}
Main reasons for failure:
- Invalid timeframe specification
- The symbol is unavailable
- Insufficient historical data (environment-dependent)
3.3 Releasing the Indicator (Important)
In MQL5, it is safer by design to explicitly release indicators you create.
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
}
What Happens If You Do Not Release It?
- Memory usage may increase
- It may cause instability in long-running EAs
Especially in VPS operation, memory management should not be ignored.
3.4 Notes for Multi-Timeframe Usage
Example: when obtaining an H1 moving average on an M5 chart
maHandle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
Points to note:
- The higher timeframe data must be loaded
- At the first execution, CopyBuffer may fail due to insufficient data
Countermeasure:
if(Bars(_Symbol, PERIOD_H1) < 100)
{
Print("Not enough bars for H1");
return;
}
3.5 Design Points from a Practical Operation Perspective
✔ Manage Handles as Global Variables
→ If it goes out of scope, you will need to create it again
✔ Use Clear Names When Using Multiple MAs
int maFastHandle;
int maSlowHandle;
✔ Consider Reinitialization Behavior
When parameters are changed, OnDeinit → OnInit is executed again.
If handle management is not appropriate, it can cause abnormal behavior.
4. How to Retrieve Moving Average Values with CopyBuffer
4.1 What Is CopyBuffer?
CopyBuffer() is a function used to retrieve actual calculated values from an indicator handle.
iMA only returns a handle, and the moving average value itself is retrieved with CopyBuffer.
The basic syntax is as follows.
int CopyBuffer(
int indicator_handle, // Indicator handle
int buffer_num, // Buffer number
int start_pos, // Start position
int count, // Number of elements to retrieve
double buffer[] // Destination array
);
The return value is the number of elements successfully copied.
If it is 0 or less, treat it as a failure.
4.2 Basic Example (Retrieving the Latest Values)
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
if(CopyBuffer(maHandle, 0, 0, 3, maBuffer) <= 0)
{
Print("CopyBuffer failed");
return;
}
Meaning of Each Argument
maHandle: the handle obtained with iMA0: buffer number (for iMA, this is basically 0)0: retrieve starting from the current bar3: retrieve 3 valuesmaBuffer: the array used to store the retrieved results
4.3 The Relationship Between start_pos and Indexes (Important)
start_pos = 0 points to the current unconfirmed bar.
Meaning of the indexes:
maBuffer[0]→ current bar (unconfirmed)maBuffer[1]→ 1 bar ago (confirmed)maBuffer[2]→ 2 bars ago
Practical Usage Notes
The unconfirmed bar (index 0) changes as the price moves.
In EA logic, it is common to use:
double currentMA = maBuffer[1]; // Use the confirmed bar
If you use the unconfirmed bar, backtest and live results may not match.
4.4 The Meaning of ArraySetAsSeries
ArraySetAsSeries(maBuffer, true);
When this is specified:
- Index 0 becomes the latest data
- Larger indexes become older data
That is how the array is handled.
If you do not specify it, the order is reversed, which makes the logic confusing.
❌ Common Mistakes
- Forgetting ArraySetAsSeries
- Misunderstanding the index direction
- Referencing an index larger than the number of retrieved values (array out of range)
4.5 What to Check Before Retrieving Data
① Whether There Are Enough Bars
if(Bars(_Symbol, PERIOD_CURRENT) < 50)
{
Print("Not enough bars");
return;
}
If you use an MA period of 20, you need at least 20 bars.
② Check the Return Value of CopyBuffer
int copied = CopyBuffer(maHandle, 0, 0, 3, maBuffer);
if(copied <= 0)
{
Print("CopyBuffer failed. Error: ", GetLastError());
return;
}
The cause of the error may depend on the environment.
4.6 Performance Design Notes
- Do not retrieve a large number of values on every tick
- Retrieve only the minimum number of values you need
- Do not call CopyBuffer repeatedly inside a loop
Example:
// Bad example
for(int i=0; i<100; i++)
{
CopyBuffer(maHandle, 0, i, 1, maBuffer);
}
This is very inefficient.
4.7 Minimal Working Example Summary
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
int copied = CopyBuffer(maHandle, 0, 0, 2, maBuffer);
if(copied > 0)
{
double prevMA = maBuffer[1]; // Confirmed bar
}
This structure is the basic pattern for retrieving moving averages in MQL5.
5. Common Errors and Solutions (Typical Problems with iMA / CopyBuffer)
5.1 Basic Strategy for Isolating Errors
Many issues related to iMA are not caused by logical mistakes, but by one of the following factors.
- Handle creation failed (iMA side)
- CopyBuffer failed (retrieval side)
- Incorrect array handling (very common)
- Insufficient historical data (environment dependent)
- Using an unconfirmed bar, causing unstable logic (difference between backtest and live trading)
First, always insert logging to determine exactly where the failure occurs.
int copied = CopyBuffer(maHandle, 0, 0, 3, maBuffer);
if(copied <= 0)
{
int err = GetLastError();
Print("CopyBuffer failed. err=", err);
}
5.2 array out of range (Array Out-of-Bounds Access)
Symptoms
- The program stops with a runtime error
array out of rangeappears in the log- Often occurs during conditional evaluation
Main Causes
- Referencing an index larger than the number of elements retrieved by
CopyBuffer - The array size was not properly allocated (dynamic array initialization problem)
- Misunderstanding the index direction due to missing
ArraySetAsSeries()
Typical Example (Failure)
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
CopyBuffer(maHandle, 0, 0, 2, maBuffer);
// Only two values retrieved but referencing maBuffer[2]
double x = maBuffer[2];
Solution
- Always retrieve at least the maximum referenced index + 1 elements
- Check the return value of CopyBuffer before referencing the array
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
int need = 3;
int copied = CopyBuffer(maHandle, 0, 0, need, maBuffer);
if(copied < need)
{
Print("Not enough data copied: ", copied);
return;
}
double prevMA = maBuffer[1];
double prev2MA = maBuffer[2];
5.3 INVALID_HANDLE (Handle Creation Failure)
Symptoms
- Log messages such as
iMA handle creation failed - CopyBuffer always fails
- The EA fails initialization (
INIT_FAILED)
Main Causes (May Vary by Environment)
- The
symbolis unavailable (no quote or incorrect specification) - Incorrect
periodspecification (special environments such as custom timeframes) - History data is not yet available at startup
- Insufficient data in the tester environment
Solution
- Always check for
INVALID_HANDLEimmediately after creating the handle - Check the minimum number of bars with
Bars()(especially for higher timeframes)
int OnInit()
{
if(Bars(_Symbol, PERIOD_CURRENT) < 100)
{
Print("Not enough bars yet");
return(INIT_FAILED);
}
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed. err=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
5.4 CopyBuffer Failed (Cannot Retrieve Values / Returns 0 or Less)
Symptoms
- The return value of CopyBuffer is
0or-1 - The buffer remains empty or values never update
Main Causes
- There is not enough data yet to calculate the indicator (most common)
- The
start_posorcountvalues are excessive - The handle is invalid (still
INVALID_HANDLE) - The logic relies on an unconfirmed bar
Solution
- Retrieve the minimum required number of values (often 2–3 is enough)
- If there are not enough bars, design the EA to wait
- Always use confirmed bars (
[1])
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
if(Bars(_Symbol, PERIOD_CURRENT) < 30) return;
int copied = CopyBuffer(maHandle, 0, 0, 2, maBuffer);
if(copied < 2)
{
Print("CopyBuffer not ready. copied=", copied, " err=", GetLastError());
return;
}
double maConfirmed = maBuffer[1];
5.5 The Value Becomes 0 or an Impossible Value
Symptoms
- The MA remains near 0
- The value is far from the price
- Strange behavior only immediately after the tester starts
Main Causes
- Data is not fully loaded yet (immediately after start)
- Misunderstanding the direction of series arrays (forgot
ArraySetAsSeries) - Referencing the current unconfirmed bar
Solution
- Do not perform calculations until enough bars have accumulated
- Use
maBuffer[1](confirmed bar)
5.6 Dangerous Pitfalls That Cause Differences in Real Operation
⚠ Using the Unconfirmed Bar (index 0)
This is a major cause of discrepancies between backtest and live trading.
EA logic should generally rely on confirmed bars.
⚠ Retrieving Large Amounts of Data with CopyBuffer on Every Tick
In VPS operation or multi-symbol EAs, this can cause heavy load.
Design your system to retrieve only the minimum required number of values.
6. Practical Considerations (Performance and Safety Design)
6.1 Avoid Unnecessary Processing on Every Tick
The most common design mistake in EAs using iMA and CopyBuffer is repeating unnecessary calculations on every tick.
❌ Typical Inefficient Example
void OnTick()
{
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
CopyBuffer(maHandle, 0, 0, 100, maBuffer);
}
Problems:
- Retrieving 100 values on every tick
- Unnecessary memory allocation occurs
- Load increases dramatically in multi-symbol EAs
✔ Improvement Strategy
- Retrieve only the minimum required number of values (usually 2–3)
- Update only when a new bar is confirmed
6.2 Detect New Bars (Practical Design)
Many moving-average-based strategies rely on confirmed bars.
Therefore, processing only when a new bar appears is often sufficient.
datetime lastBarTime = 0;
void OnTick()
{
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime == lastBarTime)
return;
lastBarTime = currentBarTime;
// Write MA retrieval logic here
}
This approach:
- Prevents unnecessary CopyBuffer calls per tick
- Improves tester speed
- Stabilizes the logic
6.3 Notes for Multi-Symbol EAs
When using iMA across multiple symbols, keep the following in mind.
✔ Manage Handles for Each Symbol
int maHandle_EURUSD;
int maHandle_USDJPY;
✔ Each Symbol Has Its Own Bar Update Timing
The iTime() check must also be performed per symbol.
⚠ Common Mistakes
- Reusing the same array for different symbols
- Using
_Symboleven though the symbol being processed is different
6.4 Do Not Forget IndicatorRelease
Each time the EA stops or reinitializes, handles are recreated.
If you do not release them, long-term operation may become unstable.
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
}
This is particularly important in continuous VPS operation.
7. Example Integration into an EA (Golden Cross Detection and Pitfalls)
7.1 Basic Concept of Golden Cross Detection
A typical example of using moving averages in an EA is detecting a crossover between a short-term MA and a long-term MA.
- The short-term MA crosses the long-term MA from below → Golden Cross (buy signal)
- The short-term MA crosses the long-term MA from above → Dead Cross (sell signal)
The key point is not the current position, but detecting the crossover by comparing it with the previous confirmed bar.
7.2 Create Two MA Handles (OnInit)
int maFastHandle;
int maSlowHandle;
int OnInit()
{
maFastHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maFastHandle == INVALID_HANDLE)
{
Print("Fast MA handle failed. err=", GetLastError());
return(INIT_FAILED);
}
maSlowHandle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
if(maSlowHandle == INVALID_HANDLE)
{
Print("Slow MA handle failed. err=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
7.3 Retrieve Two Confirmed Bars Using CopyBuffer (Only on a New Bar)
To detect a crossover, at least two confirmed bars are required.
(Because you compare the previous bar and the bar before it.)
bool GetMAValues(int handle, double &v1, double &v2)
{
double buf[];
ArraySetAsSeries(buf, true);
int copied = CopyBuffer(handle, 0, 1, 2, buf); // start_pos=1 → confirmed bars
if(copied < 2)
return false;
v1 = buf[0]; // previous bar (confirmed)
v2 = buf[1]; // two bars ago
return true;
}
Important points here:
start_pos = 1(avoid unconfirmed bars)count = 2(minimum required for cross detection)
7.4 Cross Detection Logic (Confirmed Bar Based)
void OnTick()
{
static datetime lastBarTime = 0;
datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
if(t == lastBarTime) return;
lastBarTime = t;
double fast1, fast2, slow1, slow2;
if(!GetMAValues(maFastHandle, fast1, fast2))
{
Print("Fast MA not ready");
return;
}
if(!GetMAValues(maSlowHandle, slow1, slow2))
{
Print("Slow MA not ready");
return;
}
bool goldenCross = (fast2 <= slow2) && (fast1 > slow1);
bool deadCross = (fast2 >= slow2) && (fast1 < slow1);
if(goldenCross)
Print("Golden Cross detected (confirmed bar)");
if(deadCross)
Print("Dead Cross detected (confirmed bar)");
}
This logic detects the exact moment of the crossover using confirmed bars.
It is suitable for real-world use because it minimizes differences between backtests and live trading.
7.5 Common Pitfalls (Where Many People Get Stuck)
❌ Mistaking Position Comparison for a Cross
Example: Buy if the short MA is above, sell if it is below.
Problem:
- It repeatedly signals even when the MA is already above
- This can cause continuous entries
A crossover must be detected using a change from the previous state to the current state.
❌ Detecting Crossovers on Unconfirmed Bars (index 0)
If you use unconfirmed bars, the following issues may occur.
- The crossover condition fluctuates on every tick
- False detections like “cross → revert → cross again”
- Results differ significantly between backtest and live trading
The solution is to strictly use start_pos = 1.
❌ Incorrect CopyBuffer Start Position
Example: if you write CopyBuffer(handle, 0, 0, 2, buf), then
- buf[0] becomes the unconfirmed bar
- buf[1] becomes the confirmed bar
This can easily confuse the comparison logic.
For crossover detection, it is safest to use only confirmed bars.
7.6 Additional Safety Measures for Practical Trading
A simple crossover strategy alone often produces too much noise.
In real trading systems, filters are typically combined.
Examples:
- Do not trade when spreads are wide
- Disable re-entry for a certain time period
- Trade only when the direction matches the higher timeframe MA
8. Related Topics (Planned Future Extensions)
This article explained the basics of the iMA function in MQL5, including syntax, retrieving values using CopyBuffer, and integrating it into an EA.
However, to use iMA effectively at a professional level, understanding the following related topics is essential.
8.1 Complete Understanding of CopyBuffer
iMA only returns a handle, and actual value retrieval depends entirely on CopyBuffer.
Topics planned for future articles:
- How buffer numbers work
- The exact meaning of start_pos and count
- Internal behavior of ArraySetAsSeries
- Efficient data retrieval design without performance loss
- Handling indicators with multiple buffers
Even if you understand iMA, incorrect CopyBuffer usage will almost certainly create bugs.
8.2 Complete Countermeasures for array out of range
This is the most common runtime error encountered by MQL5 beginners.
Planned future topics:
- Detailed explanation of the error mechanism
- The relationship between CopyBuffer and array size
- How to detect mistakes in series array direction
- Reusable template code to prevent recurrence
- Defensive design techniques in production EAs
Systematically handling these errors greatly improves EA stability.
8.3 Differences from iCustom
iMA is a standard indicator, but when dealing with custom indicators, you must use iCustom.
Planned explanation topics:
- Basic syntax of iCustom
- How to pass parameters
- How to identify buffer numbers
- Managing multi-buffer indicators
- Common design for handle management
After understanding iMA, moving on to iCustom is the natural next step.
8.4 EA Design Philosophy Using Moving Averages
Simple crossover strategies tend to generate too much noise and rarely work well in real trading without modification.
Topics to be covered in the future:
- Filter design (alignment with higher timeframe trend)
- Entry frequency control
- Integration with automatic lot calculation
- Integration with maximum drawdown control
- Architecture designed for forward testing
This site focuses not just on code examples but on EA structures that emphasize safe design and reproducibility.
8.5 Position of This Article
This article represents the first foundational step for retrieving indicator data in MQL5.
If this concept is not properly understood:
- Backtests and live trading results will not match
- Execution stops due to CopyBuffer errors
- Runtime errors occur due to array issues
- Performance may degrade significantly
These types of problems may occur.
Although iMA appears simple, it requires an understanding of the MQL5 handle structure, buffer structure, and series arrays.
With this foundation in place, the next step is a deeper exploration of CopyBuffer design.
9. Frequently Asked Questions (FAQ)
9.1 Why Does the iMA Value Become 0 in MQL5?
The main causes are usually one of the following.
- Insufficient historical data (not enough bars)
- CopyBuffer failed to retrieve the values correctly
- Improper start position (
start_pos) or number of elements (count) - The tester has just started and not enough data has formed yet
Countermeasures:
- Check with
Bars()that there are enough bars - Always verify the return value of CopyBuffer
- Use confirmed bars (index 1 or later)
If you proceed with logic when the value is 0, it can lead to incorrect trade entries.
9.2 What Is the Difference Between iMA in MQL4 and MQL5?
The biggest difference is the handle-based architecture.
- MQL4:
iMA()directly returns the value - MQL5:
iMA()returns a handle, and values are retrieved using CopyBuffer
Therefore, MQL4 code cannot be ported directly.
A common beginner confusion is that iMA does not return a value.
In MQL5, the process is always: handle creation → CopyBuffer retrieval.
9.3 How Many Values Should Be Retrieved with CopyBuffer?
This depends on the purpose.
- Simple value reference: 2 values (confirmed bar and previous bar)
- Cross detection: at least 2 values (comparison with previous state required)
- Slope detection: 3 or more values
The important rule is to always retrieve more elements than the maximum index you reference.
Otherwise, you will encounter an array out of range error.
9.4 Is It a Problem to Call iMA on Every Tick?
It is not recommended.
Reasons:
- Creating indicators on every tick generates unnecessary load
- Backtest speed decreases
- Performance issues become visible in multi-symbol EAs
Safe design:
- Create the handle in OnInit
- Execute CopyBuffer only when a new bar is confirmed
9.5 Is It Okay to Use the Unconfirmed Bar (index 0)?
Technically possible, but not recommended in real trading.
Reasons:
- Unconfirmed bars change as price fluctuates
- Backtest and live results become inconsistent
- Cross detection becomes unstable
For reproducibility, use confirmed bars (index 1 or later).