- 1 1. What Is mql5-create-indicator?
- 2 2. Overall Flow for Creating an Indicator
- 3 3. Understanding How Indicators Work with Minimal Code
- 3.1 3.1 Basic Structure of an Indicator (Overview)
- 3.2 3.2 Role of #property (Display Settings)
- 3.3 3.3 IndicatorBuffer (The Actual Display Data)
- 3.4 3.4 OnInit (Initialization Processing)
- 3.5 3.5 OnCalculate (Most Important)
- 3.6 3.6 Loop Processing (The Actual Drawing Logic)
- 3.7 3.7 Beginner Traps You Will Almost Certainly Hit (Important)
- 3.8 3.8 Practical Performance Note
- 4 4. IndicatorBuffer and Drawing Settings (Practical Level)
- 4.1 4.1 IndicatorBuffer Basics (Review and Extension)
- 4.2 4.2 How to Use Multiple Buffers
- 4.3 4.3 Drawing Style Settings (Color, Line, Type)
- 4.4 4.4 Importance of EMPTY_VALUE (Very Important)
- 4.5 4.5 Beginner Traps (Important)
- 4.6 4.6 Basics of Arrow and Signal Indicators
- 4.7 4.7 Practical View: Separating the Design
- 4.8 4.8 Performance and Stability
- 5 5. Advanced OnCalculate Usage (Differential Calculation and Practical Logic)
- 5.1 5.1 Core Meaning of prev_calculated (Most Important)
- 5.2 5.2 Basic Pattern for Differential Calculation
- 5.3 5.3 Why Subtract 1?
- 5.4 5.4 Handling the begin Parameter
- 5.5 5.5 How to Write Practical Logic (Important)
- 5.6 5.6 Safe Array Access (Required)
- 5.7 5.7 Common Mistakes (Important)
- 5.8 5.8 Performance Design (Practical)
- 5.9 5.9 Practical Summary
- 6 6. Indicator Implementation Examples (Moving Average and Signal Addition)
- 6.1 6.1 Implementing a Moving Average Indicator (Basic)
- 6.2 6.2 Performance Improvement (Practical View)
- 6.3 6.3 Signal Indicator (Arrow Display)
- 6.4 6.4 Practical Arrow Display Settings (Important)
- 6.5 6.5 Combined Logic (Moving Average + Signal)
- 6.6 6.6 Beginner Traps (Important)
- 6.7 6.7 Practical Design Guidelines
- 6.8 6.8 Design for Future EA Integration
- 7 7. Common Errors and Troubleshooting (Cause → Fix)
- 7.1 7.1 Nothing Is Displayed (Most Common)
- 7.2 7.2 It Does Not Appear in Navigator
- 7.3 7.3 array out of range Error
- 7.4 7.4 indicator buffers Related Errors
- 7.5 7.5 Values Are Shifted or Delayed
- 7.6 7.6 Values Appear on Every Bar (Incorrect Display)
- 7.7 7.7 Compile Errors (Basic)
- 7.8 7.8 Performance Problem (Heavy Processing)
- 7.9 7.9 Problems When Connecting with an EA
- 7.10 7.10 Practical Strategy to Avoid Problems
- 7.11 7.11 Error Priority (Practical Judgment)
- 8 8. How to Connect with an EA (Basics of iCustom and CopyBuffer)
- 8.1 8.1 Basic Structure for Using an Indicator from an EA
- 8.2 8.2 What Is iCustom?
- 8.3 8.3 iCustom When input Parameters Exist
- 8.4 8.4 Getting Values with CopyBuffer
- 8.5 8.5 How to Think About Buffer Numbers
- 8.6 8.6 Basic Example of Signal Judgment
- 8.7 8.7 Common Mistakes and Notes
- 8.8 8.8 How to Check Handle Creation Failure
- 8.9 8.9 Practical Design Guidelines
- 8.10 8.10 Beginner-Friendly Conclusion
- 9 9. Summary (How to Reach Practical Level Quickly)
- 9.1 9.1 Core Nature of an Indicator (Redefined)
- 9.2 9.2 Three Minimum Points to Remember (Important)
- 9.3 9.3 Thinking Required at a Practical Level
- 9.4 9.4 Shortest Learning Route for Beginners
- 9.5 9.5 Common Patterns Where Beginners Get Stuck
- 9.6 9.6 Most Important Practical Points
- 9.7 9.7 Long-Term Applications
- 9.8 9.8 Conclusion (Practical Summary)
- 9.9 9.9 What to Do Next (Practical Actions)
- 10 FAQ
- 10.1 Q1. Why is my MQL5 indicator not displayed?
- 10.2 Q2. What does OnCalculate do?
- 10.3 Q3. What is EMPTY_VALUE?
- 10.4 Q4. Should I always use prev_calculated?
- 10.5 Q5. How do I use an indicator from an EA?
- 10.6 Q6. How can I prevent an array out of range error?
- 10.7 Q7. How do I display multiple lines?
- 10.8 Q8. What indicator should beginners create first?
1. What Is mql5-create-indicator?
In MQL5, “create indicator” means building a program that performs custom calculations based on price data and visualizes the results on a chart.
The goal of this article is to help you reach the following state:
- You can create your own custom indicator
- You can display it on a chart
- You understand the basic mechanism, especially Buffer and OnCalculate
In MQL5, an indicator is not only a display tool. It is also important as a data-generation component that can work with an EA, or Expert Advisor, for automated trading. Once you understand this part, your options for EA development become much wider.
1.1 What Is an MQL5 Indicator?
An MQL5 indicator is a program that processes and visualizes price data, such as Open, High, Low, and Close.
Common examples:
- Moving Average (MA)
- RSI
- MACD
All of these follow the same structure: “price data → calculation → display.”
The key points are:
- An indicator does not place trades
- It displays information used for decision-making
- Calculation results are stored in arrays called Buffers
A common beginner confusion:
| Concept | Role |
|---|---|
| Indicator | Analysis and display |
| EA | Trading and execution |
If you do not understand this difference, the design can break down from the start.
1.2 What You Can Do with mql5-create-indicator
Creating an indicator allows you to do the following:
- Visualize custom logic, such as special signals
- Support entry decisions
- Connect with an EA using iCustom, explained later
The most important point is “EA integration.”
double value = iCustom(Symbol(), Period(), "MyIndicator", 0, 0);
In this way, an EA can retrieve values from your custom indicator.
In other words, you can create this division of roles:
- Indicator → handles calculation
- EA → handles execution
This is very important in real projects because separating logic improves maintainability.
1.3 Points Beginners Should Understand First
The two most important ideas in indicator creation are the following.
1. Display and calculation are separate
- Calculation is done in OnCalculate
- Display is done through IndicatorBuffer
As a code structure, the flow is:
Calculate → store in an array → draw automatically
That is the basic flow.
2. OnCalculate is the center of everything
OnCalculate is the function called every time price data is updated.
What you do here is simple:
- Get data
- Calculate
- Put the result into an array
3. Common beginner traps (important)
The following issues happen very often:
- No value is assigned to the Buffer → nothing is displayed
- Array index mistake → error
- Poor understanding of OnCalculate → behavior is not as intended
The most common problem is “I wrote the code, but nothing appears.”
In about 90% of cases, the cause is an unset Buffer or a missing value assignment.
2. Overall Flow for Creating an Indicator
Creating an indicator may look complicated, but in practice you only need to follow a fixed sequence of steps.
This section explains the process in the order “overview → execution steps” so beginners do not get lost.
2.1 Creation Steps (Overview)
First, understand the overall flow.
1. Open MetaEditor
2. Create a new indicator
3. Write the code
4. Compile
5. Apply it to a chart in MT5
The important point is to understand the big picture before writing code.
Beginners often fail because they:
- Start writing code immediately
- Do not know where the file is saved
- Do not know how to check the indicator after compiling
To avoid this, first lock in the workflow.
2.2 Understanding the File Structure
Indicators are saved in a specific MT5 folder.
Basic structure:
MQL5/
└ Indicators/
└ YourIndicator.mq5
Key points:
.mq5is the source code- After compiling, an
.ex5file is generated as the executable file
When you create the file in MetaEditor, it is automatically saved in this location.
Important notes
- If you use the wrong folder, the indicator will not appear in MT5
- If you do not compile it, it cannot be used
2.3 Shortest Steps to Run It (For Beginners)
If you follow these steps as written, the indicator will be displayed.
Steps
- Start MetaTrader 5
- Open “Tools → MetaQuotes Language Editor”
- Select “New → Custom Indicator”
- Enter a name, for example MyIndicator
- Leave the wizard settings at their defaults
- Save the generated code as is
- Compile it with F7
- Return to MT5
- From Navigator → Indicators, drag the created indicator onto the chart
Minimum code for a quick operation check
#property indicator_chart_window
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
return(rates_total);
}
This code is an indicator that simply displays the price as is.
Common Mistakes (Important)
Here are the points where beginners often get stuck.
1. Not compiling
- → It will not appear in MT5
2. It does not appear in Navigator
- → The folder is wrong, or compilation failed
3. Nothing appears even after dragging it onto the chart
- → Buffer setup mistake, explained in the next chapter
4. Ignoring errors
- → Always check the compile log
Practical Note
- The code generated by the wizard is a template
- In real work, you will always customize it
- At first, prioritize making something that works
3. Understanding How Indicators Work with Minimal Code
In this section, we break down the minimal code shown in the previous chapter and accurately understand how an indicator works.
Once you understand this, you can customize it later by adding logic.
3.1 Basic Structure of an Indicator (Overview)
An MQL5 indicator consists of the following three elements:
1. Property definitions (display settings)
2. Initialization processing (OnInit)
3. Calculation processing (OnCalculate)
Here is the minimal code again.
#property indicator_chart_window
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
return(rates_total);
}
This is the smallest structure for drawing the price as is.
![MQL5 indicator data flow diagram showing how price data is processed in OnCalculate, calculated values are stored in an indicator buffer, and visualized on a trading chart, with code example using SetIndexBuffer and buffer[i] assignment, highlighting execution flow and system structure for MetaTrader 5 custom indicator development.](http://finance.trgy.co.jp/wp-content/uploads/2026/03/6054e62ab9cffc177ba33396e18585fe-1024x538.png)
3.2 Role of #property (Display Settings)
#property indicator_chart_window
This specifies where the indicator is displayed.
indicator_chart_window→ on the main chartindicator_separate_window→ in a separate subwindow, such as RSI
Note
- If you choose the wrong setting, the indicator may be “displayed but not visible”
- Beginners should start with chart_window
3.3 IndicatorBuffer (The Actual Display Data)
double buffer[];
This is an array that stores the data drawn on the chart.
SetIndexBuffer(0, buffer);
This single line is extremely important.
Meaning:
- It registers the buffer array as the drawing target
Core idea
- Putting values into the Buffer means they are drawn on the chart
- If there are no values, nothing is displayed
Common mistakes
- Forgetting SetIndexBuffer → nothing is displayed
- Using multiple arrays but mismatching their indexes
3.4 OnInit (Initialization Processing)
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
OnInit is a function that runs only once when the indicator is loaded.
What you do here:
- Register Buffers
- Initialize parameters
- Set drawing options
Practical points
- Do not run heavy processing here; keep it lightweight
- Configuration mistakes are fixed at this stage
3.5 OnCalculate (Most Important)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
This is the heart of the indicator.
Role
- It is called every time new data arrives
- All calculation processing is done here
Meaning of the arguments, simplified for beginners
rates_total: current number of barsprev_calculated: number of bars calculated up to the previous callprice[]: price data, used as the input here
3.6 Loop Processing (The Actual Drawing Logic)
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
This is the actual processing.
Meaning:
- Set a value for every bar
- The result is drawn as is
Core understanding
Data → calculation → assign to buffer[i] → draw
3.7 Beginner Traps You Will Almost Certainly Hit (Important)
This section is very important.
1. No value is assigned to buffer
→ Nothing is displayed. This is the most common issue.
2. Index mismatch
→ array out of range error
3. Not understanding rates_total
→ Wrong loop range
4. Not using prev_calculated
→ Full recalculation every time, causing unnecessary load
3.8 Practical Performance Note
For beginners, the first priority is to make it work. In real projects, however, the following matters.
Bad example: full recalculation every time
for(int i = 0; i < rates_total; i++)
Improved example: differential calculation
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
for(int i = start; i < rates_total; i++)
{
buffer[i] = price[i];
}
This prevents unnecessary recalculation.
4. IndicatorBuffer and Drawing Settings (Practical Level)
This section explains practical use of IndicatorBuffer, which determines both the indicator’s appearance and data structure.
Once you understand this, you can do more than display a single line. You can create multiple lines, signal displays, and custom drawing.
4.1 IndicatorBuffer Basics (Review and Extension)
An IndicatorBuffer is an array that stores values drawn on the chart.
double buffer[];
SetIndexBuffer(0, buffer);
In real projects, however, using multiple Buffers is standard.
Examples:
- Moving Average: one line
- MACD: two lines plus histogram
- Signal display: arrows
4.2 How to Use Multiple Buffers
To draw multiple lines, define multiple Buffers.
Example: two lines
double buffer1[];
double buffer2[];
int OnInit()
{
SetIndexBuffer(0, buffer1);
SetIndexBuffer(1, buffer2);
return(INIT_SUCCEEDED);
}
OnCalculate side
for(int i = 0; i < rates_total; i++)
{
buffer1[i] = price[i];
buffer2[i] = price[i] * 1.01;
}
Points
- Indexes such as 0, 1, and 2 become the display order
- If the buffer and index mapping is wrong, it becomes a bug
4.3 Drawing Style Settings (Color, Line, Type)
Display is controlled through properties.
#property indicator_plots 2
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlue
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrRed
Common drawing types
| Type | Description |
|---|---|
| DRAW_LINE | Line |
| DRAW_HISTOGRAM | Bar chart |
| DRAW_ARROW | Arrow |
Example: arrow display
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrGreen
4.4 Importance of EMPTY_VALUE (Very Important)
For parts you do not want to draw, always use the following:
buffer[i] = EMPTY_VALUE;
Reason
- If a value exists, it will be drawn
- It can cause unwanted lines to connect
Example: conditional display
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
4.5 Beginner Traps (Important)
This chapter is a common source of bugs.
1. indicator_plots is not set
→ Multiple Buffers are not displayed
2. Wrong SetIndexBuffer order
→ Displays are swapped
3. EMPTY_VALUE is not used
→ Unintended lines appear
4. Misunderstanding buffer size
→ ArrayResize is not needed because it is managed automatically
4.6 Basics of Arrow and Signal Indicators
For trading signals, arrows are commonly used.
Example: display an arrow on an upward move
#property indicator_type1 DRAW_ARROW
for(int i = 1; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
Notes
- You may need to set an arrow code, such as Wingdings
- The display position is determined by the price value
4.7 Practical View: Separating the Design
In real projects, the following structure is recommended.
Calculation logic → assign to buffer → display settings
Bad examples:
- Calculation and display are mixed together
- Conditional branching is too complex
Good examples:
- Move logic into functions
- Use the buffer only for final output
4.8 Performance and Stability
Multiple Buffers can affect processing load.
Points to watch
- Do not create unnecessary Buffers
- Use differential calculation consistently
- Optimize conditional branches
5. Advanced OnCalculate Usage (Differential Calculation and Practical Logic)
This section explains differential calculation using prev_calculated and practical logic design so you can use OnCalculate at a real project level.
The conclusion is simple: optimizing OnCalculate is the core of performance and stability.
5.1 Core Meaning of prev_calculated (Most Important)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
Conclusion
prev_calculatedis the number of bars calculated up to the previous call
In other words:
You only need to calculate the newly added part
That is the main idea.
5.2 Basic Pattern for Differential Calculation
Bad pattern, common among beginners
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
Problems:
- Recalculates all data every time
- Creates unnecessary CPU load
- Can cause latency risk when used with an EA
Good pattern, practical standard
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
for(int i = start; i < rates_total; i++)
{
buffer[i] = price[i];
}
Points
- Recalculate only the immediately previous bar for safety
- Process only new data
5.3 Why Subtract 1?
prev_calculated - 1
Reason:
- The immediately previous bar may still be updated
- If it is not recalculated, values can become misaligned
Examples
- A bar updating during ticks
- An unfinished candle
Conclusion
Recalculating from one bar back is the standard approach
5.4 Handling the begin Parameter
const int begin
Role
- The calculation start position, depending on the indicator
At the beginner stage:
It is generally okay to ignore it
When it is used in practice
- Integration with another indicator
- Control of the calculation range
5.5 How to Write Practical Logic (Important)
Indicator logic becomes stable when structured as follows:
1. Get the required data
2. Check the condition
3. Assign to the buffer
Example: simple trend detection
for(int i = start; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
5.6 Safe Array Access (Required)
This is where beginners most often create errors.
Bad example
if(price[i] > price[i-1])
Problem:
- It crashes at i=0 because i-1 does not exist
Safe writing style
for(int i = MathMax(start, 1); i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
}
Conclusion
Always perform boundary checks when referencing arrays
5.7 Common Mistakes (Important)
This chapter covers issues that appear often in real work.
1. Not using prev_calculated
→ Unnecessary recalculation
2. Wrong start position
→ Missing calculations or bugs
3. i=0 problem
→ array out of range
4. EMPTY_VALUE is not set
→ Unwanted drawing artifacts
5.8 Performance Design (Practical)
This is very important when using the indicator with an EA.
Examples of negative impact
- High-frequency calculation → increased CPU load
- VPS latency → delayed execution
Improvements
- Use differential calculation consistently
- Reduce unnecessary loops
- Keep calculation load light
5.9 Practical Summary
OnCalculate is evaluated by the following criteria:
| Criterion | Description |
|---|---|
| Accuracy | Whether the calculation is correct |
| Stability | Whether errors are avoided |
| Lightweight design | Whether unnecessary processing is avoided |
6. Indicator Implementation Examples (Moving Average and Signal Addition)
In this section, you will use what you have learned to implement indicators that are actually usable.
The conclusion is that as long as you follow the pattern “calculation logic → buffer assignment,” you can apply it in many ways.
6.1 Implementing a Moving Average Indicator (Basic)
First, implement the most basic indicator: a Simple Moving Average (SMA).
Code example (SMA)
#property indicator_chart_window
#property indicator_plots 1
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlue
input int period = 14;
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
int start = prev_calculated > 0 ? prev_calculated - 1 : period;
for(int i = start; i < rates_total; i++)
{
double sum = 0.0;
for(int j = 0; j < period; j++)
{
sum += price[i - j];
}
buffer[i] = sum / period;
}
return(rates_total);
}
Point explanation
period: averaging period, entered by the useri - j: reference to past dataCannot calculate before period bars exist→ start is adjusted because bars before the period cannot be calculated
Common mistakes
- Calculating before enough bars exist for period → error
- Nested loops are heavy → inefficient for long periods
6.2 Performance Improvement (Practical View)
The SMA above is easy to understand, but it is not efficient.
Improvement idea
Reuse the previous total → reduce to O(n)
However, beginners should first prioritize making it work correctly.
6.3 Signal Indicator (Arrow Display)
Next is an example that displays trading signals.
Conditions
- Upward move: BUY signal
- Downward move: SELL signal
Code example
#property indicator_chart_window
#property indicator_plots 1
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrGreen
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
int start = prev_calculated > 0 ? prev_calculated - 1 : 1;
for(int i = start; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
return(rates_total);
}
6.4 Practical Arrow Display Settings (Important)
Arrows usually need visual adjustment.
Additional setting example
PlotIndexSetInteger(0, PLOT_ARROW, 233);
Notes
- 233: up arrow in Wingdings
- The value may differ depending on the environment
6.5 Combined Logic (Moving Average + Signal)
In real work, multiple conditions are combined.
Example: MA cross
if(ma_fast[i] > ma_slow[i] && ma_fast[i-1] <= ma_slow[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
Core idea
Condition is true → assign value → display
6.6 Beginner Traps (Important)
Errors increase sharply at this stage.
1. Array range mistakes
→ i-1 / i-period
2. EMPTY_VALUE is not set
→ Arrows appear on every bar
3. Conditions are vague
→ Unintended signals
4. Logic and display are mixed
→ Debugging becomes difficult
6.7 Practical Design Guidelines
Indicator design becomes stable when you follow these rules.
1. Separate the calculation logic
2. Use buffers only for output
3. Keep conditions clear
6.8 Design for Future EA Integration
This matters if you plan to use the indicator in an EA later.
Points
- Fix buffer numbers
- Make signal values clear
- Disable invalid states with EMPTY_VALUE
Example
double signal = iCustom(Symbol(), Period(), "MyIndicator", 0, 0);
7. Common Errors and Troubleshooting (Cause → Fix)
This section organizes common problems in MQL5 indicator creation in a clear cause → fix format.
The conclusion is that most problems come down to three areas: Buffer, array range, and compilation.
7.1 Nothing Is Displayed (Most Common)
Symptom
- Nothing appears after applying the indicator
Main causes
- No value is assigned to the Buffer
- SetIndexBuffer is not set
- EMPTY_VALUE is used incorrectly
- Drawing type is not set
Fix
SetIndexBuffer(0, buffer);
buffer[i] = price[i];
Checklist
- Does the buffer contain real numeric values?
- Is OnCalculate running?
- Is indicator_plots set?
7.2 It Does Not Appear in Navigator
Symptom
- The indicator does not appear in the MT5 indicator list
Main causes
- It has not been compiled
- There is a compile error
- It is saved in the wrong location
Fix
- Compile with F7
- Check the error log
- Confirm it is in the Indicators folder
7.3 array out of range Error
Symptom
- Runtime crash or error
Main cause
price[i-1]
- It is being referenced when i=0
Fix
for(int i = MathMax(start, 1); i < rates_total; i++)
Core idea
Always perform boundary checks for array access
7.4 indicator buffers Related Errors
Symptom
- The display is broken or only partially shown
Main causes
- The number of buffers and indicator_plots do not match
- The SetIndexBuffer order is wrong
Fix
#property indicator_plots 2
SetIndexBuffer(0, buffer1);
SetIndexBuffer(1, buffer2);
7.5 Values Are Shifted or Delayed
Symptom
- The display appears one step late
Main causes
- prev_calculated is not considered
- Differential calculation is wrong
Fix
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
7.6 Values Appear on Every Bar (Incorrect Display)
Symptom
- Unintended lines or arrows appear in large numbers
Main cause
- EMPTY_VALUE is not used
Fix
buffer[i] = EMPTY_VALUE;
7.7 Compile Errors (Basic)
Symptom
- The code cannot be compiled
Main causes
- Syntax error
- Type mismatch
- Missing semicolon
Fix
- Always read the error message
- Check the line number
7.8 Performance Problem (Heavy Processing)
Symptom
- MT5 feels slow or nearly freezes
Main causes
- Full recalculation loop
- Unnecessary processing
Fix
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
7.9 Problems When Connecting with an EA
Symptom
- Values cannot be retrieved with iCustom
Main causes
- Wrong buffer number
- EMPTY_VALUE is returned
- Parameter mismatch
Fix
iCustom(Symbol(), Period(), "IndicatorName", ...);
Checkpoints
- Confirm the buffer index
- Match input parameters
- Use the exact file name
7.10 Practical Strategy to Avoid Problems
In real work, follow this process carefully.
1. Build small, using the minimum structure
2. Check operation
3. Add features gradually
Bad approach
- Writing complex logic all at once
Good approach
- Validate step by step
7.11 Error Priority (Practical Judgment)
The priority order is:
- Crash, such as array out of range
- Nothing is displayed
- Value misalignment
- Performance
8. How to Connect with an EA (Basics of iCustom and CopyBuffer)
This section explains how to use your custom indicator from an EA.
The conclusion is that the real value of creating indicators in MQL5 is not only the display itself, but the ability to reuse them from an EA.
In real projects, separating the indicator as the analysis component and the EA as the execution component improves maintainability and reproducibility.
8.1 Basic Structure for Using an Indicator from an EA
In MQL5, when calling a custom indicator from an EA, the main flow is:
1. Load the indicator with iCustom
2. Get the handle
3. Retrieve values with CopyBuffer
4. Use the values in trading conditions
The important point is that you do not directly read the indicator itself; you read the Buffer values.
8.2 What Is iCustom?
iCustom is a function that calls a custom indicator from an EA or another MQL5 program.
Its return value is the indicator “handle.” A handle is like an identifier used to operate the target.
Basic form
int handle = iCustom(Symbol(), Period(), "MyIndicator");
Meaning
Symbol(): current currency pairPeriod(): current timeframe"MyIndicator": indicator name
Notes
- The file name must be written accurately
- If it is in a subfolder, the path must be included
- It will not work unless it has been compiled
8.3 iCustom When input Parameters Exist
If your custom indicator has input parameters, pass them on the iCustom side in the same order.
Example: indicator side
input int period = 14;
EA side
int handle = iCustom(Symbol(), Period(), "MyIndicator", 14);
Important
- If the order is wrong, the indicator may behave incorrectly
- If the type is wrong, the value may not be passed correctly
- If you add parameters later, the EA side also needs to be updated
This is a point where beginners often get stuck.
Remember this rule: the indicator’s input definitions and the EA-side iCustom arguments must match.
8.4 Getting Values with CopyBuffer
The handle returned by iCustom alone is not enough to use numeric values.
You get the actual Buffer values with CopyBuffer.
Basic form
double values[];
if(CopyBuffer(handle, 0, 0, 3, values) > 0)
{
Print(values[0]);
}
Meaning of the arguments
handle: handle obtained with iCustom0: Buffer number0: start position for retrieval, the latest bar3: number of values to retrievevalues: receiving array
Practical meaning
values[0]: latest barvalues[1]: one bar agovalues[2]: two bars ago
8.5 How to Think About Buffer Numbers
For EA integration, you must make clear which Buffer contains which value.
Example
- Buffer 0: main line
- Buffer 1: signal line
- Buffer 2: BUY signal
- Buffer 3: SELL signal
EA side
double buy_signal[];
double sell_signal[];
CopyBuffer(handle, 2, 0, 1, buy_signal);
CopyBuffer(handle, 3, 0, 1, sell_signal);
Notes
- If you change a Buffer number later, the EA breaks
- Mixing display Buffers and integration Buffers makes management difficult
In real projects, it is best to fix the Buffer design at the beginning.
8.6 Basic Example of Signal Judgment
A design where the indicator side puts a value only on signal bars and uses EMPTY_VALUE otherwise works well with EA integration.
Indicator-side concept
if(buy_condition)
buy_buffer[i] = Close[i];
else
buy_buffer[i] = EMPTY_VALUE;
EA-side judgment example
double buy_signal[];
if(CopyBuffer(handle, 2, 0, 1, buy_signal) > 0)
{
if(buy_signal[0] != EMPTY_VALUE)
{
Print("BUY signal");
}
}
With this structure, the EA can judge the signal simply by checking
whether the value is not EMPTY_VALUE.
8.7 Common Mistakes and Notes
The following mistakes are very common in EA integration.
1. Wrong file name in iCustom
- The extension is usually not needed
- If the folder hierarchy is wrong, retrieval fails
2. Wrong Buffer number in CopyBuffer
- You may read a different Buffer than intended
- This can cause the chart display to look correct while the EA judgment is wrong
3. Mishandling the latest bar
values[0]may include the unfinished candle- If you want confirmed-bar logic, using
values[1]may be effective
4. Poor understanding of EMPTY_VALUE
- You may treat no signal as 0 by mistake
EMPTY_VALUEand numeric 0 are different
5. Not checking handle creation failure
- Without an
INVALID_HANDLEcheck, the cause can become hard to identify
8.8 How to Check Handle Creation Failure
Always validate the result of iCustom.
int handle = iCustom(Symbol(), Period(), "MyIndicator");
if(handle == INVALID_HANDLE)
{
Print("indicator handle create failed");
return;
}
Why this check is needed
- File name mistake
- Parameter mismatch
- Initialization failure on the indicator side
If you do not add this check, it becomes difficult to identify the cause even when a later CopyBuffer call fails.
8.9 Practical Design Guidelines
If you create an indicator with EA integration in mind, the following guidelines are effective.
1. Fix Buffer numbers
2. Manage signal Buffers with EMPTY_VALUE
3. Clearly state whether to use confirmed or unfinished bars
4. Keep the input structure stable
Important for reproducibility
- Keep chart display and trading judgment rules consistent
- Do not change Buffer numbers later
- Do not make signal definitions vague
This is not just a matter of coding style. It is a design choice that helps prevent differences between backtest results and live operation results.
8.10 Beginner-Friendly Conclusion
The minimum set beginners should remember is:
- Call the indicator with
iCustom - Read values with
CopyBuffer - Judge whether a signal exists using
EMPTY_VALUE
If you understand these three points, you have enough foundation to integrate your custom indicator into an EA.
9. Summary (How to Reach Practical Level Quickly)
Based on everything covered so far, this section organizes the core of MQL5 indicator creation and the shortest path to improvement.
The conclusion is that the important factor is not the amount of code, but structural understanding and reproducible design.
9.1 Core Nature of an Indicator (Redefined)
An MQL5 indicator works with the following structure:
Price data → calculate in OnCalculate → store in Buffer → draw automatically
If you understand this flow, you can create any type of indicator.
Core elements
- OnCalculate: calculation engine
- IndicatorBuffer: output
- Drawing settings: appearance
9.2 Three Minimum Points to Remember (Important)
Beginners should first focus only on the following.
1. Values appear when you put them into the Buffer
- Most display problems come from this point
2. OnCalculate controls everything
- It is the center of calculation and updates
3. EMPTY_VALUE controls drawing
- It is required for signal-type indicators
9.3 Thinking Required at a Practical Level
Simply making it run is not enough.
In real work, you need the following viewpoints.
1. Differential calculation for performance
Use prev_calculated → reduce unnecessary calculation
2. Array safety for stability
i-1 / i-period → always perform boundary checks
3. Buffer design for reusability
Fix the structure with EA integration in mind
9.4 Shortest Learning Route for Beginners
To improve efficiently, order matters.
Recommended steps
1. Create a minimal indicator
2. Confirm that it is displayed
3. Add conditional branches
4. Extend it to multiple Buffers
5. Connect it with an EA
Bad route
- Writing complex logic from the beginning
- Copying and pasting without understanding
9.5 Common Patterns Where Beginners Get Stuck
Many beginners stop at these points.
Pattern 1
“Nothing is displayed, and I do not know why.”
→ The cause is often an unset Buffer
Pattern 2
“I am afraid of errors, so I cannot move forward.”
→ Understanding array boundaries solves this
Pattern 3
“The logic is too complex.”
→ It should be divided into smaller parts
9.6 Most Important Practical Points
At a professional level, the following are evaluated.
| Item | Description |
|---|---|
| Reproducibility | Whether the same result can be reproduced |
| Stability | Whether errors are avoided |
| Lightweight design | Whether unnecessary processing is avoided |
| Extensibility | Whether it can connect with an EA |
9.7 Long-Term Applications
Indicator creation can develop into the following areas:
- Automated trading with EAs
- Signal delivery
- Analysis tools
- Combined logic using AI or statistics
The especially important viewpoint is to treat indicators as reusable components.
9.8 Conclusion (Practical Summary)
Ultimately, the important points are:
1. Understand the structure
2. Build small
3. Ensure reproducibility
If you follow these three points, you can develop stable indicators.
9.9 What to Do Next (Practical Actions)
After reading this article, the next steps are clear.
- Run the minimal code yourself
- Add one piece of your own logic
- Try retrieving the value from an EA
This turns your understanding from “knowledge” into “skill.”
FAQ
Q1. Why is my MQL5 indicator not displayed?
A. In many cases, the Buffer has not been registered or no value has been assigned to it. First check SetIndexBuffer and the assignment logic inside OnCalculate.
Q2. What does OnCalculate do?
A. OnCalculate receives price data, performs calculations, and stores the results in a Buffer. It is the core function of an indicator.
Q3. What is EMPTY_VALUE?
A. EMPTY_VALUE is a special value used when you do not want to draw anything on a bar. It is essential for signal displays.
Q4. Should I always use prev_calculated?
A. It is not strictly required, but in real projects you should use it for performance and stability. It reduces unnecessary recalculation.
Q5. How do I use an indicator from an EA?
A. Call the indicator with iCustom and retrieve its values with CopyBuffer. Those values can then be used in trading logic.
Q6. How can I prevent an array out of range error?
A. Always check index boundaries, especially when using references such as i-1 or i-period. Use safeguards such as MathMax where needed.
Q7. How do I display multiple lines?
A. Define multiple IndicatorBuffers and match them correctly with indicator_plots and SetIndexBuffer. Keep each Buffer number consistent.
Q8. What indicator should beginners create first?
A. Start with a simple indicator that displays the price as is. This makes it easier to understand the basic structure of OnCalculate and Buffer.