Obey the calling-signatures:
The { iMAOnArray | iStdDevOnArray() | ... }
indicator is calculated from left to right.
To access to the array elements as to a series array (i.e., from right to left),
one has to use the ArraySetAsSeries()
function.
double iMAOnArray( double array[], // array with data <--------------
int total, // number of elements <-----------
int ma_period, // MA averaging period
int ma_shift, // MA shift
int ma_method, // MA averaging method
int shift // shift
)
double iStdDevOnArray( double array[], // array with data <--------------
int total, // number of elements <-----------
int ma_period, // MA averaging period
int ma_shift, // MA shift
int ma_method, // MA averaging method
int shift // shift
)
The second section was extremely low-performing:
MT4 Terminal is known for having a one central bottleneck. The all-graphs' shared solo-thread for each CustomIndicator
instance. So be many times more careful inside the CustomIndicator
code:
Counted_bars = IndicatorCounted();
i = Bars - Counted_bars - 1;
while( i > 0 )
{ Moving_Average_Close = iMA( _Symbol, PERIOD_CURRENT, 40, 0, MODE_EMA, PRICE_CLOSE, i );
Moving_Average_Low = iMA( _Symbol, PERIOD_CURRENT, 40, 0, MODE_EMA, PRICE_LOW, i );
Moving_Average_High = iMA( _Symbol, PERIOD_CURRENT, 40, 0, MODE_EMA, PRICE_HIGH, i );
ATR = iATR( _Symbol, PERIOD_CURRENT, 14, i );
if ( close[i] < Moving_Average_Close )
{ ATREx[i] = ( ( ( low[i] - Moving_Average_Low ) / close[i] ) * 100 ) * ( ( ATR / close[i] ) * 100 );
// ATREx_200[i] = ( ( ( low[i] - Moving_Average_Low_200 ) / close[i] ) * 100 ) * ( ( ATR / close[i] ) * 100 );
}
else ATREx[i] = ( ( ( high[i] - Moving_Average_High ) / close[i] ) * 100 ) * ( ( ATR / close[i] ) * 100 );
i--;
}
int nBARs = 40; // //?40 vvv // NEVER LEAVE ANY FULL-DEPTH PROCESSING aFeasibleDEPTH WILL SUITE ENOUGH
double aCPY[]; // ||
ArraySetAsSeries(); // ||
// ||
j = Bars - Counted_bars - 1; // ||
while( j > 0 ) // || ?40 // OUGHT BE 40?
{ ArrayCopy( aCPY, ATREx, 0, j, nBARs );// vv vvv
double aStDev = iStdDevOnArray( aCPY, nBARs, 200, 0, MODE_EMA, 0 ), // NEVER LEAVE ANY EXTENSIVE PROCESSING PIECE OF CODE IN INDICATOR (a blocking solo-thread for *ALL* MT4.Graphs !!! )
aMeanL = iMAOnArray( aCPY, nBARs, 40, 0, MODE_EMA, 0 ); // NEVER LEAVE ANY EXTENSIVE PROCESSING PIECE OF CODE IN INDICATOR ( a blocking solo-thread for *ALL* MT4.Graphs !!! )
ATREx_Upper[j] = aMean + aStDev; // REUSE VALUEs NEVER RE-PROCESS THE SAME THING, THAT HAS ALREADY BEEN COMPUTED
ATREx_Lower[j] = aMean - aStDev; // REUSE VALUEs NEVER RE-PROCESS THE SAME THING, THAT HAS ALREADY BEEN COMPUTED
// *******************************************************************************************************************
// WAS 4x MORE EXPENSIVE:
// *******************************************************************************************************************
// ATREx_Upper[j] = iMAOnArray( ATREx, 0, 40, 0, MODE_EMA, j ) + iStdDevOnArray( ATREx, 0, 200, 0, MODE_EMA, j );
// ATREx_Lower[j] = iMAOnArray( ATREx, 0, 40, 0, MODE_EMA, j ) - iStdDevOnArray( ATREx, 0, 200, 0, MODE_EMA, j );
// *******************************************************************************************************************
j--;
}
Epilogue and Errata:
double aCPY[]; // best put MEM .ALLOC in file-scope declarations
ArraySetAsSeries( aCPY, True ); // lock a TimeSeries ordering right there
While nBARs
may require some quantitative modeling to meet the best precision / computing_expenses balance, it is warmly recommended not to copy WHOLE_ARRAY
, unless any indeed ( mathematically supported ) full-depth reverse-stepped convolution ( where any change in [0] is due to get computationally back-propagated, in a domino manner, deeper-back into aTimeDOMAIN history -- which for obvious reasons is the very opposite sort of behaviour, right on the contrary to the needs that a quantitatively based Technical Analysis is happy to work with. ). So rather copy, as Albert EINSTEIN has so lovely coined for modern physics - "COPY AS-MUCH BARS BACK, AS NEEDED, BUT NOT A SINGLE MORE" - then you have the best performance.
While the repetitive use of iMAOnArray()
and iStdDevOnArray()
, it is not numerically and computationally as efficient as if using a sliding window computing, that never re-calculates any value, but improves the speed by re-using all already once computed values -- iMAOnArray( ATTREx, WHOLE_ARRAY, 3, 0, MODE_SMA, j);
being one of the examples, as being re-looped in [j]
by while(){...}
.