Writing user indicators and functions in trading system has a number of features, as well:
• Parameters to be taken into consideration for user indicators and functions should be described in
the Inputs section and be of numeric data type.
Inputs: nPeriod(13),nDeviation(0.1),nAccountedBars(300);
• Parameters will be sent to the function of custom indicator calculation in the order in which they are
described. For example, call the custom indicator having the parameters listed above will appear as follows:
iCustom( "SomeIndicator", 13, 0.1, 300, MODE_FIRST, 0 );
• Strictly speaking, parameters should not be necessarily sent to the function. If the function does not
have an Inputs section it is no use to send the parameters. Or one can use the initial values being applied
for describing parameters. For example, call the same custom indicator without parameters will appear as
follows:
iCustom( "SomeIndicator", MODE_FIRST, 0 );
This means that those values will be used which are stored in variables described in the Inputs section,i.e.
13, 0.1 and 300.
• What is the difference between the function of custom indicator calculation and a simple user
function? It is defined by the methods of call. The function of custom indicator is called once when
recalculation of the whole array of price data. The simple user function is called during the expert program
working, i.e. with each tick. The function of custom indicator calculation has access to two arrays storing the
results of calculation with the help of functions named SetIndexValue, SetIndexValue2, GetIndexValue,
GetIndexValue2. And the simple user function has access to these arrays with the help of iCustom
function. The function of custom indicator calculation can not call trading functions and functions of call of
user functions. User function should be finished with the call of the Return function in order to send the
value calculated to the expert-caller.
• There is a special value of index array which means the absence of data, it is 0. If zero value is
significant in any of the custom indicators, it is necessary to use a very small value, for example,
0.00000001. It is necessary to note that when displaying the custom indicators in the pop-up prompts, the
accuracy of 4 signs after the dot in decimal fraction will be used. Indicator placed in the price chart can not
have negative data as they can not be displayed in any case. That is why negative values of the indicator
placed in the price chart will also be considered as special ones. (The features of use of special values of
custom indicators being placed in the price chart are discussed below.)
• The values of the variables in the function of custom indicator calculation, and the data arrays with
the results of custom indicator calculation will be initialized at the first run of the indicator, and at the period
or instrument change at the chart. It means, all values will be stored between initializations! When custom
indicator is programmed in a proper and accurate way it is possible to provide the possibility of calculation of
only last, not calculated values, data arrays of the indicator. An example of an indicator of a simple moving
average:
/*[[
Name := SimpleMA
Author := Copyright (c) 2003, MetaQuotes Software Corp.
Link := [You must be registered and logged in to see this link.]
Separate Window := No
First Color := Red
First Draw Type := Line
Use Second Data := No
]]*/Inputs : MAPeriod(13);Variables : shift(0), cnt(0), loopbegin(0), first(True), prevbars(0), sum(0);SetLoopCount(0);// initial checkingsIf MAPeriod < 1 Then Exit;// check for additional bars loading or total reloadingIf Bars < prevbars Or Bars-prevbars>1 Then first = True;prevbars = Bars;If first Then Begin//loopbegin prevent couning of counted bars exclude currentloopbegin = Bars-MAPeriod-1;If loopbegin < 0 Then Exit; // not enough bars for countingfirst = False;End;// moving averageloopbegin = loopbegin+1; // current bar is to be recounted tooFor shift = loopbegin Downto 0 Beginsum = 0;For cnt = 0 To MAPeriod-1 Beginsum = sum + Close[shift+cnt];End;SetIndexValue(shift,sum/MAPeriod);loopbegin = loopbegin-1; // prevent to previous bars recountingEnd;
Explanations for the code. In the first variable after initialization the True value is stored. As soon as the
indicator runs for the first time the check of the first variable will be conducted and the value of the loopbegin
variable will be established on the assumption that the cycle would run from the data beginning.
When the
cycle is running the loopbegin variable is modified and contents in fact the value of the index of the last value calculated in the indicator array. In the case of "loop detected", the indicator expert will stop its work.
But the first variable is established in False, it means that at the next start the loopbegin variable will not be
established at the beginning of the indicator array. It means that the new calculation will be continued from
the point where the previous calculation has been made. At the end, all the bars will be calculated. But if we
need to recalculate the indicator value at the current bar with the coming of each new quote we modify the
loopbegin variable before the cycle starts, increasing it by 1 to realize at least 1 cycle iteration.
If the historical data were spooled (Refresh Chart) or reloaded (Erase and Refresh Chart) the condition of
the comparing of the current number of bars with the previous number of those would allow us to recalculate
indicator on all data.
• Custom indicator function can be called not only from the expert program, but also from the
"Navigator" window when selecting Custom Indicator. In this connection, there are several features of
designing such a program. An example of the "Envelopes" indicator:
/*[[
Name := Envelopes
Author := Copyright (c) 2003, MetaQuotes Software Corp.
Link := [You must be registered and logged in to see this link.]
Notes := Sample Custom Indicator program
Separate Window := No
First Color := Blue
First Draw Type := Line
Use Second Data := Yes
Second Color := Red
Second Draw Type := Line
]]*/Inputs : nPeriod(13),nDeviation(0.1),nAccountedBars(300);Vars : CurrentBar(0),shift(0),i(0),sum(0),UpperBand(0),LowerBand(0),BeginBar(0);Vars : prevBars(0);If prevBars = Bars Then Exit;prevBars = Bars;SetLoopCount(0);BeginBar = Bars – nAccountedBars;If BeginBar < 0 then BeginBar = 0;For CurrentBar = 0 To BeginBar-1 Beginshift = Bars-1-CurrentBar;SetIndexValue(shift, 0);SetIndexValue2(shift, 0);End;For CurrentBar = BeginBar To Bars-1 Beginshift = Bars – 1 – CurrentBar;If CurrentBar < nPeriod-1 Then Begin;SetIndexValue(shift, 0);SetIndexValue2(shift, 0);Continue;End;sum = 0;For i=0 To nPeriod-1 Beginsum = sum + Close[shift+i];End;sum = sum / nPeriod;UpperBand = sum * (1 + nDeviation/100);LowerBand = sum * (1 – nDeviation/100);SetIndexValue(shift, UpperBand);SetIndexValue2(shift, LowerBand);End;As you can see the "Experts Wizard" creates the description of custom indicator differing from the
description of the expert program.
Separate Window := No – means that the indicator chart will be developed in the same window where the
price chart is developed. If the values calculated with the custom indicator differ from the current prices very
much, the indicator chart must be shown in a separate window.
Draw Type := Line – means that the indicator chart will be developed as a line. It is also possible to develop
a histogram (Histogram) or to show a separate symbol (Symbol; in this case, the symbol will be set as a
number defining the position of the symbol in the "Wingdings" table. For example, First Symbol := 217).
Use Second Data := Yes – means that the indicator calculation results in 2 charts, and not the only one
(another example: MACD histogram and signal line). First Color, First Draw Type and First Symbol
belong to the first indicator chart, the Second Color, Second Draw Type and Second Symbol belong to
the second one.
If the indicator is shown in a separate window and the limiting values of the minimum and/or maximum are
known beforehand, these limiting values can be defined to accelerate the displaying and, in some case, to
make the displaying more beautiful (this especially concerns histograms). Experts Master will, for example,
design it, as follows:
Minimum Chart Limits := –1.000000
Maximum Chart Limits := 1.000000All parameters listed and made with the Expert Master help in quick setting of Custom Indicator.
[You must be registered and logged in to see this image.]• As it was mentioned above, the user expert chart can be displayed as a histogram. There is a
feature of displaying the histogram in the price chart window. Both data arrays of the Custom Indicator
participate in the process of histogram displaying. The line will be drawn at the chart from the first value to
the second corresponding one. If the first value is more than the second one the line will be drawn with the
first color. Otherwise, it will be drawn with the second color. This feature can be used when coloring the bars
with different colors.
/*[[
Name := ColoredBars
Author := Copyright (c) 2003, MetaQuotes Software Corp.
Link := [You must be registered and logged in to see this link.]
Notes := Sample Custom Indicator program
Separate Window := No
First Color := Blue
First Draw Type := Histogram
Use Second Data := Yes
Second Color := Pink
Second Draw Type := Histogram
]]*/Variables : CurrentBar(0),shift(0),nBWMFI(0),prevBWMFI(0),value1(0),value2(0);SetLoopCount(0);For CurrentBar = 0 To Bars-1 Beginshift = Bars-1-CurrentBar;nBWMFI = (High[shift] – Low[shift]) / Volume[shift];If CurrentBar < 1 Then BeginSetIndexValue(shift, 0);SetIndexValue2(shift, 0);prevBWMFI = nBWMFI;Continue;End;value1 = 0;value2 = 0;If nBWMFI > prevBWMFI and Volume[shift] < Volume[shift+1] Then Beginvalue1 = High[shift];value2 = Low[shift];End;If nBWMFI < prevBWMFI and Volume[shift] > Volume[shift+1] Then Beginvalue1 = Low[shift];value2 = High[shift];End;SetIndexValue(shift, value1);SetIndexValue2(shift, value2);prevBWMFI = nBWMFI;End;The example given above illustrates coloring the bars in "Bill Williams" style. If necessary, it is possible to
prepare another program of custom indicator to color bars with two other colors corresponding with other
conditions.
• The features of special values processing were mentioned above which had been less or equal to 0
and concerned the "line" custom indicators placed in the price chart. 0 means the absence of data. The line
will be plotted between points having positive values. A negative value means the end of the previous line.
I.e., lines can be interrupted. As an illustration of the "absence of data" an example of the "ZigZag" indicator
is given below which plots lines between local price extremes.
/*[[
Name := ZigZag
Author := Copyright (c) 2003, MetaQuotes Software Corp.
Link := [You must be registered and logged in to see this link.]
Separate Window := No
First Color := Blue
First Draw Type := Line
Use Second Data := No
]]*/Inputs: depth(12),deviation(5),backstep(3);Variables : shift(0),lasthigh(-1),lastlow(-1),lasthighpos(0),lastlowpos(0);Variables : val(0),back(0),res(0);Variables : curlow(0),curhigh(0);SetLoopCount(0);lasthigh=-1;lastlow=-1;for shift = Bars-300 downto 0{//-- lowval=Low[Lowest(MODE_LOW,shift+depth-1,depth)];if val==lastlow then val=0else{lastlow=val;if (Low[shift]-val)>(deviation*Point) then val=0else{for back=1 to backstep{res=GetIndexValue(shift+back);if res!=0 and res>val then SetIndexValue(shift+back,0);};};};SetIndexValue(shift,val);//-- highval=High[Highest(MODE_HIGH,shift+depth-1,depth)];if val==lasthigh then val=0else{lasthigh=val;if (val-High[shift])>(deviation*Point) then val=0else{for back=1 to backstep{res=GetIndexValue2(shift+back);if res!=0 and res};};};SetIndexValue2(shift,val);};// final cuttinglasthigh=-1; lasthighpos=-1;lastlow=-1; lastlowpos=-1;for shift = Bars-300 downto 0{curlow=GetIndexValue(shift);curhigh=GetIndexValue2(shift);if curlow == 0 & curhigh == 0 then continue;//--if curhigh!=0 then{if lasthigh>0 then{if lasthighelse SetIndexValue2(shift,0);};//--if lasthigh{lasthigh=curhigh;lasthighpos=shift;};lastlow=-1;};if curlow!=0 then{if lastlow>0 then{if lastlow>curlow then SetIndexValue(lastlowpos,0)else SetIndexValue(shift,0);};//--if curlow{lastlow=curlow;lastlowpos=shift;};lasthigh=-1;};};for shift = Bars-300 downto 0{res=GetIndexValue2(shift);if res!=0 then SetIndexValue(shift,res);};As a result, the indicator given above fills the first indicator data array with the extreme values. The values
between extremes are zero values. The lines are drawn between extremes (i.e., between positive values).
• As an illustration of symbols displaying in defining the position of the price chart a program of the
simplest calculation of "Bill Williams" fractals is given below:
/*[[
Name := Fractals
Author := Copyright (c) 2003, MetaQuotes Software Corp.
Link := [You must be registered and logged in to see this link.]
Notes := Sample Custom Indicator program
Separate Window := No
First Color := Blue
First Draw Type := Symbol
First Symbol := 217
Use Second Data := Yes
Second Color := Red
Second Draw Type := Symbol
Second Symbol := 218
]]*/Variable : value(0),CurrentBar(0), price(0);SetLoopCount(0);For CurrentBar = 0 To Bars-1 BeginIf CurrentBar < 2 Or CurrentBar >= Bars-2 Then BeginSetIndexValue(CurrentBar, 0);SetIndexValue2(CurrentBar, 0);Continue;End;value = 0;price = High[CurrentBar];If price>High[CurrentBar+1] and price>High[CurrentBar+2] andprice>High[CurrentBar-1] and price>High[CurrentBar-2]then value = price;SetIndexValue(CurrentBar, value);value = 0;price = Low[CurrentBar];If pricepricethen value = price;SetIndexValue2(CurrentBar, value);End;A user function example. Before using the function, it is necessary to be sure that it has been successfullytranslated, and that there is a corresponding exp-file in the expert catalogue./*[[
Name := UserFunc
Author := Copyright (c) 2003, Metaquotes Software Corp.
Link := [You must be registered and logged in to see this link.]
]]*/Input : parameter(0);print( "Input parameter is ", parameter );return( parameter );User Function call sample:Variable: ReturnValue(0);ReturnValue = UserFunction( "UserFunc", Close );print( "Return value is ", ReturnValue );• It must be noted that the overflow of custom indicators, improperly written user functions can
slow down the functioning of the client terminal!