Features of Custom Indicators Creation
Features of Custom Indicators Creation
Features of Custom Indicators Creation
Creation of Custom Indicators in the MetaTrader trading system has a number of features.
For the program to be considered a Custom Indicator, it must fall under one of two definitions:
or
To set the scale of a separate indicator window, the following definitions are used:
where "Min_Value" and "Max_Value" are corresponding values. For example, these values must be 0
and 100 respectively for custom indicator RSI.
The number of indicator arrays necessary for drawing an indicator must be defined as follows:
#property indicator_buffers N
...
There are functions allowing to control the process of indicator calculation and visualization.
Custom Indicator of Ishimoku Kinko Hyo is used here to illustrate it:
//+------------------------------------------------------------------+
//| Ichimoku.mq4 |
//| https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 7
double Tenkan_Buffer[];
double Kijun_Buffer[];
double SpanA_Buffer[];
double SpanB_Buffer[];
double Chinkou_Buffer[];
double SpanA2_Buffer[];
double SpanB2_Buffer[];
int a_begin;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int init()
{
//----
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,Tenkan_Buffer);
SetIndexDrawBegin(0,Tenkan-1);
SetIndexLabel(0,"Tenkan Sen");
//----
SetIndexStyle(1,DRAW_LINE);
SetIndexBuffer(1,Kijun_Buffer);
SetIndexDrawBegin(1,Kijun-1);
SetIndexLabel(1,"Kijun Sen");
//----
SetIndexStyle(2,DRAW_HISTOGRAM,STYLE_DOT);
SetIndexBuffer(2,SpanA_Buffer);
SetIndexDrawBegin(2,Kijun+a_begin-1);
SetIndexShift(2,Kijun);
SetIndexLabel(2,NULL);
SetIndexStyle(5,DRAW_LINE,STYLE_DOT);
SetIndexBuffer(5,SpanA2_Buffer);
SetIndexDrawBegin(5,Kijun+a_begin-1);
SetIndexShift(5,Kijun);
//----
SetIndexStyle(3,DRAW_HISTOGRAM,STYLE_DOT);
SetIndexBuffer(3,SpanB_Buffer);
SetIndexDrawBegin(3,Kijun+Senkou-1);
SetIndexShift(3,Kijun);
SetIndexLabel(3,NULL);
SetIndexStyle(6,DRAW_LINE,STYLE_DOT);
SetIndexBuffer(6,SpanB2_Buffer);
SetIndexDrawBegin(6,Kijun+Senkou-1);
SetIndexShift(6,Kijun);
//----
SetIndexStyle(4,DRAW_LINE);
SetIndexBuffer(4,Chinkou_Buffer);
SetIndexShift(4,-Kijun);
SetIndexLabel(4,"Chinkou Span");
//----
return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int start()
{
int i,k;
int counted_bars=IndicatorCounted();
double high,low,price;
//----
if(counted_bars<1)
{
for(i=1;i<=Tenkan;i++) Tenkan_Buffer[Bars-i]=0;
for(i=1;i<=Kijun;i++) Kijun_Buffer[Bars-i]=0;
i=Bars-Tenkan;
if(counted_bars>Tenkan) i=Bars-counted_bars-1;
while(i>=0)
{
while(k>=i)
{
price=High[k];
if(high<price) high=price;
price=Low[k];
if(low>price) low=price;
k--;
}
Tenkan_Buffer[i]=(high+low)/2;
i--;
}
i=Bars-Kijun;
if(counted_bars>Kijun) i=Bars-counted_bars-1;
while(i>=0)
{
while(k>=i)
{
price=High[k];
if(high<price) high=price;
price=Low[k];
if(low>price) low=price;
k--;
}
Kijun_Buffer[i]=(high+low)/2;
i--;
}
i=Bars-a_begin+1;
if(counted_bars>a_begin-1) i=Bars-counted_bars-1;
while(i>=0)
{
price=(Kijun_Buffer[i]+Tenkan_Buffer[i])/2;
SpanA_Buffer[i]=price;
SpanA2_Buffer[i]=price;
i--;
}
i=Bars-Senkou;
if(counted_bars>Senkou) i=Bars-counted_bars-1;
while(i>=0)
{
while(k>=i)
{
price=High[k];
if(high<price) high=price;
price=Low[k];
if(low>price) low=price;
k--;
}
price=(high+low)/2;
SpanB_Buffer[i]=price;
SpanB2_Buffer[i]=price;
i--;
}
i=Bars-1;
if(counted_bars>1) i=Bars-counted_bars-1;
//----
return(0);
}
//+------------------------------------------------------------------+
"SetIndexStyle" function controls drawing parameters of an indicator array. The drawing mode
of DRAW_LINE assumes that lines between values defined in a corresponding indicator array are
drawn. The drawing mode of DRAW_HISTOGRAM having been applied to the main window
indicator has its special features, as well. A histogram is drawn between corresponding values of
two index arrays: an even one (here: SpanA_Buffer) and an odd one (here: SpanB_Buffer). At
that, the color of the index array is used the value of which is higher.
"SetIndexDrawBegin" function specifies which element significant data of indicator array start
at.
"SetIndexBuffer" function allows to declare any one-dimensional array of the "double" type as
an index array. At that, the system will manage index arrays. It is for this reason that is not
required to specify these arrays.
double Tenkan_Buffer[];
double Kijun_Buffer[];
double SpanA_Buffer[];
double SpanB_Buffer[];
double Chinkou_Buffer[];
double SpanA2_Buffer[];
double SpanB2_Buffer[];
The ArrayResize function cannot be applied to indicator arrays, either, as it is useless. It is useless, as
well, to apply the ArrayInitialize function to indicator arrays, especially as 'init' function, when indicator
arrays have not been allocated yet. Indicator arrays are initialized automatically during memory
allocation and reallocation. EMPTY_VALUE, or the value specified by SetIndexEmptyValue function, are
used as initializing values. "Empty" values are not displayed.
The "SetIndexLabel" function sets the name to be displayed in tool tips and in data window
along with the corresponding value (the "ValueN" is set by default, where N is the number of
the index array). If NULL is transferred instead of a name, the corresponding value will be
displayed neither in tool tips, nor in the data window. In the given case, clouds are hatched
using a histogram and limited by a line. At that, the values of corresponding "line" and
"histogram" arrays are the same, and it is possible to show only one of them.
Let us discuss one more example. The custom indicator named Accelerator/Decelerator
Oscillator:
//+------------------------------------------------------------------+
//| Accelerator.mq4 |
//| https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 3
double ExtBuffer1[];
double ExtBuffer2[];
double ExtBuffer3[];
double ExtBuffer4[];
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int init()
{
IndicatorBuffers(5);
SetIndexStyle(0,DRAW_NONE);
SetIndexStyle(1,DRAW_HISTOGRAM);
SetIndexStyle(2,DRAW_HISTOGRAM);
IndicatorDigits(Digits+2);
SetIndexDrawBegin(0,38);
SetIndexDrawBegin(1,38);
SetIndexDrawBegin(2,38);
SetIndexBuffer(0,ExtBuffer0);
SetIndexBuffer(1,ExtBuffer1);
SetIndexBuffer(2,ExtBuffer2);
SetIndexBuffer(3,ExtBuffer3);
SetIndexBuffer(4,ExtBuffer4);
IndicatorShortName("AC");
SetIndexLabel(1,NULL);
SetIndexLabel(2,NULL);
return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
double prev,current;
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;
ExtBuffer3[i]=iMA(NULL,0,5,0,MODE_SMA,PRICE_MEDIAN,i)-
iMA(NULL,0,34,0,MODE_SMA,PRICE_MEDIAN,i);
ExtBuffer4[i]=iMAOnArray(ExtBuffer3,Bars,5,0,MODE_SMA,i);
bool up=true;
{
current=ExtBuffer3[i]-ExtBuffer4[i];
prev=ExtBuffer3[i+1]-ExtBuffer4[i+1];
if(current>prev) up=true;
if(current<prev) up=false;
if(!up)
{
ExtBuffer2[i]=current;
ExtBuffer1[i]=0.0;
}
else
{
ExtBuffer1[i]=current;
ExtBuffer2[i]=0.0;
}
ExtBuffer0[i]=current;
}
//---- done
return(0);
}
//+------------------------------------------------------------------+
The "SetIndexDigits" function manages the precision of information output. In this case, when
the difference between two moving averages as well as the further difference between the
result and the signal line is calculated, the standard precision of within 4 characters after point is
obviously insufficient.
The "SetIndexDrawBegin" function determines the significant starting element of the indicator
array. In our example, the signal line is calculated as simple moving average of another simple
moving average. This is why the first 38 values of the indicator are considered as empty ones
and are not to be drawn.
The "IndicatorShortName" function sets a so-called short name of the indicator to be displayed
in the upper left corner of the indicator window and in "DataWindow". If the short name has not
been set up, the custom indicator name will be used as the former one. In the given example,
there is no need to use the SetIndexLabel function, because only one value is output. So, the
name of the indicator is enough for output of a single value.
The "SetIndexStyle" function manages drawing parameters of an indicator array. The drawing
mode of DRAW_NONE means that the line does not need to be drawn. The matter is that
histogram of the indicator presented must be colored in 2 different colors. Data from ExtBuffer0
are allocated in two other arrays, ExtBuffer1 and ExtBuffer2. In order not to output doubling
data in tool tips or in data window, the SetIndexLabel function having NULL parameter is used.
The drawing mode of DRAW_HISTOGRAM being applied to the indicator of a separate window
allows to draw histogram between zero value and the value of a corresponding array (compare
with drawing of a histogram in the main window described above).
Input parameters used for calculation by custom indicators and functions must be defined as
"extern" and may be of any type.
If input parameters have not been set the corresponding custom indicator will be called in the
simplest format.
The transfer of the first two values "NULL" and "0" means that the current chart will be used. The name
of the corresponding file (without extension of mq4) is used as custom indicator name. If the last but
one parameter is 0, it means that we are interested in the data from the very first indicator array. The
last parameter being 0 means that we are interested in the value of the last element (i.e., the most
recent, current value) of indicator array requested.
Parameters are transferred in the function of custom indicator calculation in the order they
have been described. For example, custom indicator named "Ichimoku" and having parameters
of (9,26,52) will be called as follows:
Strictly speaking, custom indicator parameters do not need to be necessarily transferred to the function.
If no one extern variable is defined in the program, it is useless to trasnfer parameters. Or, if necessary,
initial values can be used that are used in description of parameters. For example, the same custom
indicator without parameters will be called as follows:
This means that the values will be used that initialize variables "Tenkan", "Kijun", "Senkou", i.e., 9, 26,
and 52. However, if one custom indicator having different sets of parameters is called in one Expert
Advisor, default settings are highly not recommended to be used.
It must be noted that the surplus of custom indicators as well as incorrectly written ones can decelerate
the work of client terminal significantly!
Warning: All rights for these materials are reserved by MetaQuotes Software Corp. Complete or partial
reproduction is prohibited.