English Русский 中文 Deutsch 日本語 Português
Gestión de capital según Vince. Implementación como módulo de Wizard MQL5

Gestión de capital según Vince. Implementación como módulo de Wizard MQL5

MetaTrader 5Sistemas comerciales | 13 febrero 2018, 14:32
2 604 0
Dmitrii Troshin
Dmitrii Troshin

Introducción

Al trabajar en los mercados financieros, estamos constantemente ocupados en la búsqueda de un sistema que nos proporcione beneficios. Además, como resulta obvio, queremos que este sistema sea lo más estable posible y que también tenga un riesgo mínimo. Para lograr este objetivo, se desarrollan diferentes sistemas comerciales que hacen especial hincapié en la búsqueda de los puntos óptimos de entrada/salida. Se crean indicadores técnicos y señales comerciales que indican cuándo comprar/vender. Se ha desarrollado un sistema completo de modelos (figuras) para el análisis técnico. Además, como muestra en su trabajo "Las matemásticas de la gestión de capital" Ralph Vince, el tamaño del capital que se usa para realizar transacciones es igualmente importante. Para optimizar el beneficio, lo cual no es menos importante, el depósito guardado debe definirse con el tamaño del lote con el que comerciamos.

De paso, en el trabajo de Vince se refutan "conceptos falsos" de uso corriente. Por ejemplo, a tales conceptos pertenece la famosa regla "cuanto mayor sea el riesgo, mayor será el beneficio":

El beneficio potencial es una función lineal de riesgo potencial. ¡Eso no es cierto!

Otro "concepto falso" es que la diversificación reduce el riesgo. Pero eso tampoco es así. Según Vince:

 Esto se puede hacer, pero en menor medida de lo que piensa la mayoría de los tráders.

Disposiciones generales

Para mayor claridad, analizaremos las nuevas ideas con ejemplos. Supongamos que existe un cierto sistema condicional que consta de dos transacciones. La primera transacción gana un 50%, la segunda pierde un 40%. Si no reinvertimos el beneficio, ganaremos un 10%, y si reinvertimos, la misma secuencia de transacciones nos darán unas pérdidas del 10%. (P&L=Profit or Loss).

Número de transacción P&L sin reinversión Capital total
P&L con reinversión Capital total


100

100
1 +50 150
+50 150
2 -40 110
-60 90

Al reinvertir el beneficio, un sistema rentable se vuelve no rentable. No resulta difícil adivinar que el orden de las transacciones no tiene importancia. Con este ejemplo, podemos ver que al reinvertir el capital, no podemos actuar exactamente de la misma forma que al comerciar con un lote fijo. Por consiguiente, es la búsqueda del tamaño de lote óptimo al reinvertir lo que precisamente constituye la base del método Vince de gestión de capital.

Vamos a ir de lo sencillo hacia lo complejo: comenzaremos lanzando una moneda al aire. Imaginemos que obtenemos 2 dólares en caso de ganar, y perdemos 1 dólar en el caso contrario. La probabilidad de perder o ganar es igual a 1/2. Supongamos que tenemos 100 dólares. Entonces, si apostamos los 100 dólares a una mano, nuestro beneficio potencial será de 200 dólares. Pero si perdemos, nos quedaremmos de golpe sin nada y no podremos continuar jugando. Si continuásemos jugando una partida sin fin, - precisamente ese juego se propone para la optimización - perderemos con toda seguridad.

Si no hemos apostado toda la suma de golpe, sino una cierta parte de la misma, por ejemplo, 20 dólares de 100: entonces, en caso de perder, nos quedaría dinero para continuar jugando. Vamos a ver la secuencia de las posibles transacciones con diferente parte del capital en una sola transacción. El capital inicial es de 100 dólares en todas.

Transacción P&L con К=0.1 Capital    P&L con К=0.2 Capital     P&L con К=0.5  Capital    P&L con К=0.7 Capital     P&L con К=1 Capital  
    100         100         100         100         100
+2 20 120    40 140    100 200    140 240    200 300 
-1 -12 108    -28 112    -100  100   -168 72    -300
+2 21.6 129.6    44.8 156.8    100 200    100.8 172.8    0
-1 -12.96 116.64    -31.36 125.44    -100 100    -120.96 51.84    0
+2 23.33 139.97    50.18 175.62    100 200    72.58 124.42    0
-1 -14 125.97   -35.12 140.5   -100 100   -87.09 37.32   0 0
Total     126      141      100      37      0

Como hemos destacado antes, el beneficio y las pérdidas no dependen de la secuencia de las transacciones. Por eso, resultará algo completamente normal que alternemos transacciones rentables con otras que conllevan pérdidas. 

Es obvio que existe un coeficiente (divisor) óptimo con el que el beneficio resulta máximo. Para los casos sencillos, en los que la probabilidad de obtener ganancias y la porporción de beneficios/pérdidas son constantes, este coeficiente se halla de acuerdo con la fórmula de Kelly:

f=((B+1)*P-1)/B

f — parte fija óptima que buscaremos en lo sucesivo;

P — probabilidad de obtener ganancias;

B — proporción de beneficios/pérdidas.

A continuación, para mayor comodidad, llamaremos a f simplemente coeficiente.

Está claro que en la práctica, el tamaño y la probabilidad de las ganancias cambian, y la fórmula de Kelly no es aplicable. Por eso, para los datos empíricos, el coeficiente f se encuentra con métodos numéricos. Optimizaremos la rentabilidad del sistema según un flujo aleatorio empírico de transacciones. Para el beneficio de la transacción, Vince adopta el término HPR (holding period returns, o beneficio en el periodo de mantenimiento de la posición). Si la transacción ha traído unos beneficios del 10%, entonces el HPR =1+0.1=1.1. Por consiguiente, para una transacción HPR =1+f*Beneficio/(Ganancias máximas posibles), donde el beneficio se toma con el signo más o menos, dependiendo de si hemos obtenido beneficios o pérdidas. En realidad, el coeficiente  f es el coeficiente de la reducción máxima posible. Para encontrar el f óptimo, tenemos que encontrar el máximo del producto de todas las transacciones max(HPR1 * HPR2 * ... *HPRn).

