
Gestión de capital según Vince. Implementación como módulo de Wizard MQL5
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 | 0 | ||||
+2 | 21.6 | 129.6 | 44.8 | 156.8 | 100 | 200 | 100.8 | 172.8 | 0 | 0 | ||||
-1 | -12.96 | 116.64 | -31.36 | 125.44 | -100 | 100 | -120.96 | 51.84 | 0 | 0 | ||||
+2 | 23.33 | 139.97 | 50.18 | 175.62 | 100 | 200 | 72.58 | 124.42 | 0 | 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:
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
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:
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.
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)^P, donde 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.
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
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





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso