I am writing an MQL4 Custom Indicator that would tell how many bars ago a particular set of moving averages crossed.
To be specific, I want the output to show me that
"The 20 period
MA( .. PRICE_OPEN )
is belowMA( .. PRICE_CLOSE )
for the past 10 bars".
in a form of an int
number.
double ma1 = iMA( Symbol(), 10080, 20, 0, 0, PRICE_OPEN, 0 );
double ma2 = iMA( Symbol(), 10080, 20, 0, 0, PRICE_CLOSE, 0 );
I want to find out that ma1
has been above or below ma2
for how many bars since the current bar.
TLDR;
MQL4
Custom Indicator design is a bit schizophrenic task with 2 partsOnce decided to design a Custom Indicator, one has to pay attention to both sides of the coin.
MQL4
code has a non-trivial signature for a caller-side
( normally an
Expert Advisor or a Script type of MQL4 code )
and
Custom Indicator, on it's own,
operates in a special mode, where it calculates & store it's values into one or more arrays called IndexBuffer
-s.
Phase I.:
design Caller-side interface ( what all do we need to set / receive ? )
Phase II.:
design Custom Indicator implementation side
This way, the given indicator shall
period
... 20
int
a value of days { +:above | 0: xoss | -: under
}Phase I.
:
Design Caller-side interfaceGiven the above parametrisation and the MQL4
concept of Custom Indicator construction, the following universal template ( recommended to be routinely maintained as a commented section right in CustomIndicator
-file ) reflects details needed for the Caller-side interface ( which one benefits from by just a copy-paste mechanics, while the implementation-integrity responsibility is born by the CustomIndicator
maintainer ):
// CALL-er SIDE INTERFACE |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//
// #define sIndicatorPathNAME "#AliceInTheWonderlands_msMOD_0.00"
//
// //_____________________________________INPUT(s)
// // iMA_PERIOD:
// extern int iMA_PERIOD = 20;
//
// //_____________________________________OUTPUT(s):
// #define iOutputDoubleUpOrDnBUFFER 0
//
// //_____________________________________CALL-SIGNATURE:
//
// double iCustom( _Symbol, // string symbol, // symbol: Symbol name on the data of which the indicator will be calculated. NULL means the current symbol.
// PERIOD_W1, // int timeframe, // timeframe
// sIndicatorPathNAME, // string name, // path/name of the custom indicator compiled program: Custom indicator compiled program name, relative to the root indicators directory (MQL4/Indicators/). If the indicator is located in subdirectory, for example, in MQL4/Indicators/Examples, its name must be specified as "Examples\\indicator_name" (double backslash "\\"must be specified as separator instead of a single one).
// iMA_PERIOD, // ...[1] ..., // custom indicator [1]-st input parameter
// <<N/A>>, // ...[2+] // custom indicator further input parameters (if necessary)
// iOutputDoubleUpOrDnBUFFER, // int mode, // line index: Line index. Can be from 0 to 7 and must correspond with the index, specified in call of the SetIndexBuffer() function.
// i // int bar_shift // shift
// );
// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Typical Expert Advisor call looks like this:
int anIndicatorVALUE = iCustom( _Symbol,
PERIOD_W1,
sIndicatorPathNAME,
iMA_PERIOD,
iOutputDoubleUpOrDnBUFFER,
aCurrentBarPTR
);
if ( 0 > anIndicatorVALUE ) // on "line" under for <anIndicatorVALUE> [PERIOD]-s
{ ...
}
Phase II.
:
Design Custom Indicator implementation sidePreset an overall capacity
#property indicator_buffers 1 // compile time directive
Allocate memory for IndexBuffer
(s) needed
IndicatorBuffers( 1 ); // upper limit of 512 is "far" enough
Declare IndexBuffer
double UpOrDnBUFFER[]; // mandatory to be a double
Associate IndexBuffer
with an index
SetIndexBuffer( 0, UpOrDnBUFFER ); // index 0: UpOrDnBUFFER[]
ArraySetAsSeries( UpOrDnBUFFER, True ); // reverse AFTER association
The core logic of any Custom Indicator is inside an OnCalculate()
function, where you
- implement desired calculus
and
- store resulting values into respective cells of the UpOrDnBUFFER[];
Writing a fully fledged code upon request is not the key objective of StackOverflow, but let me sketch a few notes on this, as Custom Indicator implementation side requires a bit practice:
because Custom Indicator OnCalculate()
operates "progressively", so do design your calculation strategy & keep in mind the state-less-ness between "blocks" of forward-progressive blocks of calculations.
as given, crosses are tri-state system, so watch issues on cases, where decisions are made on a "live" bar, where the state { above
| cross
| under
} may change many times during the bar-evolution.