Vamos a escribir un programa para encontrar f para una matriz aleatoria de datos.

Programa 1. Búsqueda del f óptimo.

double PL[]={9,18,7,1,10,-5,-3,-17,-7};  // Matriz de beneficios/pérdidas del libro
double Arr[]={2,-1};

void OnStart()
{
SearchMaxFactor(Arr);                   //O bien PL y cualquier otra matriz

}

void SearchMaxFactor(double &arr[])
{
double MaxProfit=0,K=0;                  // Beneficio máximo
                                         // y el coeficiente que le corresponde
for(int i=1;i<=100;i++)
{
   double k,profit,min;
   min =MathAbs(arr[ArrayMinimum(arr)]); // encontramos las pérdidas máximas en la matriz
   k =i*0.01;                            
   profit =1;
// Encontramos la rentabilidad con el coeficiente indicado
      for(int j=0;j<ArraySize(arr);j++)
      {
         profit =profit*(1+k*arr[j]/min);
      }
// Comparamos con la rentabilidad máxima 
   if(profit>MaxProfit)
   {
   MaxProfit =profit;
   K=k;
   }
}
Print("Optimal K  ",K," Profit   ",NormalizeDouble(MaxProfit,2));

}

Podemos asegurarnos de que para el caso +2,-1,+2,-1, etcétera, f será el mismo que el obtenido con la ayuda de la fórmula de Kelly.

Hay que considerar que la optimización tiene sentido solo para los sistemas rentables, es decir, aquellos sistemas para los que la esperanza matemática (beneficio medio) es positiva. Para los sistemas con pérdidas, la óptima es f=0. La gestión del tamaño del lote no hace rentable un sistema con pérdidas. Al contrario, si en el flujo no hay pérdidas, es decir, si P&L>0, la optimización tampoco tiene sentido, f=1, y tenemos que comerciar con el lote máximo.

Podemos, usando las posibilidades gráficas de MQL5, encontrar, no solo el valor máximo de f, sino también ver la curva de distribución del beneficio dependiendo de f. Más abajo presentamos un programa que dibuja el gráfico del beneficio dependiendo del coeficiente f.

Programa 2. Gráfico de beneficio dependiendo de f.

//+------------------------------------------------------------------+
//|                                                      Graphic.mq5 |
//|                                                       Orangetree |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Orangetree"
#property link      "https://www.mql5.com"
#property version   "1.00"

#include<Graphics\Graphic.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
//double PL[]={9,18,7,1,10,-5,-3,-17,-7};             // matriz de beficios/pérdidas del libro
double PL[]={2,-1};

void OnStart()
  {
double X[100]={0};
for(int i=1;i<=100;i++)
   X[i-1]=i*0.01;
double Y[100];
                                      
double min =PL[ArrayMinimum(PL)];                   

if(min>=0){Comment("f=1");return;}
min =MathAbs(min);

int n = ArraySize(X);
double maxX[1]= {0};
double maxY[1] ={0};

for(int j=0;j<n;j++)
{
   double k =X[j];
   double profit =1;
   for(int i=0;i<ArraySize(PL);i++)
   {
     profit =profit*(1+k*PL[i]/min);
   }
   Y[j] =profit;
   if(maxY[0]<profit)
   {
      maxY[0] =profit;
      maxX[0] =k;
   }
}  
CGraphic Graphic;
Graphic.Create(0,"Graphic",0,30,30,630,330);
CCurve *Curve=Graphic.CurveAdd(X,Y,ColorToARGB(clrBlue,255),CURVE_LINES,"Profit");
Curve.LinesStyle(STYLE_DOT);

//Si así lo desea, el gráfico se puede suavizar
/*Curve.LinesSmooth(true);
Curve.LinesSmoothTension(0.8);
Curve.LinesSmoothStep(0.2);*/

CCurve *MAX =Graphic.CurveAdd(maxX,maxY,ColorToARGB(clrBlue,255),CURVE_POINTS,"Maximum"); MAX.PointsSize(8); MAX.PointsFill(true); MAX.PointsColor(ColorToARGB(clrRed,255)); Graphic.XAxis().MaxLabels(100); Graphic.TextAdd(30,30,"Text",255);   Graphic.CurvePlotAll(); Graphic.Update(); Print("Max factor f =   ", maxX[0]);     }


El gráfico para  {+2,-1} tiene el siguiente aspecto:

Prifit


Según el gráfico obtenido, podemos ver que la regla "cuanto mayor sea el riesgo, mayor será el beneficio", no es cierta. En todos los casos en los que la curva está por debajo de 1 (f>0.5), al final obtenemos pérdidas, y si nos sometemos a un juego sin fin, terminaremos con 0 en nuestra cuenta.

Existe una interesante contradicción. Cuanto mayor sea la esperanza matemática del beneficio y más estable sea el sistema, mayor será el coeficiente f. Por ejemplo, para el flujo {-1,1,1,1,1,1,1,1,1,1}, el coeficiente es igual a 0.8, y podría parecer que un sistema así solo se da en sueños. Pero el coeficiente 0.8 denota que las pérdidas máximas permisibles son iguales al 80%, ¡por lo que un buen día podríamos perder el 80% de la cuenta! Sí, desde el punto de vista de la estadística matemática, se trata del tamaño óptimo de lote para el aumento máximo del balance, pero, ¿está usted preparado para asumir semejantes pérdidas?


