English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Ejemplo simple de creación de un indicador usando la lógica difusa

Ejemplo simple de creación de un indicador usando la lógica difusa

MetaTrader 5Trading | 24 enero 2014, 10:37
7 388 0
Максим Востров
Максим Востров

Introducción

El uso de distintos métodos en el análisis de los mercados financieros se está haciendo cada vez más popular entre los operadores en los últimos años. Me gustaría realizar mi aportación y mostrar cómo realizar un buen indicador escribiendo un par de docenas de líneas de código. También le mostraré brevemente los fundamentos de la lógica difusa.

Cualquiera que esté interesado en este tema y quiera explorarlo en mayor profundidad puede leer los siguientes trabajos:

1.  Leonenkov А. "Fuzzy Simulation in MATLAB and fuzzyTECH" (en ruso).
2.  Bocharnikov V."Fuzzy Technology: Mathematical Background. Simulation Practice in Economics" (en ruso).
3.  S.N. Sivanandam, S. Sumathi, S.N. Deepa. Introduction to Fuzzy Logic using MATLAB.
4.  C. Kahraman. Fuzzy Engineering Economics with Applications (Studies in Fuzziness and Soft Computing).


1. Fundamentos de la lógica difusa

¿Cómo podemos explicar a nuestras máquinas informáticas los significados de las expresiones simples "..un poco más", "...demasiado rápido" o "...casi nada..."? De hecho, esto puede hacerse usando los elementos de la teoría de conjuntos difusos o las llamadas "funciones de afiliación". Este es un ejemplo del libro de A. Leonenkov:

Vamos a describir la función de afiliación para la frase "café caliente": la temperatura del café se estimará en el rango de 0 a 100 grados centígrados por la simple razón de que a temperaturas inferiores a 0 grados se convertirá en hielo, mientras que a temperaturas por encima de los 100 grados centígrados se evaporará. Es bastante obvio que de una taza de café con una temperatura de 20 grados centígrados no puede decirse que esté caliente, es decir, la función de afiliación en la categoría "caliente" es igual a 0, mientras que una taza de café con una temperatura de 70 grados centígrados pertenece definitivamente a la categoría "caliente" y, por tanto, el valor de la función se iguala a 1 en este caso.

Por lo que respecta a los valores de la temperatura que se sitúan entre estos dos valores extremos, la situación no es tan clara. Algunas personas pueden considerar que una taza de café con una temperatura de 55 grados está "caliente" mientras que otras pueden pensar que "no lo son tanto". Esto es "difusión".

No obstante, podemos imaginar el aspecto aproximado de la función de afiliación: es "monótona creciente":


La figura anterior muestra la función de afiliación "lineal por segmentos".

Por tanto, la función puede ser definida por la siguiente expresión analítica:


Usaremos tales funciones para nuestro indicador.


2. Función de afiliación

De una u otra forma, la tarea de cualquier indicador técnico es determinar el estado actual del mercado (plano, tendencia al alza, tendencia a la baja), así como la generación de señales de entrada/salida del mercado. ¿Cómo puede hacerse esto con la ayuda de las funciones de afiliación? Muy fácil.

En primer lugar necesitamos definir las condiciones límite. Supongamos que tenemos las siguientes condiciones límite: para "100% de tendencia al alza" será el cruce de EMA con un periodo 2, basado en el precio típico (H+L+C)/3 con el borde superior de Envelopes con los parámetros 8, 0.08 SMA, Close, mientras que para "100% de tendencia a la baja" será el cruce de la misma EMA con el borde inferior de Envelopes. Todo lo que está entre estas condiciones se asumirá que es plano. Vamos a añadir un envelope más con los parámetros 32, 0.15, SMA, Close. 

Como resultado obtendremos dos funciones de afiliación idénticas. La señal buy se activará cuando ambas funciones sean iguales a 1, mientras que la señal sell se activará cuando ambas funciones sean iguales a -1, respectivamente. Al ser conveniente construir gráficos con el rango de -1 a 1, el gráfico resultante se obtendrá como la media aritmética de dos funciones F(x)= (f1(x)+f2(x))/2.

