Como avaliar os resultados dos testes do Expert
MetaTrader 4
—
Testador
| 18 fevereiro 2016, 11:21
1 713
0
Em primeiro lugar, algumas palavras a respeito do procedimento de teste. Antes de iniciar o teste, o subsistema de teste carrega o expert, configura os seus parâmetros definidos anteriormente pelo usuário, e chama a função init(). Então o verificador executa a sequência gerada e chama a função start() todas as vezes. Quando a sequência de teste é finalizada, o verificador chama a função deinit(). Além disso, todo o histórico de transações gerado durante o teste fica disponível. A eficiência do expert pode ser analisada nesse momento.
A função CalculateSummary abaixo fornece o cálculo dos resultados do teste, ou seja, os dados fornecidos no relatório padrão do verificador de estratégia.
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(); //---- initialize summaries InitializeSummaries(initial_deposit); //---- for(int i=0; i<trades_total; i++) { if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue; int type=OrderType(); //---- initial balance not considered if(i==0 && type==OP_BALANCE) continue; //---- calculate profit double profit=OrderProfit()+OrderCommission()+OrderSwap(); balance+=profit; //---- drawdown check 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; //---- market orders only if(type!=OP_BUY && type!=OP_SELL) continue; SummaryProfit+=profit; SummaryTrades++; if(type==OP_BUY) LongTrades++; else ShortTrades++; //---- loss trades if(profit<0) { LossTrades++; GrossLoss+=profit; if(MinProfit>profit) MinProfit=profit; //---- fortune changed 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; } } //---- profit trades (profit>=0) else { ProfitTrades++; if(type==OP_BUY) WinLongTrades++; if(type==OP_SELL) WinShortTrades++; GrossProfit+=profit; if(MaxProfit<profit) MaxProfit=profit; //---- fortune changed 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; } //---- final drawdown check 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; } //---- consider last trade 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; } } //---- collecting done double dnum, profitkoef=0.0, losskoef=0.0, avgprofit=0.0, avgloss=0.0; //---- average consecutive wins and losses dnum=AvgConWinners; if(profitseqs>0) AvgConWinners=dnum/profitseqs+0.5; dnum=AvgConLosers; if(lossseqs>0) AvgConLosers=dnum/lossseqs+0.5; //---- absolute values 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; //---- profit factor if(GrossLoss>0.0) ProfitFactor=GrossProfit/GrossLoss; //---- expected payoff 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; } //---- absolute drawdown AbsoluteDrawdown=initial_deposit-MaxLoss; }
Para que os cálculos estejam corretos, o valor do depósito inicial deve ser conhecido. Para isso, na função init(), a função AccountBalance() deve ser chamada, pois ela irá fornecer o valor do balanço no início do teste.
void init() { ExtInitialDeposit=AccountBalance(); }
Na função CalculateSummary acima, assim como no relatório padrão, o lucro é calculado na moeda de depósito. Outros resultados de transações, como a "transação de maior lucro" ou a "perda máxima consecutiva", que são calculados com base no lucro, também são medidos em termos monetários. Portanto, é fácil recalcular o lucro em pontos.
... //---- market orders only if(type!=OP_BUY && type!=OP_SELL) continue; //---- calculate profit in points profit=(OrderClosePrice()-OrderOpenPrice())/MarketInfo(OrderSymbol(),MODE_POINT); SummaryProfit+=profit; ...
Os resultados obtidos podem ser escritos no arquivo do relatório através do uso da função WriteReport.
void WriteReport(string report_name) { int handle=FileOpen(report_name,FILE_CSV|FILE_WRITE,'\t'); if(handle<1) return; //---- FileWrite(handle,"Initial deposit ",InitialDeposit); FileWrite(handle,"Total net profit ",SummaryProfit); FileWrite(handle,"Gross profit ",GrossProfit); FileWrite(handle,"Gross loss ",GrossLoss); if(GrossLoss>0.0) FileWrite(handle,"Profit factor ",ProfitFactor); FileWrite(handle,"Expected payoff ",ExpectedPayoff); FileWrite(handle,"Absolute drawdown ",AbsoluteDrawdown); FileWrite(handle,"Maximal drawdown ", MaxDrawdown, StringConcatenate("(",MaxDrawdownPercent,"%)")); FileWrite(handle,"Relative drawdown ", StringConcatenate(RelDrawdownPercent,"%"), StringConcatenate("(",RelDrawdown,")")); FileWrite(handle,"Trades total ",SummaryTrades); if(ShortTrades>0) FileWrite(handle,"Short positions(won %) ", ShortTrades, StringConcatenate("(",100.0*WinShortTrades/ShortTrades,"%)")); if(LongTrades>0) FileWrite(handle,"Long positions(won %) ", LongTrades, StringConcatenate("(",100.0*WinLongTrades/LongTrades,"%)")); if(ProfitTrades>0) FileWrite(handle,"Profit trades (% of total)", ProfitTrades, StringConcatenate("(",100.0*ProfitTrades/SummaryTrades,"%)")); if(LossTrades>0) FileWrite(handle,"Loss trades (% of total) ", LossTrades, StringConcatenate("(",100.0*LossTrades/SummaryTrades,"%)")); FileWrite(handle,"Largest profit trade ",MaxProfit); FileWrite(handle,"Largest loss trade ",-MinProfit); if(ProfitTrades>0) FileWrite(handle,"Average profit trade ",GrossProfit/ProfitTrades); if(LossTrades>0) FileWrite(handle,"Average loss trade ",-GrossLoss/LossTrades); FileWrite(handle,"Average consecutive wins ",AvgConWinners); FileWrite(handle,"Average consecutive losses",AvgConLosers); FileWrite(handle,"Maximum consecutive wins (profit in money)", ConProfitTrades1, StringConcatenate("(",ConProfit1,")")); FileWrite(handle,"Maximum consecutive losses (loss in money)", ConLossTrades1, StringConcatenate("(",-ConLoss1,")")); FileWrite(handle,"Maximal consecutive profit (count of wins)", ConProfit2, StringConcatenate("(",ConProfitTrades2,")")); FileWrite(handle,"Maximal consecutive loss (count of losses)", -ConLoss2, StringConcatenate("(",ConLossTrades2,")")); //---- FileClose(handle); }
Um exemplo do uso dessas funções para gerar um relatório é fornecido abaixo.
void deinit() { if(!IsOptimization()) { if(!IsTesting()) ExtInitialDeposit=CalculateInitialDeposit(); CalculateSummary(ExtInitialDeposit); WriteReport("MACD_Sample_Report.txt"); } }
Como você pode ver, os relatórios podem ser gerados não apenas após o teste, mas também na deinicialização do Expert Advisor ativo. Você pode estar se perguntando como é possível descobrir o tamanho do depósito inicial caso o histórico da conta tiver sido transferido apenas parcialmente ao terminal (por exemplo, caso apenas o histórico relativo a um mês tiver sido solicitado na aba do histórico da conta). A função CalculateInitialDeposit auxilia na resolução desse 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(); //---- initial balance not considered if(i==0 && type==OP_BALANCE) break; if(type==OP_BUY || type==OP_SELL) { //---- calculate profit double profit=OrderProfit()+OrderCommission()+OrderSwap(); //---- and decrease balance initial_deposit-=profit; } if(type==OP_BALANCE || type==OP_CREDIT) initial_deposit-=OrderProfit(); } //---- return(initial_deposit); }
Essa é a forma com que os relatórios são gerados no terminal do cliente do MetaTrader 4.
Ela pode ser comparada aos dados calculados através do uso do programa exposto.
Initial deposit 10000 Total net profit -13.16 Gross profit 20363.32 Gross loss 20376.48 Profit factor 0.99935416 Expected payoff -0.01602923 Absolute drawdown 404.28 Maximal drawdown 1306.36 (11.5677%) Relative drawdown 11.5966% (1289.78) Trades total 821 Short positions(won %) 419 (24.821%) Long positions(won %) 402 (31.592%) Profit trades (% of total) 231 (28.1364%) Loss trades (% of total) 590 (71.8636%) Largest profit trade 678.08 Largest loss trade -250 Average profit trade 88.15290043 Average loss trade -34.53640678 Average consecutive wins 1 Average consecutive losses 4 Maximum consecutive wins (profit in money) 4 (355.58) Maximum consecutive losses (loss in money) 15 (-314.74) Maximal consecutive profit (count of wins) 679.4 (2) Maximal consecutive loss (count of losses) -617.16 (8)
Recomenda-se colocar o arquivo SummaryReport.mq4 anexo a este artigo no diretório experts\include e inseri-lo através do uso da diretiva #include.
#include <SummaryReport.mq4> double ExtInitialDeposit;
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1403
Arquivos anexados |
SummaryReport.mq4
(12 KB)
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Ir para discussão
Gerenciamento de pedidos - É simples
O artigo trata das várias formas de se controlar posições abertas e pedidos pendentes. Ele tem como objetivo simplificar a escrita de Expert Advisors.
Eventos no MetaTrader 4
O artigo trata do monitoramento programado de eventos no terminal do cliente do MetaTrader 4, como a abertura/fechamento/modificação de pedidos, e é destinado a um usuário que possua habilidades básicas no trabalho com o terminal e em programação em MQL4.
Armazenamento e visualização de informações
O artigo trata de métodos convenientes e eficientes de armazenamento e visualização de informações. São consideradas aqui alternativas ao arquivo log padrão do terminal e à função Comment().
Sincronização de Expert Advisors, scripts e indicadores
O artigo considera a necessidade e os princípios gerais do desenvolvimento de um pacote de programas que incluiria um Expert Advisor, um script e um indicador.
Você está perdendo oportunidades de negociação:
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Registro
Login
Você concorda com a política do site e com os termos de uso
Se você não tem uma conta, por favor registre-se