Hablemos un poco sobre diversificación

Supongamos que tenemos dos estrategias comerciales, A y B, con idéntica distribución de beneficio/pérdidas, por ejemplo, los mismos (+2,-1). Para estos sistemas, el f óptimo será igual a 0.25. Vamos a analizar los casos en los que los sistemas tienen una correlación de 1,0 y -1. El balance de la cuenta lo dividiremos en dos partes iguales entre estos dos sistemas.

Correlación 1, f=0.25

Sistema A Transacción P&L   Sistema B Transacción P&L   Cuenta combinada
   50      50    100
2 25   2 25   150
-1 -18.75   -1 -18.75   112.5
2 28.13   2 28.13   168.75
-1 -21.09   -1 -21.09   126.56
             El beneficio es 26.56

Como podíamos esperar, esta variante no se distingue en nada del caso en el que se comercia con todo el capital de una estrategia. Ahora tomemos el caso en el que la correlación es 0.

Correlación 0, f=0.25

Sistema A Transacción P&L Sistema B Transacción P&L Cuenta combinada
   50    50  100
2 25 2 25 150
2 37.5 -1 -18.75 168.75
-1 -21.1 2 42.19 189.85
-1 -23.73 -1 -23.73 142.39




El beneficio es 42.39

El beneficio resulta significativamente mayor. Y, al fin, el caso con la correlación -1.

Correlación -1, f=0.25

Sistema A Transacción P&L Sistema B Transacción P&L Cuenta combinada
   50    50  100
2 25 -1 -12.5 112.5
-1 -14.08 2 28.12 126.56
2 31.64 -1 -15 142.38
-1 17.8 2 35.59 160.18




El beneficio es 60.18

En este caso, el beneficio es el máximo. Con estos ejemplos y otros semejantes, podemos ver que en el caso de reinvertir el beneficio, la diversificación da mejores resultados. Asimismo, resulta muy sencillo notar que la diversificación no nos protege del peor caso (en nuestro caso, las pérdidas mayores f=0.25 del tamaño del balance), con la excepción de la opción cuando los sistemas tienen una correlación -1. En la práctica, no existen esos sistemas con una correlación -1. Esto resulta análogo al caso de la apertura de posiciones conforme a un instrumento en diferentes direcciones. Basándose en semejantes juicios, Vince llega a la conclusión siguiente. Vamos a mostrar una cita literal del libro.

La moraleja es la siguiente: la diversificación, si se ejecuta de forma correcta, es un método que aumenta los beneficios. No reduce obligatoriamente las pérdidas del peor caso, lo que contradice totalmente la creencia popular.


Correlación y otras estadísticas

Antes de pasar a los métodos paramétricos de búsqueda del coeficiente f, vamos a analizar varias características más del flujo de beneficios. Podría resultar que obtengamos una serie de resultados interrelacionados. Tras transacciones rentables, vienen otras rentables, y tras transacciones con pérdidas, llegan otras con pérdidas. Para descubrir estas dependencias, analizaremos dos métodos: la localización de la autocorrelación de la serie y el test de serie.

El test de serie consiste en el cálculo de un índice que se llama puntuación-Z. En cuanto a su contenido, la puntuación-Z representa el número de desviaciones en el que los datos se retrasan con respecto al valor medio de la distribución normal. Un valor Z negativo nos indica que hay menos franjas (series continuas de beneficio/pérdidas) que en una distrbución normal, lo que significa que después del beneficio probablemente tengamos pérdidas, y al contrario. Fórmula de cálculo de la puntuación-Z:

Z=(N(R-0.5)-Х)/((Х(Х-N))/(N-1))^(1/2)

o Fórmula:

donde:

  • N — número total de transacciones;
  • R — número total de series;
  • X=2*W*L, donde
  • W = es el número total de transacciones rentables en la secuencia;
  • L = es el número total de transacciones con pérdidas en la secuencia

Programa 3. Puntuación-Z.

double Z(double &arr[])
{
int n =ArraySize(arr);
int W,L,X,R=1;
   if(arr[0]>0)
   {
      W=1;
      L=0;
   }
   else
   {
      W=0;
      L=1;
   }

   for(int i=1;i<n;i++)
   {
    if(arr[i]>0)
      {
      W++;
      if(arr[i-1]<=0){R++;}
      }
    else
      {
      L++;
      if(arr[i-1]>0){R++;}
      }    
   }
 X =2*W*L;
 double x=(n*(R-0.5)-X);
 double y =X*(X-n);
 y=y/(n-1);
 double Z=(n*(R-0.5)-X)/pow(y,0.5);  
Print(Z);
return Z;
}

La puntuación-Z se calcula con el Simulador de Estrategias, en cuyo informe (Backtest) se llama precisamente así, "Puntuación-Z".

La autocorrelación constituye la interrelación estática entre secuencias de magnitudes de una serie, tomadas con desplazamiento. Para la serie {1,2,3,4,5,6,7,8,9,10}, será la correlación entre las series {1,2,3,4,5,6,7,8,9} y {2,3,4,5,6,7,8,9,10}. Más abajo analizamos un programa para la búsqueda de la autocorrelación.

Programa 4. Autocorrelación.