Así es como aparece en el gráfico:


En este caso la función de afiliación tendrá la siguiente representación gráfica:


Analíticamente puede escribirse de la siguiente forma:

,

donde a y b son líneas envelope superiores e inferiores, respectivamente, mientras que x es un valor de EMA(2).

Con la función definida podemos ahora seguir escribiendo el código del indicador.


3. Crear el código del programa

En primer lugar, debemos definir qué y cómo vamos a dibujar.

Los resultados de los cálculos de la función de afiliación se mostrarán en pantalla como una línea roja y azul, respectivamente.

La media aritmética se mostrará en pantalla como un histograma de línea cero y en uno de los cinco colores en función del valor resultante de la función:

Para esto se usará el estilo de dibujo DRAW_COLOR_HISTOGRAM.

Vamos a dibujar los rectángulos azules y rojos como señales comprar/salir sobre las barras del histograma, los valores iguales a 1 o -1.

Es el momento de ejecutar MetaEditor y empezar. Nuevo -> Indicador personalizado -> Siguiente... Rellenamos el campo "Parámetros":


 Creamos los buffers:


Después de hacer clic en el botón "Finalizar" recibimos un código fuente y empezamos a mejorarlo.

Antes de nada vamos a definir el número de buffers. Siete de ellos ya fueron creados por el Wizard (5 para los datos y 2 para el color). Necesitamos 5 más:

#property indicator_minimum -1.4 // Setting fractional values
#property indicator_maximum 1.4  // Expert Advisors wizard ignores fractional parts for some reason
#property indicator_buffers 12   // Changing the value from 7 to 12 (5 more buffers have been added)
Vamos a editar los parámetros de entrada:
input string txt1="----------";
input int                  Period_Fast=8;
input ENUM_MA_METHOD        Method_Fast = MODE_SMA; /*Smoothing method*/ //moving average smoothing method 
input ENUM_APPLIED_PRICE    Price_Fast  = PRICE_CLOSE;
input double               Dev_Fast=0.08;
input string txt2="----------";
input int                  Period_Slow=32;
input ENUM_MA_METHOD        Method_Slow = MODE_SMA;
input ENUM_APPLIED_PRICE    Price_Slow  = PRICE_CLOSE;
input double               Dev_Slow=0.15;  /*Deviation parameter*/
input string txt3="----------";
input int                  Period_Signal=2;
input ENUM_MA_METHOD        Method_Signal = MODE_EMA;
input ENUM_APPLIED_PRICE    Price_Signal  = PRICE_TYPICAL;
input string txt4="----------";

Los comentarios que siguen a las variables declaradas son prácticos. El texto de los comentarios es insertado en la ventana de parámetros del indicador.

La posibilidad de crear listas también es muy útil:


Reservar las variables para los controladores del indicador y buffers:

int Envelopes_Fast;     // Fast envelope
int Envelopes_Slow;     // Slow envelope
int MA_Signal;          // Signal line

double Env_Fast_Up[];   // Fast envelope upper border
double Env_Fast_Dn[];   // Fast envelope lower border

double Env_Slow_Up[];   // Slow envelope upper border
double Env_Slow_Dn[];   // Slow envelope lower border

double Mov_Sign[];      // Signal line

Ahora nos vamos a la función OnInit().

Vamos a añadir algo: especificamos el nombre del indicador y eliminamos los ceros decimales adicionales:

IndicatorSetInteger(INDICATOR_DIGITS,1); // setting display accuracy, we do not need some outstanding accuracy values 
string name;                           // indicator name 
StringConcatenate(name, "FLE ( ", Period_Fast, " , ", Dev_Fast, " | ", Period_Slow, " , ", Dev_Slow, " | ", Period_Signal, " )"); 
IndicatorSetString(INDICATOR_SHORTNAME,name);

y añadimos los buffers:

