Promediación efectiva de algoritmos con retraso mínimo: Uso en indicadores

Nikolay Kositsin | 11 mayo, 2016


Introducción

Creo que no es necesario explicar lo importante que es refinar los algoritmos para el análisis técnico y los sistemas de trading. Los códigos de casi todos los indicadores contienen algoritmos de promediación explícitos o implícitos. Si miramos más de cerca las plataformas de trading y los terminales de cliente en línea, la mayoría de ellos y la mayoría de indicadores resultan ser los más sencillos (aunque no los más efectivos) algoritmos de promediación.

Actualmente se han desarrollado algoritmos de promediación mucho más efectivos. No obstante, el intento de aplicarlos a los indicadores suele, debido a la gran complejidad de los algoritmos, dar como resultado que los programadores no tengan la paciencia suficiente y que creen como mucho uno o dos indicadores que de ningún modo operan siempre de forma correcta. Después de todo, suelen estar cansados de trabajar en este sentido. La ventaja básica de las medias simples es que siempre están disponibles como funciones personalizadas sencillas que pueden aplicarse en cualquier lugar y en cualquier momento.


Tema central

En este artículo me gustaría explicar a los traders que conocen MQL4 los algoritmos de promediación efectivos con un retraso mínimo representados como simples funciones personalizadas. El uso de estas funciones no es mucho más complejo que el de los indicadores técnicos. Las funciones se escribieron mucho antes y la calidad de su funcionamiento también ha sido comprobada durante bastante tiempo. En ellos no se han encontrado fallos, problemas ni cálculos incorrectos. Por ello, vamos a considerar los siguientes algoritmos:
- JJMASeries () - algoritmo adaptativo de ajuste de JMA;
- JLiteSeries() - algoritmo de ajuste de JMA sin algoritmo adaptativo;
- JurXSeries () - algoritmo de ajuste ultralineal obtenido del indicador JRSX;
- ParMASeries() - algoritmo de ajuste basado en una aproximación parabólica;
- LRMASeries () - algoritmo de ajuste basado en una progresión lineal;
- T3Series () - algoritmo de ajuste basado en el algoritmo Tilson.

Ajuste de funciones

Las funciones se representan en los archivos siguientes: JJMASeries.mqh, JLiteSeries. mqh, JurXSeries. mqh, ParMASeries.mqh, LRMASeries.mqh, T3Series.mqh.

Las llamadas a las propias funciones son absolutamente idénticas, la única diferencia es que algunas funciones no tienen algunas variables externas. Dichas funciones se suelen utilizar para procesar matrices personalizadas y de indicadores que operan como variables externas. En mi opinión, no siempre es adecuado, por lo que sería mucho mejor usar estas funciones para procesar variables normales, no matrices. En este caso, podemos hacer una cantidad ilimitada de ajustes usando estos algoritmos en un solo ciclo de cómputo. Creo que no es necesario proporcionar el código de estas funciones en este artículo. El código será interesante solo para aquellos que vayan a crear funciones similares basadas en otros algoritmos. Nos interesa solo el algoritmo de llamada a la función en el código del indicador, es decir, en el uso práctico de las funciones.

JJMASeries ()
Empezaremos aprendiéndolas con la función JJMASeries():

double JJMASeries(int number, int din, int MaxBar, int limit, 
                  int Phase, int Length, double series, int bar,
                  int& reset)

El archivo JJMASeries.mqh contiene cuatro funciones: JJMASeries(), JJMASeriesResize(), JJMASeriesAlert() y JMA_ErrDescr(). El archivo contiene también las variables declaradas como globales.


La función JJMASeries() tiene por finalidad usar el algoritmo JMA al escribir cualquier indicador técnico o asesor experto, para sustituir el clásico cálculo de promediación con este algoritmo. La función no opera si el parámetro 'limit' toma el valor cero. Todos los indicadores que he desarrollado para JJMASeries están diseñados teniendo en cuenta esta limitación. El archivo debe guardarse en la carpeta MetaTrader\experts\include\. Debe recordarse que si el valor de la variable 'bar' supera el de la variable MaxBar, la función JJMASeries() devolverá un valor cero para esta barra. Y, por tanto, este valor puede no estar presente como término de una fracción en los cálculos de algunos indicadores. JJMASeries() también devolverá cero en las consiguientes 30 barras.

Esta versión de JJMASeries() ayuda a los asesores expertos cuando funciona en los indicadores personalizados usados por el asesor experto. Además, esta versión de JJMASeries() ayuda a los asesores expertos cuando funciona en el código del indicador colocado completamente en el código del experto y manteniendo todas las declaraciones y variables DO. Al escribir código para los indicadores o asesores expertos usando JJMASeries, no se recomienda nombrar las variables con nombre que comiencen por nJMA o dJMA. . La función JJMASeries() puede utilizarse en el código interno de otras funciones personalizadas siempre que se tenga en cuenta que cada llamada a JJMASeries() debe tener su número único en cada llamada para dicha función personalizada. Esta versión de JJMASeries() tiene por finalidad procesar variables relativas a matrices de series de tiempo del gráfico actual. Si se utiliza esta función para procesar variables en matrices de series de tiempo de otros gráficos, los cálculos serán incorrectos.

Entradas:
- number - el número de la llamada a la función JJMASeries() en el código del indicador (0, 1, 2, 3, ...);
- din - parámetro que permite modificar los parámetros Longitud y Fase en cada barra. 0 - los parámetros no pueden cambiarse, cualquier otro valor permite cambiar los parámetros;
- MaxBar - valor máximo del número de barra calculado. Normalmente, es en Bars-1-period donde "período" es la cantidad de barras en que el valor de las series iniciales no se calcula;
- limit - cantidad de barras no calculadas más una o el número de la última barra no calculada. Debe ser igual a Bars-IndicatorCounted()-1;
- Length - profundidad de promediación;
- Phase - parámetro que cambia en el rango comprendido entre -100 y +100. Afecta a la calidad del proceso transitorio;
- series - entrada subyacente al cálculo de JJMASeries();
- bar - el número de la barra a calcular. Este parámetro debe ser cambiado por la declaración DO desde el valor máximo a cero. Su valor máximo siempre debe ser igual al valor de 'limit'.