double AutoCorr(double &arr[])
{
   int n =ArraySize(arr);
   
   double avr0 =0;
   for(int i=0;i<n-1;i++)
   {
   avr0=avr0+arr[i];
   }
   avr0=avr0/(n-1);
   
   double avr1 =0;
   
   for(int i=1;i<n;i++)
   {
   avr1=avr1+arr[i];
   }
   avr1=avr1/(n-1);
   
   double D0 =0;
   double sum =0.0;
   
   for(int i=0;i<n-1;i++)
   {
   sum =sum+(arr[i]-avr0)*(arr[i]-avr0);
   }
   D0 =MathSqrt(sum);
   
   double D1 =0;
   sum =0.0;
   for(int i=1;i<n;i++)
   {
   sum =sum+(arr[i]-avr1)*(arr[i]-avr1);
   }
   D1 =MathSqrt(sum);
   
   sum =0.0;
   for(int i=0;i<n-1;i++)
   {
   sum =sum +(arr[i]-avr0)*(arr[i+1]-avr1);
   }
   if(D0==0||D1==0) return 1;
   double k=sum/(D0*D1);
return k;
}

Si los resultados de las transacciones están relacionados entre sí, tiene sentido corregir la estrategia comercial. Los mejores resultados se conseguirán si usamos dos coeficientes distintos: f1 y f2, para los beneficios y las pérdidas. Para este caso, escribiremos un módulo de gestión de capital aparte en MQL5.

Métodos paramétricos

Optimizando los parámetros del sistema, podremos usar los dos enfoques. El primero, empírico, se basa directamente en los datos experiementales, cuando optimizamos los parámetros conforme a resultados concretos. El segundo, paramétrico, se basa en las dependencias funcionales o estáticas. Un ejemplo de método paramétrico es la localización del coeficiente óptimo de la fórmula de Kelly. 

Para encontrar el coeficiente óptimo, Vince propone usar la distribución de los beneficios obtenidos. En primer lugar, analiza la distribución normal como la más estudiada y extendida, después construye una distribución generalizada.

La tarea se formula de la manera siguiente. Supongamos que los beneficios/pérdidas han sido distribuidos de acuerdo con las distribuiciones normales (o, en general, con otra cualquiera). Encontramos el coeficiente f óptimo para esta distribución. En el caso de la distribución normal, tendremos suficiente con encontrar en los datos experimentales el valor medio del flujo PL (profit/loss) y la desviación estándar. Estos dos parámetros caracterizan totalmente la distribución normal.

Vamos a recordar la fórmula de la densidad de la distribución normal:

Densidad

donde 

  • σ — es la desviación estándar
  • m — es la esperanza matemática (valor medio).

La propia idea es de nuestro gusto. Con la ayuda de los datos empíricos, encontramos el carácter de la distribución de los beneficos/péridas. Y ya conforme a esta función, hacia la que tienden los resultados, encontramos el parámetro f, evitando con ello la influencia de valores casuales. Pero, por desgracia, en la práctica no todo es tan simple. Vamos a ir por orden. Hablemos primero del propio método.

Distribución

 

En el gráfico, en color azul se ha construido el gráfico de densidad de la distribución normal, donde el valor medio es igual a cero, y la desviación estándar es igual a la unidad. En rojo se representa la integral de esta función. Se trata de una probabilidad acumulativa, es decir la probabilidad de que el valor sea menor o igual a Х. Normalmente se designa con F(x). El gráfico naranja representa la probabilidad de que el valor sea igual o menor a х con х<0, y que el valor sea superior o igual a х con х>0 (F(x)' =1-F(x), con х>0. Todas estas funciones son bien conocidas, y sus valores son fáciles de obtener.

Vamos a necesitar encontrar la media geométrica de las transacciones distribuidas según esta ley. Para ello, Vince propone las siguientes acciones.

En primer lugar, encontramos las características de la distribución: el valor medio y la desviación estándar. A continuación, elegimos el "intervalo de confianza" o la anchura que se expresa en las desviaciones estándar. Normalmente, se elige el intervalo 3σ. Los valores superiores a 3σ se descartan. A continuación, el intervalo se divide en segmentos y se encuentran los "valores asociados" de beneficio/pérdidas (PL). Por ejemplo, para  σ=1 y m=0, el valor de los PL asociados en los límites del intervalo serán m +- 3σ = +3 y -3. Si hemos dividido el intervalo en segmentos de una longitud 0.1σ, los PL asociados serán -3, -2.9, -2.8 ... 0 ... 2.8, 2,9, 3. Y precisamente para este flujo de PL, encontramos el f óptimo.

Dado que diversos valores de PL tiene diferente probabilidad, para cada valor se encontrará su "probabilidad asociada" de P. Tras realizar estas transformaciones, se busca el máximo de los productos:

HPR=(1+PL*f/maxLoss)^Pdonde maxLoss supone las pérdidas máximas (del módulo).

Aquí Vince propone tomar como probabilidad asociada la probabilidad acumulada, que en nuestro gráfico se muestra en color naranja F'(x).

Sería lógico si la probabilidad acumulada se tomara solo para los valores extremos, y para el resto de los valores P=F'(x)-F'(y), donde х e у son los valores F(x) en los límites del intervalo.

Probabilidades

 

Entonces el multiplicador HPR=(1+PL*f/maxLoss)^P sería una especie de "valor ponderado". La probabilidad total de estos valores, como mandan los cánones, sería igual a la unidad. En el libro, Vince reconoce que los resultados obtenidos de esta formna no coinciden con los resultados obtenidos con los datos reales. Él relaciona este hecho con las limitaciones de la muestra y las diferencias de la distribución con respecto a la normal. Se afirma que al aumentar el número de elementos y su distribución según la ley normal, los valores paramétricos y factuales del coeficiente f óptimo coincidirán.

Resulta interesante que en el ejemplo analizado según su metodología, la probabilidad total sea igual a 7.9. Para encontrar la media geométrica, simplemente extrae del resultado la raíz de 7.9 grado. Según parece, para semejante enfoque existe una base matemática rigurosa.

Teniendo a nuestra disposición una herramienta como MQL5, podemos comprobar esto con facilidad. Para ello, disponemos de la biblioteca Normal.mqh, que se encuentra en la ruta <Math\Stat\Normal.mqh>.

Para los experimentos hemos implementado dos enfoques: exactamente como Vince y el descrito más arriba. Para encontrar las "probabilidades asociadas" se usa la función de biblioteca MathCumulativeDistributionNormal(PL,mean,stand,ProbCum).

 Programa 5. Búsqueda de f óptimo según la distribución normal (de Vince).

//+------------------------------------------------------------------+
//|                                                        Vince.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include<Math\Stat\Math.mqh>
#include<Math\Stat\Normal.mqh>

input double N=3;                      // intervalo de exclusión en las desviaciones estándar
input int M=60;                        // número de segmentos divididos
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
double arr[10000];  
bool ch =MathRandomNormal(1,8,10000,arr);
double mean =MathMean(arr);
double stand =MathStandardDeviation(arr);

double PL[];                      // matriz de "beneficios asociados"
ArrayResize(PL,M+1);
                                  // Rellenando la matriz
for(int i=0;i<M+1;i++)
   {
   double nn =-N+2.0*i*N/M;
   PL[i] =stand*nn+mean;
   }
//............................. matriz de "probabilidades asociadas"
double ProbCum[];
ArrayResize(ProbCum,M+1);
//............................. Rellanando la matriz ..................
ch =MathCumulativeDistributionNormal(PL,mean,stand,ProbCum);
//F'(x)= 1-F(x) при х>0

for(int i=0,j=0;i<M+1;i++)
{
if(i<=M/2)continue;
else j=M-i;
ProbCum[i] =ProbCum[j];
}

double SumProb=0;
for(int i=0;i<M+1;i++)
{
SumProb =SumProb+ProbCum[i];
}
Print("SumProb ",SumProb);
double MinPL =PL[ArrayMinimum(PL)];
double min =arr[ArrayMinimum(arr)];

double f=0.01,HPR=1,profit=1; 
double MaxProfit=1,MaxF=0;


for(int k=0;k<1000;k++)
   {
   f=k*0.001;
   profit =1;  
      for(int i=0;i<M+1;i++)
      {
      HPR=pow((1-PL[i]/MinPL*f),ProbCum[i]);
      profit =HPR*profit;
      }
   if(MaxProfit<profit)
     {
     MaxF =f;
     MaxProfit =profit;
     } 
   }
Print("Profit Vince");   
Print(MaxF,"   ",pow(MaxProfit,1/SumProb),"  ",Profit(MaxF,min,arr));
//... Para realizar la comparación, encontraremos el beneficio máximo según los datos factuales
MaxF =0;
MaxProfit =1;

for(int k=0;k<1000;k++)
   {
   f=k*0.001;
   profit =Profit(f,min,arr);  

   if(MaxProfit<profit)
     {
     MaxF =f;
     MaxProfit =profit;
     } 
   }
Print("------MaxProfit-------");   
Print(MaxF,"   ",MaxProfit);

  }