SetIndexBuffer(7,Env_Fast_Up,INDICATOR_CALCULATIONS);
SetIndexBuffer(8,Env_Fast_Dn,INDICATOR_CALCULATIONS);
SetIndexBuffer(9,Env_Slow_Up,INDICATOR_CALCULATIONS);
SetIndexBuffer(10,Env_Slow_Dn,INDICATOR_CALCULATIONS);
SetIndexBuffer(11,Mov_Sign,INDICATOR_CALCULATIONS); 

El parámetro INDICATOR_CALCULATIONS significa que el dato del buffer es necesario solo para los cálculos intermedios. No se muestran en el gráfico.

Observe cómo se declaran los indicadores con buffers de color:

SetIndexBuffer(4,SignalBuffer1,INDICATOR_DATA);      // All indicator buffers at first 
SetIndexBuffer(5,SignalBuffer2,INDICATOR_DATA);      // as this is Color Histogram2, then it has 2 data buffers
SetIndexBuffer(6,SignalColors,INDICATOR_COLOR_INDEX);// the color buffer comes next.

Rellenando los controladores:

Envelopes_Fast = iEnvelopes(NULL,0,Period_Fast,0,Method_Fast,Price_Fast,Dev_Fast);
Envelopes_Slow = iEnvelopes(NULL,0,Period_Slow,0,Method_Slow,Price_Slow,Dev_Slow);
MA_Signal      = iMA(NULL,0,Period_Signal,0,Method_Signal,Price_Signal);

Todo el trabajo con la función OnInit() ha terminado.

Ahora vamos a crear la función que calculará el valor de la función de afiliación:

double Fuzzy(double x,double a, double c)
{
double F;
     if (a<x)          F=1;                 // 100% uptrend
else if (x<=a && x>=c)  F=(1-2*(a-x)/(a-c));// Flat
else if (x<c)           F=-1;               // 100% downtrend
return (F);
}

Los preparativos han terminado. Se han declarado las variables y buffers y los controladores han sido asignados.

Ahora es el momento de trabajar con la función básica OnCalculate().

En primer lugar, vamos a escribir los valores de los indicadores necesarios en los buffers intermedios. Usamos la función CopyBuffer().

CopyBuffer(Envelopes_Fast,  // Indicator handle
           UPPER_LINE,      // Indicator buffer
           0,              // The point to start 0 - from the very beginning
           rates_total,    // How many to be copied - All 
           Env_Fast_Up);   // The buffer the values are written in
// - the rest are done in a similar way
CopyBuffer(Envelopes_Fast,LOWER_LINE,0,rates_total,Env_Fast_Dn);
CopyBuffer(Envelopes_Slow,UPPER_LINE,0,rates_total,Env_Slow_Up);
CopyBuffer(Envelopes_Slow,LOWER_LINE,0,rates_total,Env_Slow_Dn);
CopyBuffer(MA_Signal,0,0,rates_total,Mov_Sign);

 Aquí debemos añadir el código para la optimización de los cálculos (solo se realiza el recálculo de la última barra):

// declaring start variable for storing the index of the bar, recalculation of the indicator buffers will be
// carried out from.