Parámetros de salida:
- JMASeries() - valor de JMA. Si el valor del parámetro 'bar' supera MaxBar-30, la función JJMASeries() siempre devuelve cero.
- reset - parámetro que devuelve por referencia un valor distinto a 0 si se produce un error en el cálculo de la función y devuelve 0 si el cálculo fue correcto. Este parámetro solo puede ser variable, pero no un valor.


Inicialización de la función
Antes de llamar a la función JJMASeries(), cuando la cantidad de barras ya calculadas es igual a 0, las variables del búfer interno de la función deben redimensionarse (sería incluso mejor hacerlo en el bloque de inicialización del indicador personalizado o del asesor experto). Para ello, es necesario llamar a las variables de JJMASeries() usando la función de ayuda JJMASeriesResize() con los parámetros siguientes: JJMASeriesResize(número+1); es necesaria para hacer que el parámetro 'number' (MaxJMA.number) sea igual a la cantidad de llamadas para JJMASeries, es decir, superior en 1 al valor máximo de 'number'. Junto con el redimensionamiento de los búferes de JJMASeries(), es posible comprobar en el bloque de inicialización los valores de entrada del indicador Length y Phase que son entradas de JJMASeries(), para ver si quedan dentro de su rango de cambio usando JJMASeriesAlert():

JJMASeriesAlert(int Number, string name, int ExternVar)

- Number - parámetro que puede tomar dos valores: 0 - para comprobar la entrada ExternVar para ver si cae dentro del rango de cambio de la entrada Length de JJMASeries() y 1 - para comprobar la entrada ExternVar para ver si cae dentro del rango de cambio de la entrada Phase de JJMASeries();
- name - nombre de la entrada ExternVar para proporcionar una alerta;

- ExternVar - entrada del indicador

Indicación del error

Cuando se depuran, los códigos de los indicadores o asesores expertos pueden contener errores. Para encontrar las causas de los errores es necesario ver el archivo de registro. La función JJMASeries() registra todos los errores en un archivo de registro en la carpeta llamada \MetaTrader\EXPERTS\LOGS\. Si se produce un error de MQL4 en el código que precede a la función JJMASeries() antes de llamar a esta función, la función registrará el código de error y el contenido de este en un archivo de registro. Si se produce un error de MQL4 en el algoritmo de JJMASeries() durante la ejecución de esta función, la función registrará también el código de error y el contenido de este en un archivo de registro. Si la llamada a la función JJMASeries() 'number' se especificó de forma incorrecta o definiendo incorrectamente el tamaño de las variables del búfer nJJMAResize.Size, los mensajes sobre los parámetros incorrectos serán grabados en el archivo de registro. La información sobre las definiciones incorrectas del parámetro 'limit' se grabarán también en el archivo de registro.

Si hay un fallo en el redimensionamiento de los búferes de JJMASeries durante la ejecución de la función init(), la función JJMASeriesResize() registrará información sobre el redimensionamiento fallido en el archivo de registro. Si se incumple la secuencia correcta de cambio del parámetro 'bar' al llamar a la función JJMASeries() a través de una declaración DO externa, esta información quedará grabada también en el archivo de registro. Debe tenerse en cuenta que algunos errores en el código producirán más errores en su ejecución, por ello, si la función JJMASeries() registra varios errores en el archivo de registro al mismo tiempo, estos errores deberán ser eliminados por orden de aparición. En un indicador escrito correctamente, la función JJMASeries() puede realizar registros en el archivo de registro utilizando solo desajustes del sistema. Una excepción es el registro del redimensionamiento de las variables del búfer en el reinicio del indicador o asesor experto que ocurre en cada llamada a la función init(). Todos los errores MQL4 se graban en el archivo de registro usando la función JMA_ErrDescr() limpia el código y el contenido del error de acuerdo a su código obtenido usando la función GetLastError() en el archivo de registro.

Llamada a la función JJMASeries() de ejemplo (doble ajuste JMA del precio de entrada):

/*
For the indicator to operate, files 
JJMASeries.mqh 
PriceSeries.mqh 
must be placed into the directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
into the directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        J2JMA.mq4 | 
//|                       JMA code: Copyright © 2005, Jurik Research | 
//|                                          http://www.jurikres.com/ | 
//|    MQL4 JJMASeries+J2JMA: Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+   
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Magenta 
//---- INDICATOR INPUTS 
extern int Length1 = 5; // depth of the first smoothing 
extern int Length2 = 5; // depth of the second smoothing 
// the first smoothing parameter changing within the range between -100 and +100, 
//it influences the transient quality; 
extern int Phase1  = 100;
// the second smoothing parameter changing in the range between -100 and +100, 
//it influences the transient quality; 
extern int Phase2  = 100;
// indicator shifting along the time axis 
extern int Shift   = 0;
/* Choosing of prices to be used for indicator calculations 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double J2JMA[];
//---- floating points variables  
double Temp_Series; 
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>   
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| J2JMA indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
  {  
//---- defining of the chart drawing style
   SetIndexStyle (0, DRAW_LINE); 
//---- 1 indicator buffer is used for calculations
   SetIndexBuffer(0, J2JMA);
//---- horizontal shift of the indicator line 
   SetIndexShift (0, Shift);  
//---- placing of indicator values that will not be visible in the chart
   SetIndexEmptyValue(0, 0); 
//---- name for data windows and label for subwindows 
   IndicatorShortName ("J2JMA(Length1=" + Length1 + ", Phase1=" + Phase1 +
                       ", Length2=" + Length2 + ", Phase2=" + Phase2 + 
                       ", Shift=" + Shift + ")"); 
   SetIndexLabel (0, "J2JMA"); 
//---- Setting the indicator imaging precision format
   IndicatorDigits(Digits);
//----+ Resizing of buffer variables of function JJMASeries, 
//nJMAnumber=2(two calls for function JJMASeries)
   if(JJMASeriesResize(2) != 2)
       return(-1);
//---- setting alerts for nonaccepted values of external variables
   JJMASeriesAlert (0,"Length1", Length1);
   JJMASeriesAlert (0,"Length2", Length2);
   JJMASeriesAlert (1,"Phase1", Phase1 );
   JJMASeriesAlert (1,"Phase2", Phase2 );
   PriceSeriesAlert(Input_Price_Customs);
//---- complete initialization
   return(0); 
  } 
//+------------------------------------------------------------------+   
//| J2JMA iteration function                                         | 
//+------------------------------------------------------------------+ 
int start() 
  { 
//---- Bar quantity control over sufficiency for further calculations
   if(Bars - 1 < 61)
       return(0);
//----+ Introducing of integer variables and obtaining of bars already computed
   int reset, MaxBar1, MaxBar2, counted_bars = IndicatorCounted();
//---- checking for possible errors
   if(counted_bars < 0) 
       return(-1);
//---- the last counted bar should be recalculated 
//---- (without this recalculation for counted_bars, function JJMASeries will not 
//     operate correctly!!!)
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
   int limit = Bars - counted_bars - 1; 
   MaxBar1 = Bars - 1; 
   MaxBar2 = MaxBar1 - 30;
 
//----+ INDICATOR COMPUTING BASIC LOOP 
   for(int bar = limit; bar >= 0; bar--)
     {
       // Call for function PriceSeries to get the entry price Series
       Temp_Series = PriceSeries(Input_Price_Customs, bar);
       // Two calls fro function JJMASeries numbered as 0,1. Parameters 
       //nJMA.Phase and nJMA.Length 
       //do not change at each bar (nJMA.din=0)
       //(In the second call, parameter nJMA.MaxBar is decreased by 30 since it is 
       //the repeated JMA smoothing)
       Temp_Series = JJMASeries(0,0,MaxBar1,limit,Phase1,Length1,
                                Temp_Series,bar,reset);
       // checking for errors in the preceding operation
       if(reset != 0)
           return(-1);
       Temp_Series = JJMASeries(1,0,MaxBar2,limit,Phase2,Length2,
                                Temp_Series,bar,reset);
       // checking for errors in the preceding operation
       if(reset != 0)
           return(-1);
       J2JMA[bar] = Temp_Series;
     }
//---- complete calculation of indicator values
   return(0); 
  } 
//+--------------------------------------------------------+


De este modo, pueden destacarse los siguientes puntos en la aplicación de esta función:
1. Declaración de funciones que son parte del archivo JJMASeries.mqh con la línea #include al comienzo del código del indicador. Se declaran las variables y cuatro funciones: JJMASeries(), JJMASeriesResize(), JJMASeriesAlert(), JMA_ErrDescr().
2. Redimensionamiento de los elementos del búfer por la función JJMASeries() usando la función JJMASeriesResize() en el bloque de inicialización.
3. Comprobar usando la función JJMASeriesAlert() en el bloque de inicialización si los valores de las variables externas del indicador que son variables externas de la función JJMASeries() son correctos.
4. Llamadas a la propia función JJMASeries() realizadas mediante el uso de declaraciones DO con control de error relevante. 


Otras funciones

El algoritmo para la llamada a otras funciones es muy similar al algoritmo anterior, pero hay algunas diferencias en la cantidad de variables externas disponibles en las funciones:

JJMASeries (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JLiteSeries(int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JurXSeries (int number, int din, int MaxBar, int limit,
            int Length, double series, int bar, int&reset)
T3Series   (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset )
ParMASeries(int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset)
LRMASeries (int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset )

Debe observarse que las funciones JJMASeries() y JLiteSeries() no son compatibles en el mismo asesor experto o indicador. De hecho, el propio código JMA con el nombre de la función de JJMASeries() se coloca en el archivo JLiteSeries.mqh sin ninguna adaptación. Para sustituir la función JJMASeries() por la función JLiteSeries() en un asesor experto o indicador, es suficiente con sustituir la línea #include por #include. Todas las llamadas a las funciones del archivo JLiteSeries.mqh se consideran llamadas a las funciones idénticas a aquellas usadas para las funciones del archivo JJMASeries.mqh.

Otras funciones son totalmente compatibles dentro del mismo código del indicador o asesor experto. En las funciones ParMASeries() y LRMASeries(), el valor de la variable externa 'period' está limitado a 501. Si son necesarios valores mayores, es necesario cambiar los primeros (no cero) de los búferes dParMA.TempBuffer[][501] y dParMA.TEMPBUFFER[][501] para la función ParMASeries() o dLRMA.TempBuffer[][501] y dLRMA.TEMPBUFFER[][501] para la función LRMASeries() en los archivos ParMASeries.mqh y LRMASeries.mqh, respectivamente. >


Función JurXSeries()
A continuación se muestra una llamada a la función JurXSeries() de ejemplo (ajuste ultralineal del precio de entrada con ajuste adicional JMA):


/*
For the indicator to operate, it is necessary to place files 

JurXSeries.mqh, 
JJMASeries.mqh, 
PriceSeries.mqh,  
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
This indicator is based on the smoothing algorithm of indicator JRSX.
The final result of this indicator bear some resemblance to 
double JMA smoothing, but is less perfect since it is simpler.
 
*/
//+------------------------------------------------------------------+
//|                                                        JJurX.mq4 | 
//|                           Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Gold
//---- INDICATOR INPUTS 
extern int JurX_Length  = 5; // depth of JurX smoothing 
extern int JJMA_Length  = 4; // depth of JJMA smoothing 
// parameter of JJMA smoothing ranging between -100 and +100 
// influences the transient quality; 
extern int JJMA_Phase   = -100;
extern int Shift        = 0;      // indicator shift along the time axis 
/* Choosing of prices underlying the indicator calculations 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer[];
//---- floating point variables  
double Price,JurX,JJurX,Error;
//+------------------------------------------------------------------+
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>
//+------------------------------------------------------------------+
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+
//| JJurX indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
{  
//---- defining of the charting style
SetIndexStyle (0,DRAW_LINE); 
//---- 1 indicator buffer is used to calculate
SetIndexBuffer(0,Ind_Buffer);
//---- horizontal shift of the indicator line 
SetIndexShift (0, Shift); 
//---- setting indicator values that will not be visible in the chart
SetIndexEmptyValue(0,0); 
//---- name for data windows and label for subwindows 
IndicatorShortName ("JJurX( JurX_Length="+JurX_Length+", Shift="+Shift+")"); 
SetIndexLabel (0, "JJurX"); 
//---- Setting the indicator imaging precision format
IndicatorDigits(Digits);
//----+ Resizing buffer variables of function JurXSeries, 
//      nJurXnumber=2
//(To calls for function JurXSeries)
if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries,
//      nJMAnumber=1
//(One call for function JJMASeries)
if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables
JurXSeriesAlert(0,"JurX_Length",JurX_Length); 
JJMASeriesAlert(0,"JJMA_Length",JJMA_Length); 
JJMASeriesAlert(1,"JJMA_Phase",JJMA_Phase); 
PriceSeriesAlert(Input_Price_Customs);
//---- complete initialization
return(0); 
} 
//+-----------------------------------------------------------------------------+
//| JJurX iteration function                                                    | 
//+-----------------------------------------------------------------------------+
int start() 
{ 
//---- Bar quantity control over sufficiency for further calculations
if (Bars-1<JurX_Length+32)return(0);
//----+ Introducing of integer variables and obtaining of bars already computed
int reset,MaxBar,counted_bars=IndicatorCounted();
//---- checking for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar should be recalculated 
//(without this recalculation for counted_bars, function JurXSeries will not 
// operate correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
int limit=Bars-counted_bars-1; 
determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1; 
 
//----+ INDICATOR COMPUTING BASIC LOOP
for(int bar=limit;bar>=0;bar--)
 {
  //----+ Call for function PriceSeries to get the entry
  //      price Series
  Price=PriceSeries(Input_Price_Customs,bar);
  //----+ One call for function JurXSeries numbered as 0. 
  //Parameter nJJurX.Length does not change on each bar (nJurXdin=0)
  JurX=JurXSeries(0,0,MaxBar,limit,JurX_Length,Price,bar,reset); 
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1); 
  //----+ detection of error in calculations of parameter JurX
  //----+ the second call for function JurXSeries numbered as 1. 
  //Parameter nJJurX.Length does not change on each bar (nJurXdin=0)
  Error=JurXSeries(1,0,MaxBar,limit,JurX_Length,100,bar,reset); 
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1);
  if(Error==0)Error=100;
  JurX*=100/Error;
  //----+ Call for function JJMASeries numbered as 0. 
  //      Parameters nJMA.Phase and nJMA.Length do not change on each bar 
  //      (nJMA.din=0)
  JJurX=JJMASeries(0,0,MaxBar,limit,JJMA_Phase,JJMA_Length,JurX,bar,reset);
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1);
  Ind_Buffer[bar]=JJurX;                 
 }
//---- complete calculation of indicator values
return(0); 
} 
//+-------------------------------------------------------------------------+

En este ejemplo, debe recordarse que la función JurXSeries() promedia el precio de entrada y la constante. Al haber dividido el resultado promedio por el valor de la constante, obtendremos el error de ajuste. Para obtener resultados más precisos del ajuste de las series de precios, es necesario dividir el resultado del ajuste por el valor de este error. En nuestro caso esto ya lo hemos hecho. En los dos casos siguientes, el numerador y el denominador se ajustan de forma independiente, por lo que no es necesario el procedimiento anterior. Dicho error no se produce para las demás funciones de ajuste.

A continuación se muestra un ejemplo de llamada a las funciones JJMASeries() y JurXSeries() (CCI análogo con ajuste JMA adicional):

/*
For the indicator to operate, it is necessary to place files 
JJMASeries.mqh
JurSeries.mqh 
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        JCCIX.mq4 |
//|                               Copyright © 2006, Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+    
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in a separate window
#property indicator_separate_window
//---- amount of indicator buffers
#property indicator_buffers  1
//---- colors of indicator
#property indicator_color1  BlueViolet
//---- parameters of the indicator horizontal levels
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- INDICATOR INPUTS 
extern int  JJMA.Length = 8;  // depth of JJMA smoothing of entry price
// depth of JurX smoothing of the obtained indicator 
extern int  JurX.Length = 8;
// parameter ranging between -100 and +100 influences 
// the smoothing transient quality
extern int  JJMA.Phase = 100;
 /* Choosing of prices underlying the indicator calculations  
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer1[];
//---- integer constans 
int    w;
//+------------------------------------------------------------------+
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh>
//+------------------------------------------------------------------+  
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| JCCIX initialization function                                    |
//+------------------------------------------------------------------+
int init()
 {
//---- indicator drawing styles
   SetIndexStyle(0,DRAW_LINE);
//---- 1 indicator buffer is used for calculations. 
   SetIndexBuffer(0,Ind_Buffer1);
//---- setting of the indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0); 
//---- names for data windows and labels for subwindows
   SetIndexLabel(0,"JCCIX");
   IndicatorShortName("JCCIX(JJMA.Length="+JJMA.Length+", JurX.Length"+
                      JurX.Length+")");
//---- Setting imaging precision format (count of characters after decimal point) 
//to visualize the indicator values  
   IndicatorDigits(2);
//----+ Resizing buffer variables of function JurXSeries, 
//      nJurXnumber=2
//(Two calls for function JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries, 
//      nJMAnumber=1
//(One call for function JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables
   JurXSeriesAlert (0,"JurX.Length",JurX.Length);
   JJMASeriesAlert (0,"JJMA.Length",JJMA.Length);
   JJMASeriesAlert (1,"JJMA.Phase",JJMA.Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- setting the bar number, starting from which the indicator will be 
//     drawn  
   SetIndexDrawBegin(0,JurX.Length+31);
//---- coefficients initialization to compute the indicator 
   if (JurX.Length>5) w=JurX.Length-1; else w=5;
//---- initialization complete
   return(0);
  }
//+------------------------------------------------------------------------+
//|  JCommodity Channel IndexX                                             |
//+------------------------------------------------------------------------+
int start()
  {
//---- Introducing of floating point variables    
double price,Jprice,JCCIX,UPCCI,DNCCI,JUPCCIX,JDNCCIX; 
//----+ Introducing of integer variables and getting bars already computed
int reset,MaxBar,MaxBarJ,limit,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
//---- (without this recalculation for counted_bars, functions JJMASeries 
//and JurXSeries will not work correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
limit=Bars-counted_bars-1; 
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1; MaxBarJ=MaxBar-30;
//---- correction of the start calculated bar in the loop
if(limit>=MaxBar)limit=MaxBar;
 
for(int bar=limit; bar>=0; bar--)
 { 
   //----+ Call for function PriceSeries to get entry 
   //      price Series
   price=PriceSeries(Input_Price_Customs, bar);
   //+----------------------------------------------------------------
   //----+ One call for function JJMASeries numbered as 0 
   //----+ Parameters nJMA.Phase and nJMA.Length do not change within  
   //      each bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   Jprice=JJMASeries(0,0,MaxBar,limit,JJMA.Phase,JJMA.Length,price,
                     bar,reset);
   //----+ check for errors in the preceding operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+    
   UPCCI=price-Jprice;         
   DNCCI=MathAbs(UPCCI);
   //----+ Two calls for function JurXSeries numbered as 0 and 1. 
           Parameter nJJurXLength does not 
   //change within each bar (nJurXdin=0)
   //----+ check for errors in the preceding operation
   JUPCCIX=JurXSeries(0,0,MaxBarJ,limit,JurX.Length,UPCCI,bar,reset); 
   if(reset!=0)return(-1); 
   JDNCCIX=JurXSeries(1,0,MaxBarJ,limit,JurX.Length,DNCCI,bar,reset); 
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBarJ-w)JCCIX=0;
   else 
     if (JDNCCIX!=0)
       {
        JCCIX=JUPCCIX/JDNCCIX;
        if(JCCIX>1)JCCIX=1;
        if(JCCIX<-1)JCCIX=-1;
       }
     else JCCIX=0;
   Ind_Buffer1[bar]=JCCIX; 
   //----+
 }
//----
   return(0);
  }
//+-------------------------------------------------------------------+


Debe tenerse en cuenta el hecho siguiente: Después de dos ajuste en la función JurXSeries(), uno de los valores obtenidos será comprobado por si no es igual a cero, ya que es un denominador.

A continuación se muestra un ejemplo de llamada a las funciones JJMASeries() y JurXSeries() (RSI análogo con ajuste JMA adicional):

/*
For the indicator to operate, it is necessary to place files  
JurXSeries.mqh
JJMASeries.mqh  
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                        JJRSX.mq4 |
//|    MQL4 JJRSX: Copyright © 2006,                Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in a separate window
#property indicator_separate_window
//---- amount of indicator buffers
#property indicator_buffers  1
//---- colors of the indicator
#property indicator_color1  BlueViolet
//---- parameters of the indicator horizontal levels
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- INDICATOR INPUTS 
extern int  Length = 8;  // depth of JurX smoothing of the indicator
// depth of JJMA smoothing of the obtained indicator
extern int  Smooth = 3;
// parameter ranging between -100 and +100, influences 
//the smoothing transient quality
extern int  Phase = 100;
/* Choosing of prices, at which the indicator is computed 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer[];
//---- integer variables 
int    w;  
//+------------------------------------------------------------------+  
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+---------------------------------------------------------------------+ 
//| JJRSX initialization function                                       |
//+---------------------------------------------------------------------+ 
int init()
  {
//---- indicator drawing styles
   SetIndexStyle(0,DRAW_LINE);
//---- 1 indicator buffer is used for counting. 
   SetIndexBuffer(0,Ind_Buffer);
//---- setting the indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0); 
//---- names for data windows and labels for subwindows
   SetIndexLabel(0,"JRSX");
   IndicatorShortName("JRSX(Length="+Length+", Input_Price_Customs="+
                      Input_Price_Customs+")");
//---- Setting imaging precision format (count of characters after decimal point) 
//to visualize the indicator values
   IndicatorDigits(2);
//----+ Resizing buffer variables of function JurXSeries,
        nJurXnumber=2
//(Two calls for function JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries,
        nJMAnumber=1
//(One call for function JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables
   JurXSeriesAlert (0,"Length",Length);
   JJMASeriesAlert (0,"Smooth",Smooth);
   JJMASeriesAlert (1,"Phase",Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- setting the bar number, starting from which there will be drawn the
       indicator  
   SetIndexDrawBegin(0,Length+31);
//---- correction of nonaccepted value ща parameter Length
   if(Length<1)Length=1; 
//---- coefficients initialization to compute the indicator 
   if (Length>5) w=Length-1; else w=5;
//---- initialization complete
return(0);
  }
//+-----------------------------------------------------------------------------+ 
//| JJRSX iteration function                                                    |
//+-----------------------------------------------------------------------------+ 
int start()
{
//---- Introducing floating point variables 
double dPrice,dPriceA,UPJRSX,DNJRSX,JRSX,JJRSX; 
//----+ Introducing of integer variables and obtaining of bars already computed
int bar,limit,reset,MaxBar,MaxBarJ,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-2; MaxBarJ=MaxBarJ-w-1; 
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
limit=Bars-counted_bars-1; 
//----+ 
if (limit>MaxBar){limit=MaxBar;Ind_Buffer[MaxBar]=0.0;}
 
for(bar=limit;bar>=0;bar--)
  {
   //----+ two calls for function PriceSeries to get the difference
   //      between entry prices dPrice
   dPrice = PriceSeries(Input_Price_Customs, bar)-
                        PriceSeries(Input_Price_Customs, bar+1);
   //----+  
   dPriceA=MathAbs(dPrice);
   //----+ Two calls for function JurXSeries numbered as 0 and 1. 
   //      Parameter nJJurXLength 
   //does not change on each bar (nJurXdin=0) 
   //check for errors in the preceding operation
   UPJRSX=JurXSeries(0,0,MaxBar,limit,Length,dPrice, bar,reset); 
   if(reset!=0)return(-1);
   DNJRSX=JurXSeries(1,0,MaxBar,limit,Length,dPriceA,bar,reset);
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBar-w)JRSX=0;
   else if (DNJRSX!=0){JRSX=UPJRSX/DNJRSX;
   if(JRSX>1)JRSX=1;
   if(JRSX<-1)JRSX=-1;}else JRSX=0;
   //+---------------------------------------------------------------+ 
   //----+ One call for function JJMASeries numbered as 0 
   //----+ Parameters nJMA.Phase and nJMA.Length do not change 
   //      on each bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   JJRSX=JJMASeries(0,0,MaxBarJ,limit,Phase,Smooth,JRSX,bar,reset);
   //----+ check for errors in the preceding operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+  
   Ind_Buffer[bar]=JJRSX;  
}
//---- complete calculation of the indicator values
return(0);
}
//+------------------------------------------------------------------+



Funciones T3Series()
A continuación se muestra una llamada a la función T3Series() de ejemplo (tres bandas de Bollinger con ajuste T3 adicional):

/*
To work with the indicator, files 
T3Series.mqh 
PriceSeries.mqh 
must be placed in directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
in directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                          T3.6Bollinger Bands.mq4 | 
//|                        Copyright © 2006,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 7
//---- indicator color
#property indicator_color1 Gray 
#property indicator_color2 Red
#property indicator_color3 Blue 
#property indicator_color4 Lime
#property indicator_color5 Blue
#property indicator_color6 Red
#property indicator_color7 Gray 
//---- indicator line style
#property indicator_style1 4
#property indicator_style2 2
#property indicator_style3 4
#property indicator_style4 4
#property indicator_style5 4
#property indicator_style6 2
#property indicator_style7 4
//---- INDICATOR INPUTS 
// averaging period of J2Bollinger Bands
extern int        Bands_Period = 100;
extern double Bands_Deviations = 2.0; // deviation 
extern int         MA_method = 0;   // averaging method
// smoothing depth of the obtained Moving Avereges
extern int         MA_Smooth = 20;
// smoothing depth of the obtained Bollinger Bands
extern int        Bands_Smooth = 20;
// smoothing parameter ranging between -100 and +100, 
// influences the transient quality; 
extern int    Smooth_Curvature = 100;
// indicator shift along the time axis 
extern int         Bands_Shift = 0;
//Choosing of prices, on which the indicator is calculated 
/*(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.)*/
extern int Input_Price_Customs = 0;
//---- indicator buffers
double UpperBuffer3  [];
double UpperBuffer2  [];
double UpperBuffer1  [];
double T3MovingBuffer[];
double LowerBuffer1  [];
double LowerBuffer2  [];
double LowerBuffer3  [];
double Series_buffer [];
//+------------------------------------------------------------------+ 
//----+ Introducing of function T3Series 
//----+ Introducing of function T3SeriesResize 
//----+ Introducing of function T3SeriesAlert 
//----+ Introducing of function T3_ErrDescr  
#include <T3Series.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+  
//| T3.6Bollinger Bands initialization function        | 
//+------------------------------------------------------------------+  
int init()
  {
//---- defining the chart drawing style
   SetIndexStyle(0,DRAW_LINE); 
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE); 
   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(5,DRAW_LINE); 
   SetIndexStyle(6,DRAW_LINE);
//---- 4 indicator buffers are used for calculations  
   IndicatorBuffers(8);
   SetIndexBuffer(0,UpperBuffer3 );
   SetIndexBuffer(1,UpperBuffer2 );
   SetIndexBuffer(2,UpperBuffer1 );
   SetIndexBuffer(3,T3MovingBuffer);
   SetIndexBuffer(4,LowerBuffer1 );
   SetIndexBuffer(5,LowerBuffer2 );
   SetIndexBuffer(6,LowerBuffer3 );
   SetIndexBuffer(7,Series_buffer);
//---- setting up indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(1,0);
   SetIndexEmptyValue(2,0);
   SetIndexEmptyValue(3,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   SetIndexEmptyValue(6,0);
//---- setting up the bar number, starting from which the indicator
//     will be drawn  
   int drawbegin=100+Bands_Shift;
   SetIndexDrawBegin(0,drawbegin);
   SetIndexDrawBegin(1,drawbegin);
   SetIndexDrawBegin(2,drawbegin);
   SetIndexDrawBegin(3,drawbegin);
   SetIndexDrawBegin(4,drawbegin);
   SetIndexDrawBegin(5,drawbegin);
   SetIndexDrawBegin(6,drawbegin);
//---- horizontal shift of the indicator lines  
   SetIndexShift (0, Bands_Shift); 
   SetIndexShift (1, Bands_Shift); 
   SetIndexShift (2, Bands_Shift); 
   SetIndexShift (3, Bands_Shift); 
   SetIndexShift (4, Bands_Shift); 
   SetIndexShift (5, Bands_Shift); 
   SetIndexShift (6, Bands_Shift); 
//---- name for data windows and labels for subwindows
   IndicatorShortName ("T3.4Bollinger Bands( Period="+Bands_Period+
        ", Deviations="+Bands_Deviations+")"); 
   SetIndexLabel (0, "Upper3 Bands");
   SetIndexLabel (1, "Upper2 Bands");
   SetIndexLabel (2, "Upper1 Bands"); 
   SetIndexLabel (4, "Lower1 Bands"); 
   SetIndexLabel (5, "Lower2 Bands"); 
   SetIndexLabel (6, "Lower3 Bands"); 
   string Moving;
   switch(MA_method)
       {
        case  0: Moving= "T3SMA";break;
        case  1: Moving= "T3EMA";break;
        case  2: Moving="T3SSMA";break;
        case  3: Moving="T3LWMA";break;
        default: Moving="T3SMA";
       }
   SetIndexLabel (3, "Moving Avereges "+Moving+" ("+Bands_Period+")");
//---- Setting imaging precision format for the indicator
   IndicatorDigits(Digits);
//----+ Resizing of buffer variables of function T3Series, 
//nT3.number=7(Seven calls for function T3Series)
   if (Bands_Smooth<=1){if (T3SeriesResize(1)!=1)return(-1);}
   else if (T3SeriesResize(7)!=7)return(-1);
//---- setting alerts for nonaccepted values of external variables
   T3SeriesAlert(0,"MA_Smooth",MA_Smooth);
   T3SeriesAlert(0,"Bands_Period",Bands_Period);
   PriceSeriesAlert(Input_Price_Customs);
   if((MA_method<0)||(MA_method>3))
        Alert("Parameter MA_method must range between 0 and 3" 
        + " You input a nonaccepted " 
       +MA_method+ "0 will be used");
//---- correction of the nonaccepted value of parameter Bands_Period
   if(Bands_Period<1)Bands_Period=1; 
//---- initialization complete
   return(0);
  }
//+------------------------------------------------------------------------+  
//| T3.6Bollinger Bands iteration function                                 | 
//+------------------------------------------------------------------------+  
int start()
  {
//---- check for whether the amount of bars is sufficient for calculations
if(Bars-1<=Bands_Period) return(0);
//---- Introducing of floating point variables  
double deviation1,deviation2,deviation3,Temp_Series,sum,midline,
       priceswing,Resalt;
//----+ Introducing of integer variables and getting the bars already calculated
int reset,MaxBar,MaxBarBB,MaxBarBB1,bar,kk,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
// (without this recalculation for counted_bars, function T3Series will not work
// correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
int limit=Bars-counted_bars-1;
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1-Bands_Period; MaxBarBB=MaxBar-30-Bands_Period; 
MaxBarBB1=MaxBarBB-1;
//----+ loading of entry prices into the buffer for calculations       
for(bar=limit;bar>=0;bar--)
    Series_buffer[bar]=PriceSeries(Input_Price_Customs,bar);
//---- checking whether the bars are sufficient for calculation of Bollinger Bands 
//---- zero initialization        
if (limit>MaxBar)
     {
      for(bar=limit;bar>=MaxBar;bar--)T3MovingBuffer[bar]=0;
      limit=MaxBar;
     }
//----+ Moving Averages calculation loop
for(bar=limit;bar>=0;bar--)
     {
      //----+ Moving Averages calculation formula
      Temp_Series=iMAOnArray(Series_buffer,0,Bands_Period,0,
                             MA_method, bar);
      //----+ smoothing of the obtained Moving Averages
      //----+ call for function T3Series numbered as 0. 
      // Parameters nT3.Curvature and nT3.Length do not change on 
      // each bar (nT3.din=0)
      Resalt=T3Series(0,0,MaxBar,limit,Smooth_Curvature,MA_Smooth,
                      Temp_Series,bar,reset);
      //----+ check for error in the preceding operation
      if(reset!=0)return(-1); 
      T3MovingBuffer[bar]=Resalt; 
     }     
//---- CALCULATION of Bollinger Bands 
//---- zero initialization      
if (limit>MaxBarBB)
     {
      for(bar=limit;bar>=MaxBarBB;bar--)
       {
        UpperBuffer2[bar]=0;
        UpperBuffer1[bar]=0;
        LowerBuffer1[bar]=0;
        LowerBuffer2[bar]=0;
       }
      limit=MaxBarBB;
     }
for(bar=limit;bar>=0;bar--)
   {       
     sum=0.0;
     midline=T3MovingBuffer[bar];
     kk=bar+Bands_Period-1;
     while(kk>=bar)
      {
       priceswing=PriceSeries(Input_Price_Customs,kk)-midline;
       sum+=priceswing*priceswing;
       kk--;
      }
     deviation2=Bands_Deviations*MathSqrt(sum/Bands_Period);     
     deviation1=0.5*deviation2;
     deviation3=1.5*deviation2;
     if (Bands_Smooth>1)
      {
       //----+ calculation and T3 smoothing of Bollinger Bands      
       //----+ ------------------------------------------------------+        
       //----+ six parallel calls for function T3Series numbered 
       //      as 1, 2, 3, 4, 5, 6. 
       //----+ Parameters nT3.Length do not change on each bar 
       //      (nT3.din=0)
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(1,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation3,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer3[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(2,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation2,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+       
       Resalt=T3Series(3,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation1,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(4,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation1,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(5,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation2,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(6,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation3,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer3[bar]=Resalt;        
       //----+ ------------------------------------------------------+ 
      }
     else 
      {
       //----+ calculation of Bollinger Bands without T3 smoothing 
       UpperBuffer3[bar]=midline+deviation3; 
       UpperBuffer2[bar]=midline+deviation2;
       UpperBuffer1[bar]=midline+deviation1;
       LowerBuffer1[bar]=midline-deviation1;
       LowerBuffer2[bar]=midline-deviation2;
       LowerBuffer3[bar]=midline-deviation3;
      }
      
   }
//---- complete indicator calculations
   return(0);
  }
//+-------------------------------------------------------------------+



Funciones ParMASeries()
A continuación se muestra una llamada a la función ParMASeries() de ejemplo (ParMA moviéndose con ajuste JMA adicional):

/*
Moving average ParMA calculated on parabolic 
regression with bands 
 
for the indicator to work, one should place files 
JJMASeries.mqh 
ParMASeries.mqh 
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                       JParMA.mq4 |
//|                       ParMA MQL4 CODE: Copyright © 2006, alexjou |
//|             JParMA Indicator: Copyright © 2006, Nikolay Kositsin |
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window
//---- amount of indicator buffers
#property indicator_buffers 1
//---- color of the indicator 
#property indicator_color1 Red
//---- INDICATOR INPUTS 
extern int MA_Period  = 8; // ParMA period
extern int Length = 3;   // smoothing depth 
// parameter ranging between -100 and +100, 
//it influences the transient quality; 
extern int Phase  = 100;
extern int Shift  = 0;   // indicator shift along the time axis 
//Choosing of prices, at which the indicator is calculated 
/*(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double IndBuffer[];
//---- float point variables 
double JResalt, Price, Resalt;
//+------------------------------------------------------------------+  
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>
//+------------------------------------------------------------------+ 
//----+ Introducing of function ParMAMASeries 
//----+ Introducing of function ParMASeriesResize 
//----+ Introducing of function ParMASeriesAlert 
//----+ Introducing of function ParMA_ErrDescr 
#include <ParMASeries.mqh>
//+------------------------------------------------------------------+  
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+   
//| JParMA initialization function                                   |
//+------------------------------------------------------------------+ 
int init()
 {
  //---- Setting imaging precision format for the indicator
  IndicatorDigits(Digits);
  //---- defining the chart drawing style
  SetIndexStyle(0, DRAW_LINE);
  //---- 1 indicator buffer is used for calculations
  SetIndexBuffer(0, IndBuffer);
  //---- horizontal shift of the indicator line 
  SetIndexShift (0, Shift); 
  //---- setting the indicator values that will not be visible in
  //     the chart
  SetIndexEmptyValue(0, 0.0); 
  //---- name for data windows and label for subwindows 
  IndicatorShortName ("JParMA( Length="+Length+", Phase="+Phase+", 
                      Shift="+Shift+")");   
  SetIndexLabel(0, "JParMA Line");
  //---- setting the bar number, starting from which there will be drawn
         indicator 
  SetIndexDrawBegin(0, MA_Period);
  //----+ Resizing buffer variables of function JJMASeries, 
  //nJMAnumber=1(One call for function JJMASeries)
  if (JJMASeriesResize(1)!=1)return(-1);
  //----+ Resizing buffer variables of function ParMASeries, 
  //nParMAnumber=1(One call for function ParMASeries)
  if (ParMASeriesResize(1)!=1)return(-1);
  //---- setting alerts for nonaccepted values of external variables
  JJMASeriesAlert (0,"Length",Length);
  JJMASeriesAlert (1,"Phase", Phase );
  ParMASeriesAlert(0,"MA_Period",MA_Period);
  PriceSeriesAlert(Input_Price_Customs);
  return(0);
 }
//+-----------------------------------------------------------------------+ 
//| JParMA iteration function                                             |
//+-----------------------------------------------------------------------+ 
int start()
 {
 //---- check whether the amount of bars is sufficient for calculations
if (Bars-1<MA_Period)return(0);
//----+ Introducing of integer variables and getting bars already counted
int reset,MaxBar,MaxBarP,bar,Limit,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
if (counted_bars>0) counted_bars--;
//---- defining the oldest bar number, starting from which all bars 
//will be recalculated
MaxBar=Bars-1; MaxBarP=MaxBar-MA_Period;

//---- defining the oldest bar number, starting from which new bars 
//will be recalculated 
Limit=Bars-counted_bars-1; 
 
//---- Indicator calculation
for (bar=Limit; bar>=0; bar--)
   { 
    //----+ 
     Price=PriceSeries(Input_Price_Customs,bar);
     //----+ getting the initial indicator
     //----+ Call for function ParMASeries numbered as 0
     Resalt=ParMASeries(0,MaxBar,Limit,MA_Period,Price,bar,reset); 
     //----+ check for errors in the preceding operation
     if(reset!=0)return(-1);
     //----+ JMA smoothing of the obtained indicator, 
     //parameter nJMA.MaxBar is decreased by MA_Period 
     //----+ Call for function JJMASeries numbered as 0, 
     // parameters nJMA.Phase and nJMA.Length do not change on each bar
     // (nJMA.din=0)
     JResalt=JJMASeries(0,0,MaxBarP,Limit,Phase,Length,Resalt,bar,reset);
     //----+ check for errors in the preceding operation
     if(reset!=0)return(-1);
     IndBuffer[bar]=JResalt;
   }
 //----
  return(0);
 }
 
//+-------------------------------------------------------------------+

En todos los indicadores, la matriz de series de tiempo normalmente utilizada Close[] es sustituida por la función PriceSeries(). Su uso no debe causar ningún problema.

double  PriceSeries(int Input_Price_Customs, int bar)

El parámetro Input_Price_Customs puede variar entre 0 y 14. Dependiendo del valor de este parámetro, la función devuelve el valor del precio para el gráfico actual por el número de barras usadas como segundo parámetro: 0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0. 5*TRENDFOLLOW, 11-Heiken Ashi High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 14-Heiken Ashi Close. Si es necesario, pueden escribirse algunas expresiones en las instancias de la función para definir los precios de entrada sobre la base de las matrices de series de tiempo. Los indicadores que usan la función PriceSeries() son de mucha ayuda en la optimización y prueba de los asesores expertos.

Conclusión

En NK_library.zip hay más de un centenar de indicadores escritos usando estos algoritmos. Estos ejemplos son más que suficientes para aprender a usar las funciones descritas en estos artículos para escribir cualquier otro indicador. Todos los indicadores del archivo zip con estas versiones de funciones de ajuste ayudan a los asesores expertos y colaboran con ellos sin fallar. Las excepciones son los indicadores con las letras HTF al final. Estos indicadores, debido a lo específico de su cálculo, no pueden utilizarse con los asesores expertos. Los indicadores de las carpetas del archivo zip deben colocarse en la carpeta del programa del terminal de cliente de MetaTrader 4: \MetaTrader\EXPERTS\indicators. Las propias funciones están en un archivo zip en la carpeta INCLUDE. Todo el contenido de esa carpeta debe colocarse en la carpeta del programa del terminal de cliente de MetaTrader 4: \MetaTrader\EXPERTS\INCLUDE.