//   Programa de búsqueda del beneficio según los datos factuales 
//   matriz arr[] con el valor mínimo min
//   y el valor f establecido

double Profit(double f,double min, double &arr[])
{
if(min>=0)
{
   return 1.0;
   Alert("min>=0");
}

double profit =1;
int n =ArraySize(arr);
   for(int i=0;i<n;i++)
   {
   profit =profit*(1-arr[i]*f/min);
   }
return profit;
}

El código del progroma se encuentra en el archivo Vince.mq5

En este programa se busca el coeficiente de la distribución normal y, a continuación, - para realizar la comparación - según los datos factuales. La segunda opción se distingue solo por la matriz de probabilidades "asociadas" y PL.

Programa 6. 

.............................................
double ProbDiff[];
ArrayResize(ProbDiff,M+2);
double PLMean[];
ArrayResize(PLMean,M+2);

ProbDiff[0]=ProbCum[0];
ProbDiff[M+1]=ProbCum[M];
PLMean[0]=PL[0];
PLMean[M+1]=PL[M];

for(int i=1;i<M+1;i++)
{
ProbDiff[i] =MathAbs(ProbCum[i]-ProbCum[i-1]);
PLMean[i] =(PL[i]+PL[i-1])/2;
}
..............................................

El código del programa se encuentra en el archivo Vince_2.mq5

Aquí PLMean[i] =(PL[i]+PL[i-1])/2; es el valor medio de PL en el segmento de división, ProbDiff[] es el valor de probabilidad de que la magnitud se encuentre en el intervalo indicado. En los extremos los valores se descartan (puede ser con stop-loss o take-profit), por eso la probabilidad en los extremos es sencillamente igual a la probabilidad acumulada.

Ambos programas funcionan aproximadamente igual y dan más o menos los mismos resultados. Resulta que la respuesta depende estrechamente de N, la amplitud del descarte ("intervalo de confianza"). Además, lo peor es que al aumentar N, el coeficiente f, obtenido de la distribución normal, tiende a 1. En teoría, cuanto mayor sea el intervalo de "descarte", más preciso debe ser el resultado obtenido. Pero en la práctica esto no es así.

Puede resultar así por el error acumulado. La función exponencial decae bastante deprisa, y nos vemos obligados a lidiar con magnitudes bastante bajas - HPR=pow((1-PL[i]/MinPL*f),ProbCum[i]). Es posible que la propia metodología contenga un error en algún lugar. Pero para el uso práctico, este detalle no es relevante. En cualquier caso, para que funcione correctamente, necesitamos "ajustar" de alguna forma el parámetro N, que influye en gran medida en el resultado.

