Cómo evaluar los resultados de los Asesores Expertos
Primero de todo, vamos a explicar el procedimiento de las pruebas en unas cuantas líneas. Antes de comenzar con las pruebas, el subsistema carga el asesor experto, estableciendo los parámetros previamente definidos por el usuario, y llama a la función init(). A continuación el Probador recorre la secuencia generada y llama cada vez a la función start(). Al terminar la secuencia de pruebas, el Probador llama a la función deinit(). Entonces está disponible el historial de trading completo, generado durante las pruebas. La eficiencia del asesor experto se puede analizar en ese momento.
La función CalculateSummary proporciona los cálculos de los resultados de las pruebas, es decir, los datos del informe estándar del Probador de Estrategias.
void CalculateSummary(double initial_deposit) { int sequence=0, profitseqs=0, lossseqs=0; double sequential=0.0, prevprofit=EMPTY_VALUE, drawdownpercent, drawdown; double maxpeak=initial_deposit, minpeak=initial_deposit, balance=initial_deposit; int trades_total=HistoryTotal(); //---- inicializamos los resúmenes InitializeSummaries(initial_deposit); //---- for(int i=0; i<trades_total; i++) { if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue; int type=OrderType(); //---- depósito inicial no considerado if(i==0 && type==OP_BALANCE) continue; //---- calculamos el beneficio double profit=OrderProfit()+OrderCommission()+OrderSwap(); balance+=profit; //---- comprobación de la reducción if(maxpeak<balance) { drawdown=maxpeak-minpeak; if(maxpeak!=0.0) { drawdownpercent=drawdown/maxpeak*100.0; if(RelDrawdownPercent<drawdownpercent) { RelDrawdownPercent=drawdownpercent; RelDrawdown=drawdown; } } if(MaxDrawdown<drawdown) { MaxDrawdown=drawdown; if(maxpeak!=0.0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0; else MaxDrawdownPercent=100.0; } maxpeak=balance; minpeak=balance; } if(minpeak>balance) minpeak=balance; if(MaxLoss>balance) MaxLoss=balance; //---- solo órdenes de mercado if(type!=OP_BUY && type!=OP_SELL) continue; SummaryProfit+=profit; SummaryTrades++; if(type==OP_BUY) LongTrades++; else ShortTrades++; //---- operaciones perdedoras if(profit<0) { LossTrades++; GrossLoss+=profit; if(MinProfit>profit) MinProfit=profit; //---- cambio de suerte if(prevprofit!=EMPTY_VALUE && prevprofit>=0) { if(ConProfitTrades1<sequence || (ConProfitTrades1==sequence && ConProfit2<sequential)) { ConProfitTrades1=sequence; ConProfit1=sequential; } if(ConProfit2<sequential || (ConProfit2==sequential && ConProfitTrades1<sequence)) { ConProfit2=sequential; ConProfitTrades2=sequence; } profitseqs++; AvgConWinners+=sequence; sequence=0; sequential=0.0; } } //---- operaciones ganadoras (profit>=0) else { ProfitTrades++; if(type==OP_BUY) WinLongTrades++; if(type==OP_SELL) WinShortTrades++; GrossProfit+=profit; if(MaxProfit<profit) MaxProfit=profit; //---- cambio de suerte if(prevprofit!=EMPTY_VALUE && prevprofit<0) { if(ConLossTrades1<sequence || (ConLossTrades1==sequence && ConLoss2>sequential)) { ConLossTrades1=sequence; ConLoss1=sequential; } if(ConLoss2>sequential || (ConLoss2==sequential && ConLossTrades1<sequence)) { ConLoss2=sequential; ConLossTrades2=sequence; } lossseqs++; AvgConLosers+=sequence; sequence=0; sequential=0.0; } } sequence++; sequential+=profit; //---- prevprofit=profit; } //---- comprobación de reducción final drawdown=maxpeak-minpeak; if(maxpeak!=0.0) { drawdownpercent=drawdown/maxpeak*100.0; if(RelDrawdownPercent<drawdownpercent) { RelDrawdownPercent=drawdownpercent; RelDrawdown=drawdown; } } if(MaxDrawdown<drawdown) { MaxDrawdown=drawdown; if(maxpeak!=0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0; else MaxDrawdownPercent=100.0; } //---- consideramos la última transacción if(prevprofit!=EMPTY_VALUE) { profit=prevprofit; if(profit<0) { if(ConLossTrades1<sequence || (ConLossTrades1==sequence && ConLoss2>sequential)) { ConLossTrades1=sequence; ConLoss1=sequential; } if(ConLoss2>sequential || (ConLoss2==sequential && ConLossTrades1<sequence)) { ConLoss2=sequential; ConLossTrades2=sequence; } lossseqs++; AvgConLosers+=sequence; } else { if(ConProfitTrades1<sequence || (ConProfitTrades1==sequence && ConProfit2<sequential)) { ConProfitTrades1=sequence; ConProfit1=sequential; } if(ConProfit2<sequential || (ConProfit2==sequential && ConProfitTrades1<sequence)) { ConProfit2=sequential; ConProfitTrades2=sequence; } profitseqs++; AvgConWinners+=sequence; } } //---- recopilación hecha double dnum, profitkoef=0.0, losskoef=0.0, avgprofit=0.0, avgloss=0.0; //---- ganancias y pérdidas consecutivas medias dnum=AvgConWinners; if(profitseqs>0) AvgConWinners=dnum/profitseqs+0.5; dnum=AvgConLosers; if(lossseqs>0) AvgConLosers=dnum/lossseqs+0.5; //---- valores absolutos if(GrossLoss<0.0) GrossLoss*=-1.0; if(MinProfit<0.0) MinProfit*=-1.0; if(ConLoss1<0.0) ConLoss1*=-1.0; if(ConLoss2<0.0) ConLoss2*=-1.0; //---- factor de beneficio if(GrossLoss>0.0) ProfitFactor=GrossProfit/GrossLoss; //---- rentabilidad esperada if(ProfitTrades>0) avgprofit=GrossProfit/ProfitTrades; if(LossTrades>0) avgloss =GrossLoss/LossTrades; if(SummaryTrades>0) { profitkoef=1.0*ProfitTrades/SummaryTrades; losskoef=1.0*LossTrades/SummaryTrades; ExpectedPayoff=profitkoef*avgprofit-losskoef*avgloss; } //---- disminución absoluta AbsoluteDrawdown=initial_deposit-MaxLoss; }Hay que conocer el valor inicial del depósito para que los cálculos sean correctos. Para ello hay que llamar a la función AccountBalance() en la función init(). Esto calculará el valor del depósito justo cuando comiencen las pruebas.
void init() { ExtInitialDeposit=AccountBalance(); }El beneficio se calcula en la divisa del depósito, tanto en la función CalculateSummary como en el informe estándar. Los resultados de trading tales como la "Mayor operación de beneficios" o la "Pérdida consecutiva máxima" se calculan en función del beneficio, y también se miden en términos de dinero. Por lo tanto, recalcular el beneficio en puntos es sencillo.
... //---- solo órdenes de mercado if(type!=OP_BUY && type!=OP_SELL) continue; //---- calculamos el beneficio en puntos profit=(OrderClosePrice()-OrderOpenPrice())/MarketInfo(OrderSymbol(),MODE_POINT); SummaryProfit+=profit; ...Los resultados obtenidos se escriben en el archivo del informe con la función WriteReport.
void WriteReport(string report_name) { int handle=FileOpen(report_name,FILE_CSV|FILE_WRITE,'\t'); if(handle<1) return; //---- FileWrite(handle,"Depósito inicial ",InitialDeposit); FileWrite(handle,"Beneficio neto total ",SummaryProfit); FileWrite(handle,"Beneficio bruto ",GrossProfit); FileWrite(handle,"Pérdida bruta ",GrossLoss); if(GrossLoss>0.0) FileWrite(handle,"Factor de beneficio ",ProfitFactor); FileWrite(handle,"Rentabilidad esperada ",ExpectedPayoff); FileWrite(handle,"Disminución absoluta ",AbsoluteDrawdown); FileWrite(handle,"Disminución máxima ", MaxDrawdown, StringConcatenate("(",MaxDrawdownPercent,"%)")); FileWrite(handle,"Disminución relativa ", StringConcatenate(RelDrawdownPercent,"%"), StringConcatenate("(",RelDrawdown,")")); FileWrite(handle,"Total de operaciones ",SummaryTrades); if(ShortTrades>0) FileWrite(handle,"Posiciones cortas (ganado %) ", ShortTrades, StringConcatenate("(",100.0*WinShortTrades/ShortTrades,"%)")); if(LongTrades>0) FileWrite(handle,"Posiciones largas (ganado %) ", LongTrades, StringConcatenate("(",100.0*WinLongTrades/LongTrades,"%)")); if(ProfitTrades>0) FileWrite(handle,"Operaciones de beneficios (% del total)", ProfitTrades, StringConcatenate("(",100.0*ProfitTrades/SummaryTrades,"%)")); if(LossTrades>0) FileWrite(handle,"Operaciones de pérdidas (% del total) ", LossTrades, StringConcatenate("(",100.0*LossTrades/SummaryTrades,"%)")); FileWrite(handle,"Mayor operación de beneficios ",MaxProfit); FileWrite(handle,"Mayor operación de pérdidas ",-MinProfit); if(ProfitTrades>0) FileWrite(handle,"Operación de beneficios media ",GrossProfit/ProfitTrades); if(LossTrades>0) FileWrite(handle,"Operación de pérdidas media ",-GrossLoss/LossTrades); FileWrite(handle,"Media de ganancias consecutivas ",AvgConWinners); FileWrite(handle,"Media de pérdidas consecutivas",AvgConLosers); FileWrite(handle,"Ganancias consecutivas máximas (beneficios en dinero)", ConProfitTrades1, StringConcatenate("(",ConProfit1,")")); FileWrite(handle,"Pérdidas consecutivas máximas (pérdidas en dinero)", ConLossTrades1, StringConcatenate("(",-ConLoss1,")")); FileWrite(handle,"Máximo beneficio consecutivo (número de ganancias)", ConProfit2, StringConcatenate("(",ConProfitTrades2,")")); FileWrite(handle,"Máxima pérdida consecutiva (número de pérdidas)", -ConLoss2, StringConcatenate("(",ConLossTrades2,")")); //---- FileClose(handle); }El siguiente ejemplo ilustra cómo generar un informe con estas funciones.
void deinit() { if(!IsOptimization()) { if(!IsTesting()) ExtInitialDeposit=CalculateInitialDeposit(); CalculateSummary(ExtInitialDeposit); WriteReport("MACD_Sample_Report.txt"); } }Como se observa, los informes se generan no solo después de realizar las pruebas, sino también en la desinicialización del asesor experto. Tal vez usted se pregunte cómo se puede conocer el tamaño del depósito inicial si el historial de la cuenta se descarga en el terminal sólo parcialmente, por ejemplo, con los datos de un solo mes. La función CalculateInitialDeposit ayuda a resolver este problema.
double CalculateInitialDeposit() { double initial_deposit=AccountBalance(); //---- for(int i=HistoryTotal()-1; i>=0; i--) { if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue; int type=OrderType(); //---- depósito inicial no considerado if(i==0 && type==OP_BALANCE) break; if(type==OP_BUY || type==OP_SELL) { //---- calculamos el beneficio double profit=OrderProfit()+OrderCommission()+OrderSwap(); //---- disminuimos el depósito initial_deposit-=profit; } if(type==OP_BALANCE || type==OP_CREDIT) initial_deposit-=OrderProfit(); } //---- return(initial_deposit); }Los informes se generan de este modo en el terminal cliente MetaTrader 4.
Depósito inicial 10000 Beneficio neto total -13.16 Beneficio bruto 20363.32 Pérdida bruta 20376.48 Factor de beneficio 0.99935416 Rentabilidad esperada -0.01602923 Disminución absoluta 404.28 Disminución máxima 1306.36 (11.5677%) Disminución relativa 11.5966% (1289.78) Total de operaciones 821 Posiciones cortas(ganado %) 419 (24.821%) Posiciones largas(ganado %) 402 (31.592%) Operaciones de beneficios (% del total) 231 (28.1364%) Operaciones de pérdidas (% del total) 590 (71.8636%) Mayor operación de beneficios 678.08 Mayor operación de pérdidas -250 Operación de beneficios media 88.15290043 Operación de pérdidas media -34.53640678 Media de ganancias consecutivas 1 Media de pérdidas consecutivas 4 Ganancias consecutivas máximas (beneficios en dinero) 4 (355.58) Pérdidas consecutivas máximas (pérdidas en dinero) 15 (-314.74) Máximo beneficio consecutivo (número de ganancias) 679.4 (2) Máxima pérdida consecutiva (número de pérdidas) -617.16 (8)Se recomienda poner el archivo SummaryReport.mq4 en el directorio experts\include, e insertarlo mediante la directiva #include. Dicho archivo se adjunta en este artículo.
#include <SummaryReport.mq4> double ExtInitialDeposit;
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/1403
- 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