int start;              
if (prev_calculated==0// in case no bars have been calculated
    {
    start = Period_Slow; // not all indicators have been calculated up to this value, therefore, there is no point in executing the code
    }
else start=prev_calculated-1;

for (int i=start;i<rates_total;i++)
      {
      // All remaining code will be written here
      }

No queda mucho del código.

Establecer los parámetros x, a y b, realizar los cálculos del valor de la función de afiliación y escribirlo en el buffer apropiado:
double x = Mov_Sign[i]; // Signal
// Setting the first membership function parameters:
double a1 = Env_Fast_Up[i]; // Upper border
double b1 = Env_Fast_Dn[i];
// setting the first membership function value and writing it to the buffer
Rule1Buffer[i] = Fuzzy(x,a1,b1);
// Setting the second membership function parameters:
double a2 = Env_Slow_Up[i]; // Upper border
double b2 = Env_Slow_Dn[i];
// setting the second membership function value and writing it to the buffer
Rule2Buffer[i] = Fuzzy(x,a2,b2);

Se han construido dos líneas del indicador.

Ahora vamos a calcular el valor resultante.

ResultBuffer[i] = (Rule1Buffer[i]+Rule2Buffer[i])/2;

A continuación debemos dibujar las barras del histograma con los colores adecuados: como tenemos cinco colores, ResultColors[i] puede tener cualquier valor comprendido entre 0 y 4.

Generalmente, el número de colores posibles es de 64. Por tanto, es una gran oportunidad para aplicar las capacidades creativas de cada uno.

for (int ColorIndex=0;ColorIndex<=4;ColorIndex++) 
    { 
    if (MathAbs(ResultBuffer[i])>0.2*ColorIndex && MathAbs(ResultBuffer[i])<=0.2*(ColorIndex+1)) 
        { 
        ResultColors[i] = ColorIndex; 
        break; 
        } 
    }

A continuación debemos dibujar los rectángulos de la señal. Usaremos el estilo de dibujo DRAW_COLOR_HISTOGRAM2.

Tiene dos buffers de datos con una barra del histograma y un buffer de color construido entre ellos.

Los valores de los buffers de datos serán siempre los mismos: 1.1 y 1.3 para una señal buy, y -1.1 y -1.3 para una señal sell, respectivamente.

EMPTY_VALUE significará ausencia de señal..

      if (ResultBuffer[i]==1)
        {
        SignalBuffer1[i]=1.1;
        SignalBuffer2[i]=1.3;
        SignalColors[i]=1;
        }
      else if (ResultBuffer[i]==-1)
        {
        SignalBuffer1[i]=-1.1;
        SignalBuffer2[i]=-1.3;
        SignalColors[i]=0;
        }
      else
        {
        SignalBuffer1[i]=EMPTY_VALUE;
        SignalBuffer2[i]=EMPTY_VALUE;
        SignalColors[i]=EMPTY_VALUE;
        }

Hacemos clic en "Compilar" y ¡voilá!



Conclusión

¿Qué más puede añadirse? En este artículo he tratado el enfoque más básico de la lógica difusa.

Es posible hacer aquí varios experimentos. Por ejemplo, podemos usar la siguiente función:


Creo que no le será difícil escribir la expresión analítica para ella y encontrar las condiciones adecuadas.

¡Buena suerte!

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/178

Archivos adjuntos |
Cree su propia Observación del Mercado usando las clases de la librería estándar Cree su propia Observación del Mercado usando las clases de la librería estándar
El nuevo terminal de cliente de MetaTrader 5 y el lenguaje MQL5 proporcionan nuevas oportunidades al operador para la representación visual de información. En este artículo proponemos un conjunto universal y extensible de clases que controlan todo el trabajo que requiere organizar la representación en pantalla de la información sobre los gráficos. Se incluye el ejemplo del indicador Observación del Mercado.
MQL5 Wizard: crear asesores expertos sin programar MQL5 Wizard: crear asesores expertos sin programar
¿Quiere probar una estrategia de trading sin perder tiempo en programar? En el MQL5 Wizard puede seleccionar el tipo de señales de trading, añadir módulos de posiciones de arrastre y gestionar dinero, ¡y su trabajo ha terminado! Cree su propia implementación de módulos o encárguelos a través del servicio Trabajos y combine sus nuevos módulos con los que ya posee.
Construir un analizador de espectro Construir un analizador de espectro
Este artículo pretende que sus lectores se familiaricen con una posible variante del uso de los objetos gráficos en el lenguaje MQL5. Analiza un indicador que implementa un panel para la gestión de un analizador de espectro simple usando objetos gráficos. El artículo va dirigido a los lectores que están familiarizados con los conceptos básicos de MQL5.
Gas neuronal creciente: implementación en MQL5 Gas neuronal creciente: implementación en MQL5
Este artículo muestra un ejemplo de cómo desarrollar un programa MQL5 implementando el algoritmo adaptativo de agrupamiento llamado gas neuronal creciente (GNG). El artículo está dirigido a aquellos usuarios que han estudiado la documentación del lenguaje y tienen cierta capacidad para programar y un conocimiento básico en el área de la neuroinformática.