Está claro que el flujo real de PL se diferencia de la distribución normal. En relación con esto, Vince crea una distribución generalizada con parámetros que imitan las características de cualquier distribución aleatoria. Se añaden parámetros que indican diferentes momentos de la distribución (valor medio, curtosis, anchura, asimetría). Después se presupone, con ayuda de métodos numéricos, encontrar estos parámetros para los datos empíricos y construir la función de distribución del flujo de PL.

Puesto que los resultados de los experimentos con la distribución normal no nos han gustado, hemos decidido no probar los cálculos numéricos con la distribución generalizada. Vamos a exponer un argumento más a favor de nuestras dudas. 

Vince afirma que los métodos paramétricos son mucho más potentes. Y es que, con el aumento del número de experimentos, los datos tenderán hacia los resultados teóricos, ya que el coeficiente obtenido según la muestra no es preciso como consecuencia de las limitaciones de la misma. Pero los parámetros en el caso de la distribución normal (valor medio y desviación estándar) los obtenemos precisamente a partir de esta muestra limitada. La imprecisión del cálculo de las características de la distribución es exactamente la misma. Después, esta imprecisión no hace sino aumentar, debido al error acumulado en los cálculos aumentados. Además, en este caso, como sucede, los resultados en la implementación práctica también dependen de la amplitud del descarte. Puesto que en la práctica la distribución no es normal, añadimos otro eslabón: la búsqueda de la función de distribución, de nuevo basado en aquellos mismos datos empíricos finales. El eslabón adicional conlleva un margen de error añadido en los cálculos.

Aquí nos permitimos expresar nuestra modesta opinión. El enfoque paramétrico es un gran ejemplo de que ciertas ideas, bonitas en teoría, no siempre son tan bellas en la práctica.

Breve reseña del libro de Vince

Ha llegado el momento de resumir el trabajo de Vince: "Las matemáticas de la gestión de capital". El libro supone una mezcla entre la revisión de los métodos de estadística y los diferentes métodos de búsqueda del coeficiente f óptimo. En el libro se analiza un conjunto bastante amplio de temas: el modelo de Marcowitz de gestión del portafolio, la prueba de Kolmogorov-Smirnov para las distribuciones, la valoración de activos financieros de Black-Scholes e incluso los métodos de solución de sistemas de ecuaciones. Todo ello se sale del tema del presente artículo. Lo más importante es que todos estos métodos se analizan en el contexto de la búsqueda del coeficiente f óptimo. Por eso hemos decidido no detenernos en ellos, sino pasar a la implementación práctica de dicho método. La implementación se realizará en forma de módulos para el wizard MQL5.


Módulo del wizard MQL5

En general, la implementación del módulo es semejante a la del módulo estándar MoneyFixedRisk ya disponible. Allí el tamaño del lote se encuentra a través del stop-loss establecido. Para mayor claridad, dejaremos el stop-loss como independiente e indicaremos el coeficiente f y las pérdidas máximas de forma explícita a través de los parámetros de entrada. 

Para comenzar, crearemos en el directorio Include/Expert una nueva carpeta para nuestros módulos, por ejemplo, MyMoney. En esta, crearemos el archivo MoneyF1.mql.

Todos los módulos comerciales constan de un conjunto de partes estándar: la clase del módulo comercial y su descripción especial (descriptor de la clase). 

La clase, como norma, contiene:

  • un constructor;
  • un destructor;
  • funciones de establecimiento de los parámetros de entrada;
  • una función de comprobación de los parámetros introducidos ValidationSettings(void);
  • métodos de definición del volumen de la posición CheckOpenLong(double price,double sl) y CheckOpenShort(double price,double sl).

Vamos a llamar nuestra clase CMoneyFactor

class CMoneyFactor : public CExpertMoney
  {
protected:
   //--- input parameters
   double            m_factor;          // coeficiente de pérdidas máximas f
   double            m_max_loss;        // pérdidas máximas en puntos

public:
                     CMoneyFactor(void);
                    ~CMoneyFactor(void);
   //---
   void              Factor(double f)       { m_factor=f;}       
   void              MaxLoss(double point)  { m_max_loss=point;}         
   virtual bool      ValidationSettings(void);
   //---
   virtual double    CheckOpenLong(double price,double sl);               
   virtual double    CheckOpenShort(double price,double sl);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
void CMoneyFactor::CMoneyFactor(void) : m_factor(0.1),
                                        m_max_loss(100)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
void CMoneyFactor::~CMoneyFactor(void)
  {
  }

Las pérdidas máximas en puntos se establecen con el tipo double, para que exista correspondencia con el módulo estándar. Esto se releciona con el hecho de que en otros módulos suministrados junto con el distribuidor, el stop-loos y el take-profit determinados en la clase básica ExpertBase.mqh se indican en puntos.

   ExpertBase.mqh
   int digits_adjust=(m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 10 : 1;
   m_adjusted_point=m_symbol.Point()*digits_adjust;

Es decir, para las cotizaciones con cinco y tres dígitos decimales, un punto es igual a 10*Point(). 105 puntos en relación con Point() son iguales a 10.5 puntos en los módulos estándar para MQL5.

Las funciones Factor(double f) y MaxLoss(double point) establecenlos parámetros de entrada y deberán nombrarse de la misma forma en la que posteriormente serán descritos en el descriptor del módulo.

Función de comprobación de la corrección de los parámetros introducidos:

bool CMoneyFactor::ValidationSettings(void)
  {
   if(!CExpertMoney::ValidationSettings())
   return(false);
//--- initial data checks  
   if(m_factor<0||m_factor>1)
   {
   Print(__FUNCTION__+"El tamaño del coeficiente debe encontrarse entre 0 y 1");
   return false;   
   }
 
  return true;
  }

Aquí comprobamos que el valor del coeficiente esté entre 0 y 1.

Al fin, las propias funciones de definición del volumen de la posición. Para la apertura en "long":

double CMoneyFactor::CheckOpenLong(double price,double sl)
{
   if(m_symbol==NULL)
      return(0.0);
//--- Definiendo el tamaño del lote
   double lot;
   
/*   
      ExpertBase.mqh
      int digits_adjust=(m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 10 : 1;
      m_adjusted_point=m_symbol.Point()*digits_adjust;
*/
    double loss;
    if(price==0.0)price =m_symbol.Ask();
    loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,price,price - m_max_loss*m_adjusted_point);
    double stepvol=m_symbol.LotsStep();
    lot=MathFloor(m_account.Balance()*m_factor/loss/stepvol)*stepvol;
   
   double minvol=m_symbol.LotsMin();
//---comprobación del lote mínimo
   if(lot<minvol)
      lot=minvol;
//---comprobación del lote máximo
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol)
      lot=maxvol;
//--- return trading volume
   return(lot);

}

Aquí las pérdidas máximas se encuentran con la ayuda del método de biblioteca de la clase CAccountInf - OrderProfitCheck(). Después se ha añadido la comparación del lote sobre su correspondencia con los valores límite máximo y mínimo.

Al principio de cada módulo tenemos su descripción (descriptor), que el compilador necesita para su reconcimiento.

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Comercio con el coeficiente f óptimo                     |
//| Type=Money                                                       |
//| Name=FixedPart                                                   |
//| Class=CMoneyFactor                                               |
//| Page= ?                                                          |
//| Parameter=Factor,double,0.1,Parte óptima fija       |
//| Parameter=MaxLoss,double,50,Pérdidas máximas en puntos        |
//+------------------------------------------------------------------+
// wizard description end

Para los experimentos, este módulo se puede compilar con cualquier módulo de señales comerciales disponible. Podemos compilar de manera preliminar el módulo de señales comerciales elegido con el módulo de gestión de capital con lote fijo. Los resultados obtenidos los usamos para encontrar las pérdidas máximas y el flujo de PL. Después, según estos resultados, encontramos el factor f óptimo con la ayuda del Programa 1. De esta forma, según los datos experimentales podemos encontrar el coeficiente f óptimo. Otro método para encontrar el coeficiente f óptimo parte directamente del asesor obtenido, usando como base nuestro módulo a través de la optimización. Nuestros resultados divergen solo en +/- 0.01. Esto se relaciona con el margen de error de cálculos, por ejemplo, a causa del redondeo.

El código del módulo se encuentra en el archivo MoneyF1.mqh.

Puede suceder que el flujo de nuestros beneficios/pérdidas tenga una autocorrección significativa. Esto se puede aclarar con la ayuda de los programas mostrados anteriormente para el cálculo de la "puntuación-Z" y la autocorrelación. Entonces tiene sentido indicar dos coeficientes: f1 y f2. El primero se aplica después de las transacciones rentables, el segundo, tras las transacciones con pérdidas. Vamos a escribir para esta estrategia un segundo módulo de gestión de capital. Los coeficientes los podemos encontrar después con la ayuda de la optimización, o bien directamente con los datos del flujo de beneficios/pérdidas para la misma estrategia con lote fijo.

Programa 7. Definiendo los f1 y f2 óptimos según el flujo de beneficios/pérdidas.

void OptimumF1F2(double &arr[])
{
double f1,f2;
double profit=1;
double MaxProfit =0;
double MaxF1 =0,MaxF2 =0;
double min =MathAbs(arr[ArrayMinimum(arr)]);

   for(int i=1;i<=100;i++)
   {
   f1 =i*0.01;
      for(int j=1;j<=100;i++)
      {
         f2 =j*0.01;
         profit =profit*(1+f1*arr[0]/min);
            for(int n=1;n<ArraySize(arr);n++)
            {
            if(arr[n-1]>0){profit =profit*(1+f1*arr[n]/min);}
            else{profit =profit*(1+f2*arr[n]/min);}
            }
         if(MaxProfit<profit)
         {
         MaxProfit=profit;
         MaxF1 =i;MaxF2 =j;
         }   
      }
   }

Por consiguiente, para el wizard de MQL5 tenemos que rehacer las funciones principales de gestión de capital. En primer lugar, añadiremos un parámetro más — f2 — y su comprobación. En segundo lugar, reharemos las funciones CheckOpenLong() y CheckOpenShort(). Para determinar el resultado financiero de la anterior transacción, añadiremos la función CheckLoss().

//+------------------------------------------------------------------+
//| Comprueba el resultado de la anterior transacción                            |
//+------------------------------------------------------------------+
double CMoneyTwoFact:: CheckLoss()
  {
double lot=0.0;
HistorySelect(0,TimeCurrent());

int deals=HistoryDealsTotal();           // número de transacciones en la historia
CDealInfo deal;
//--- búsqueda de la transacción anterior
if(deals==1) return 1;
   for(int i=deals-1;i>=0;i--)
   {
   if(!deal.SelectByIndex(i))
      {
      printf(__FUNCTION__+": error al elegir la transacción según el índice");
      break;
      }
//--- selección de transacciones por símbolo o cualquier otro
      if(deal.Symbol()!=m_symbol.Name()) continue;
//--- retornamos el resultado de la transacción
    lot=deal.Profit();
    break;
   }

   return(lot);
  }

Funciones CheckOpenLong()  CheckOpenShort():

double CMoneyTwoFact::CheckOpenLong(double price,double sl)
  {
   double lot=0.0;
   double p=CheckLoss();
   
/*   
      ExpertBase.mqh
      int digits_adjust=(m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 10 : 1;
      m_adjusted_point=m_symbol.Point()*digits_adjust;
*/
   
   double loss;
   
   if(price==0.0)price =m_symbol.Ask();   
   if(p>0)
      {
      loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,price,price - m_max_loss*m_adjusted_point);
      double stepvol=m_symbol.LotsStep();
      lot=MathFloor(m_account.Balance()*m_factor1/loss/stepvol)*stepvol;
      }  
   if(p<0)
      { 
      loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,price,price - m_max_loss*m_adjusted_point);
      double stepvol=m_symbol.LotsStep();
      lot=MathFloor(m_account.Balance()*m_factor2/loss/stepvol)*stepvol;
      }


  return(lot);   
  }
//+------------------------------------------------------------------+

double CMoneyTwoFact::CheckOpenShort(double price,double sl)
  {
  double lot=0.0;
  double p=CheckLoss();
/*   int digits_adjust=(m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 10 : 1;
   m_adjusted_point=m_symbol.Point()*digits_adjust;*/
   
   double loss;
   
   if(price==0.0)price =m_symbol.Ask();   
   if(p>0)
      {
      loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,price,price+m_max_loss*m_adjusted_point);
      double stepvol=m_symbol.LotsStep();
      lot=MathFloor(m_account.Balance()*m_factor1/loss/stepvol)*stepvol;
      }  
   if(p<0)
      { 
      loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,price,price+m_max_loss*m_adjusted_point);
      double stepvol=m_symbol.LotsStep();
      lot=MathFloor(m_account.Balance()*m_factor2/loss/stepvol)*stepvol;
      }
  return(lot);     
  }

El código completo se encuentra en el archivo MoneyF1F2.mqh.

Como hemos mencionado más arriba, en general, el concepto de gestión de capital según Vince gira en torno al coeficiente f óptimo. Por eso, en el ejemplo podemos limitarnos perfectamente a dos módulos. Aunque podemos inventar también cualquier variable adicional. Por ejemplo, añadir elementos de martingale.


Archivos adjuntos

En el archivo Programs.mq5 se encuentran los programas usados en el artículo. Aquí se ha añadido también el programa de lectura de datos del archivo void ReadFile(string file,double &arr[]). Lo necesitamos para encontrar los coeficientes f en el flujo de beneficios/pérdidas del simulador de estrategias. También podemos, claro está, hacer una aproximación detallada y escribir una clase completa para el parseo de informes, como se ha hecho en el artículo "Colocando las entradas por los indicadores". Pero se trata de un programa completo aparte, con sus propias clases.

A nuestro parecer, es más sencillo hacer así. Probamos la estrategia con lote fijo en el simulador de estrategias. Guardamos el informe del simulador en forma de Open XML (MS Office Excel). A la columna "beneficio" añadimos "swap" y "comisión", y obtenemos el flujo de beneficios de PL. Guardamos esta columna aparte en un archivo de texto o un archivo csv. Obtenemos un conjunto de líneas que constan de resultados aparte de cada transacción. La función añadida ReadFile() lee estos resultados en la matriz arr[]. De esta forma tan sencilla, podemos encontrar el f óptimo según los datos de cualquier estrategia con lote fijo.

En los archivos Vince.mq5 y Vince_2.mq5 se encuentran los archivos fuente de los métodos paramétricos de búsqueda de los coeficientes óptimos analizados en el artículo.

Los archivos MoneyF1.mqh y MoneyF1F2.mqh son los archivos fuente de los módulos comerciales de gestión de capital.

El archivo comprimido contiene todos estos archivos, estructurados de acuerdo con su ubicación en el MetaEditor.

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

Archivos adjuntos |
Programs.mq5 (8.42 KB)
Vince.mq5 (5.95 KB)
Vince_2.mq5 (6.27 KB)
MoneyF1.mqh (9.67 KB)
MoneyF1F2.mqh (12.93 KB)
MQL5.zip (9.29 KB)
Patrón de ruptura del canal Patrón de ruptura del canal
Como se sabe, los canales de precios se forman por las tendencias de precios. Una de las señales más fuertes del cambio de la tendencia es la ruptura del canal actual. En este artículo, yo propongo intentar automatizar el proceso de la búsqueda de las señales de este tipo, y ver si es posible formar su propia estrategia a base de eso.
LifeHack para tráders: preparando "comida rápida" a partir de indicadores LifeHack para tráders: preparando "comida rápida" a partir de indicadores
Si usted se ha decidido a dar el salto a MQL5 solo ahora, entonces este artículo le resultará muy útil: por una parte, el acceso a los datos de los indicadores y a las series se ha ejecutado en el estilo MQL4, al que usted ya está acostumbrado, y por otro, toda la implementación se ha escrito en MQL5 con la misma sencillez. Todas las funciones son totalmente comprensibles y se adecuan perfectamente a la depuración paso a paso.
Construcción automática de las líneas de apoyo y resistencia Construcción automática de las líneas de apoyo y resistencia
En el artículo se analiza la construcción automática de las líneas de apoyo y resistencia a través de los máximos y mínimos locales de los gráficos de precio. Para definir estos extremos, usaremos el indicador ZigZag, conocido por todos.
Simulador de estrategias personalizado basado en cálculos matemáticos rápidos Simulador de estrategias personalizado basado en cálculos matemáticos rápidos
El artículo describe el proceso de construcción de un simulador de estrategias personalizado y un analizador de pasadas de optimización de creación propia. Después de leerlo, usted entenderá cómo funciona el modo de cálculos matemáticos y el mecanismo de los llamados frames; también aprenderá a preparar y cargar sus propios datos para los cálculos y a utilizar algoritmos eficientes para la compresión de los mismos. Además, este artículo será de interés para cualquier persona interesada en las distintas formas de almacenamiento de la información del usuario en un experto.