Otimização automática de EAs no MetaTrader 5
BPASoftware Thai Co. Ltd | 18 dezembro, 2018
Introdução
Nosso EA Buddy Ilan usará 4 parâmetros fundamentais. Seria bom implementar uma auto-otimização semanal desses parâmetros para que o EA correspondesse às mudanças no mercado ao máximo.
Esses parâmetros são:
- SL - stop-loss
- TP - take-profit
- STOFilter - filtro
- STOTimeFrameFilter - filtro do timeframe
É impossível iniciar esse processo a cada semana manualmente, por essa razão, tentamos encontrar mecanismos para realizar tarefas repetitivas. Como não encontramos soluções prontas para o MetaTrader 5, decidimos desenvolver nosso próprio mecanismo.
Graças a Igor Maltsev, autor do artigo "Otimização automatizada de um robô de negociação no trading real" para o terminal MetaTrader 4.
Funcionamento
A primeira instância do terminal MetaTrader 5 trabalha 24/7. É nesse terminal que são iniciados o EA Buddy Ilan e o EA em que trabalharemos nesse artigo (EA Optimizer). Esse EA executa o processo de otimização na segunda instância do terminal MetaTrader 5.
No final do processo, o EA Optimizer define os valores otimizados em variáveis globais, que serão lidas pelo EA Buddy Ilan inicializado.
Como programado, a otimização será realizada todos os sábados sem qualquer manipulação manual.
Copiando dados
Como mencionado acima, precisamos de duas instâncias do terminal MetaTrader 5.
A primeira instância é responsável por copiar a configuração, os parâmetros e os arquivos de relatório entre os dois terminais.
Por razões de segurança, como no MetaTrader 5 é impossível acessar arquivos fora da área restrita, usaremos o comando "xcopy" do MS-DOS para copiar dados entre os dois ambientes.
Para fazer isso, usamos uma DLL baseada em bibliotecas do Windows, que declararemos da seguinte forma:
#import "shell32.dll" int ShellExecuteW(int hwnd,string Operation,string File,string Parameters,string Directory,int ShowCmd); #import
Aqui está a chamada para essa função:
string PathIniFile = sTerminalTesterDataPath + "\\config\\common.ini"; string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\"; int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0);
Essa função também será chamada para executar otimizações, por exemplo:
int start = ShellExecuteW(0, "Open", sTerminalTesterPath + "\\terminal64.exe", "/config:" + TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\optimise.ini", "", 0); if(start<32) { Print("Erro ao iniciar o testador"); return false; }
Para esse EA, deve-se habilitar as importações de DLL:
Auto-otimização
A plataforma MetaTrader 5 pode ser iniciada com comandos (veja "Execução da plataforma de negociação"). Da mesma forma, podem-se executar tarefas automáticas.
Por exemplo, podemos adicionar o bloco de inicialização "[Tester]" ao arquivo de configuração padrão (common.ini), permitindo executar a auto-otimização ao iniciar o MetaTrader 5.
É precisamente isso o que vamos fazer.
Implementação
O EA Optimizer precisa conhecer os caminhos da instância do MetaTrader 5 a ser usada para teste. Esses caminhos serão listados como parâmetros.
input string sTerminalTesterPath = "C:\\Program Files\\ForexTime MT5"; input string sTerminalTesterDataPath="C:\\Users\\BPA\\AppData\\Roaming\\MetaQuotes\\Terminal\\5405B7A2ED87FF45712A041DEF45780";
Nós já definimos o diretório de trabalho no primeiro terminal do MetaTrader 5: "MQL5\Files\Optimiser".
Em seguida, a função "CopyAndMoveCommonIni()" copia o arquivo de configuração padrão "common.ini" da instância do MetaTrader 5 para teste no diretório de trabalho e muda seu nome para "optimise.ini".
bool CopyAndMoveCommonIni() { string PathIniFile= sTerminalTesterDataPath+"\\config\\common.ini"; string PathTester = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\"; int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0); // Esperamos a cópia do arquivo Sleep(2500); if(ret<32) { Print("Erro ao copiar o arquivo .ini"); return false; } // Agora estamos trabalhando na área restrita e podemos usar comandos de arquivo regulares do MetaTrader 5 string IniFileName="Optimiser\\common.ini"; string CopyTo="Optimiser\\optimise.ini"; return FileMove( IniFileName, 0, CopyTo, 0 ); }
Para obter mais informações sobre como funciona a função ShellExecuteW, consulte a documentação da Microsoft para a função. ShellExecuteW. A função não espera a execução do comando do MS-DOS, portanto, é usado um atraso (Sleep 2500).
Agora adicionamos o bloco "Tester" ao arquivo:
bool AddTesterStanza() { int filehandle=FileOpen("Optimiser\\Optimise.ini",FILE_READ|FILE_WRITE|FILE_TXT); if(filehandle!=INVALID_HANDLE) { FileSeek(filehandle,0,SEEK_END); FileWrite(filehandle,"[Tester]\n", "Expert=BuddyIlan\\BuddyIlan\n", "ExpertParameters=BuddyIlanTester.set\n", "Symbol="+_Symbol+"\n", "Period=M15\n", "Login=\n", "Model=4\n", "ExecutionMode=0\n", "Optimization=2\n", "OptimizationCriterion=0\n", "FromDate="+TimeToString(TimeGMT()-InpTesterPeriod*86400,TIME_DATE)+"\n", "ToDate="+TimeToString(TimeGMT(),TIME_DATE)+"\n", "ForwardMode=0\n", "Report=MQL5\\Files\\Reports\\BuddyIlanReport\n", "ReplaceReport=1\n", "ShutdownTerminal=1\n", "Deposit=10000\n", "Currency=EURUSD\n", "Leverage=1:100\n", "UseLocal=1\n", "UseRemote=0\n", "UseCloud=0\n", "Visual=1\n"); FileClose(filehandle); } else { Print("FileOpen, error ",GetLastError()); return false; } return true; }
Até aqui, nós definimos o EA que otimizaremos ("BuddyIlan"), por isso, esse EA deve estar presente no segundo ambiente. Também estabelecemos o arquivo de parâmetros "BuddyIlanTester.set" (o nome deve diferir do nome do EA), definimos o intervalo (de FromDate a ToDate) e todos os parâmetros necessários para a otimização.
Definimos "ShutdownTerminal=1", o que significa que o terminal será encerrado após o término da otimização.
Adicionalmente, será formado o arquivo "Files\Reports\BuddyIlanReport" com o relatório, sendo que nesse ponto a plataforma adicionará a extensão ".xlm".
Se você iniciar EAs num servidor virtual com recursos de computação limitados, será possível usar agentes de teste remotos ou de nuvem ("UseRemote" ou "UseCloud") para otimização.
Arquivo de parâmetros
Agora, é preciso criar o arquivo de parâmetros definido acima (BuddyIlanTester.set), uma vez que ele conterá os valores de cada parâmetro otimizado do EA (Buddy Ilan).
Os valores padrão desses parâmetros são definidos pelo usuário (definidos como parâmetros):
input _TradingMode TradingMode = Dynamic; // Volume fixo ou dinâmico input double InpIlanFixedVolume = 0.1; // Tamanho do volume fixo (se usado) input int InpNCurrencies=1; // Número de instâncias do EA Buddy Ilan na conta input double LotExponent = 1.4; input bool DynamicPips = true; input int DefaultPips = 15; input int Glubina=24; // Número das últimas barras para calcular a volatilidade input int DEL=3; input int TakeProfit = 40.0; // Take-Profit em pontos input int Stoploss = 1000.0; // Stop-Loss em pontos input bool InpIlanTrailingStop = true; // Usar trailing-stop input int InpIlanDistanceTS = 5; // Distância do trailing-stop em pontos input int MaxTrades=10; input int InpDeviation=10; // Desvio máximo permitido em pontos input bool bSTOFilter = true; // Filtro dinâmico de tendência input bool bSTOTimeFrameFilter = false; // Filtro dinâmico de timeframe input int InpMaxTf = 60; // Timeframe máximo
A função a seguir aceita 8 argumentos, os 4 primeiros correspondem aos parâmetros otimizados (SL, TP, STOFilter e STOTimeFrameFilter). Se for true, um "Y" será adicionado ao final da string do parâmetro correspondente. Os quatro argumentos a seguir correspondem aos valores já otimizados que precisam ser considerados na próxima otimização.
Como o nome indica, a função também copia o arquivo de parâmetros para o diretório correspondente da instância do terminal MetaTrader 5 usada para teste (MQL5\Profiles\Tester).
bool CreateAndCopyParametersFile( bool SL, bool TP, bool STOFilter, bool STOTimeFrameFilter, int SLValue, int TPValue, bool STOFilterValue, bool STOTimeFrameFilterValue ) { int filehandle=FileOpen("Optimiser\\BuddyIlanTester.set",FILE_WRITE|FILE_TXT); if(filehandle!=INVALID_HANDLE) { FileWrite(filehandle, "_EA_IDENTIFIER=Buddy Ilan\n", "_EA_MAGIC_NUMBER=1111||0||1||10||N\n", StringFormat("TradingMode=%d||0||0||0||N\n",TradingMode), StringFormat("InpIlanFixedVolume=%lf||0.0||0.000000||0.000000||N\n",InpIlanFixedVolume), StringFormat("InpNCurrencies=%d||0||1||10||N\n",InpNCurrencies), StringFormat("LotExponent=%lf||0.0||0.000000||0.000000||N\n",LotExponent), StringFormat("DynamicPips=%s||false||0||true||N\n",(DynamicPips==true)?"true":"false"), StringFormat("DefaultPips=%d||0||1||10||N\n",DefaultPips), StringFormat("Glubina=%d||0||1||10||N\n",Glubina), StringFormat("DEL=%d||0||1||10||N\n",DEL), StringFormat("TakeProfit=%d||30||10||70||%s\n",(TPValue==0)?30:TPValue,(TP==true)?"Y":"N"), StringFormat("Stoploss=%d||500||250||1500||%s\n",(SLValue==0)?1000:SLValue,(SL==true)?"Y":"N"), StringFormat("InpIlanTrailingStop=%s||false||0||true||N\n",(InpIlanTrailingStop==true)?"true":"false"), StringFormat("InpIlanDistanceTS=%d||0||1||10||N\n",InpIlanDistanceTS), StringFormat("MaxTrades=%d||0||1||10||N\n",MaxTrades), StringFormat("InpDeviation=%d||0||1||10||N\n",InpDeviation), StringFormat("bSTOFilter=%s||false||0||true||%s\n",(STOFilterValue==true)?"true":"false",(STOFilter==true)?"Y":"N"), StringFormat("bSTOTimeFrameFilter=%s||false||0||true||%s\n",(STOTimeFrameFilterValue==true)?"true":"false",(STOTimeFrameFilter==true)?"Y":"N"), StringFormat("InpMaxTf=%d||0||1||10||N\n",InpMaxTf)); FileClose(filehandle); } else { Print("FileOpen BuddyIlanTester.set, error ",GetLastError()); return false; } Sleep(1500); string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\BuddyIlanTester.set"; string PathProfile=sTerminalTesterDataPath+"\\MQL5\\Profiles\\Tester\\"; // Copiamos o arquivo ini para o diretório do testador int ret=ShellExecuteW(0,"Open","xcopy","\""+PathTester+"\" \""+PathProfile+"\" /y","",0); // Esperamos a cópia do arquivo Sleep(2500); if(ret<32) { Print("Erro ao copiar o arquivo de parâmetros"); return false; } return true; }
Execução da otimização
A função a seguir inicia uma instância de teste do MetaTrader 5, enquanto isso, uma otimização é iniciada automaticamente com os parâmetros especificados. Essa segunda instância gera um arquivo com os resultados, após o qual o terminal será encerrado.
bool StartOptimizer() { // Excluímos o relatório anterior FileDelete("Optimiser\\BuddyIlanReport.xml"); // Excluímos o relatório anterior (segunda instância do MetaTrader 5) string PathReport=sTerminalTesterDataPath+"\\MQL5\\Files\\Reports\\BuddyIlanReport.xml"; ShellExecuteW(0,"Open","cmd.exe"," /C del "+PathReport,"",0); Sleep(2500); string sTerminalPath=TerminalInfoString(TERMINAL_PATH); // Inicialização do processo de otimização int start=ShellExecuteW(0,"Open",sTerminalTesterPath+"\\terminal64.exe","/config:"+TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\optimise.ini","",0); if(start<32) { Print("Erro ao iniciar o Testador"); return false; } Sleep(15000); return true; }
A maneira mais fácil de saber se otimização acabou a partir do primeiro terminal é verificar a presença do arquivo de relatório.
Após criar o arquivo de relatório, copie-o para o diretório de trabalho.
bool CopyReport() { int nTry=0; // Esperamos e copiamos o arquivo de relatório while(nTry++<500) // Timeout: 2 horas { string PathReport = sTerminalTesterDataPath + "\\MQL5\\Files\\Reports\\BuddyIlanReport.xml"; string PathTarget = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\"; int ret=ShellExecuteW(0,"Open","xcopy","\""+PathReport+"\" \""+PathTarget+"\" /y","",0); if(ret<32) { PrintFormat("Aguardando geração do relatório (%d) ...",nTry); Sleep(15000); } else { if(FileIsExist("Optimiser\\BuddyIlanReport.xml")==true) { PrintFormat("Relatório (ret=%d) encontrado ...",ret); Sleep(2500); return true; } else { PrintFormat("Aguardando relatório (%d) ...",nTry); Sleep(15000); } } } return false; }
Leitura de resultados
O arquivo de relatório é gerado no formato XML. Por sorte, temos uma biblioteca para trabalhar com esses dados, escrita por Paul van Hemmen. A biblioteca pode ser baixada nesse link: https://www.mql5.com/pt/code/1998.
Adicionamos essa biblioteca ao nosso EA:
#include <EasyXML\EasyXml.mqh>
Adicionamos uma função e fizemos algumas pequenas alterações na biblioteca para adaptá-la aos nossos arquivos de relatório (veja os arquivos anexados).
//+------------------------------------------------------------------+ //| Load XML by given file | //+------------------------------------------------------------------+ bool CEasyXml::loadXmlFromFullPathFile(string pFilename) { string sStream; int iStringSize; Print("Loading XML File ",pFilename); int hFile=FileOpen(pFilename,FILE_ANSI|FILE_READ,0,CP_UTF8); if(hFile==INVALID_HANDLE) { Err=EASYXML_ERR_CONNECTION_FILEOPEN; PrintFormat("[%s] Err=%d",pFilename,GetLastError()); return(Error()); } while(!FileIsEnding(hFile)) { iStringSize = FileReadInteger(hFile, INT_VALUE); sStream += FileReadString(hFile, iStringSize); } FileClose(hFile); return(loadXmlFromString(sStream)); }
O acesso aos dados é realizado de forma simples: várias funções permitem analisar os resultados e ler os dados em que estamos interessados.
bool LoadResults( OptimisationType eType ) { // Variável Init BetterProfit=0.0; // Carregamento de resultados CEasyXml EasyXmlDocument; EasyXmlDocument.setDebugging(false); if(EasyXmlDocument.loadXmlFromFullPathFile("Optimiser\\BuddyIlanReport.xml")==true) { str=""; CEasyXmlNode *RootNode=EasyXmlDocument.getDocumentRoot(); for(int j=0; j<RootNode.Children().Total(); j++) { CEasyXmlNode *ChildNode=RootNode.Children().At(j); for(int i=0; i<ChildNode.Children().Total(); i++) { CEasyXmlNode *cNode=ChildNode.Children().At(i); if(cNode.getName() == "Worksheet" ) { switch(eType) { case _SL : DisplayNodesSL(cNode); PrintFormat("-> SL=%d (Profit=%.2lf)",BetterSL,BetterProfit); break; case _TP : DisplayNodesTP(cNode); PrintFormat("-> TP=%d (Profit=%.2lf DD=%lf)",BetterTP,BetterProfit,BetterDD); break; case _STO : DisplayNodesSTO(cNode); PrintFormat("-> STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf)",(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit); break; } break; } } } } else PrintFormat("Erro"); return true; }
Como precisamos otimizar vários parâmetros cujos resultados terão que ser analisados de forma diferente, precisamos de uma função separada para cada otimização (para os parâmetros SL, TP e STO). Essas são funções recursivas.
Aqui está uma função para analisar os resultados da otimização do parâmetro SL:
void DisplayNodesSL( CEasyXmlNode *Node ) { for(int i=0; i<Node.Children().Total(); i++) { CEasyXmlNode *ChildNode=Node.Children().At(i); if(ChildNode.Children().Total()==0) { str+=ChildNode.getValue()+","; } else { DisplayNodesSL(ChildNode); if(Node.getName()=="Table" && ChildNode.getName()=="Row") { string res[]; StringSplit(str,',',res); // Iteração de cabeçalhos de coluna if(StringCompare(res[0],"Pass",true)!=0) { double profit=StringToDouble(res[2]); int sl=(int) StringToInteger(res[10]); PrintFormat("[%s] Profit=%.2lf StopLoss=%d DD=%s",str,profit,sl,res[8]); if(profit>BetterProfit || (profit==BetterProfit && sl<BetterSL)) { BetterProfit=profit; BetterSL=sl; } } } if(Node.getName()=="Table") str=""; } } }
Essa função é chamada para cada linha e célula.
Se o nó não tiver descendentes, isso significa que ele contém dados, portanto, salvamos esses dados como string, e dividimos no final da linha.
if( ChildNode.Children().Total() == 0 ) { str+=ChildNode.getValue()+","; }
Assim, os valores para cada coluna ficam disponíveis na matriz "res[]" e podemos selecionar os resultados desejados.
Corpo do EA
Agora, temos todos os elementos necessários para otimizar nossos quatro parâmetros, busca dos melhores parâmetros e definição desses valores para as variáveis globais correspondentes que serão lidas pelo EA Buddy Ilan.
void OnTimer() { MqlDateTime dt; datetime now=TimeLocal(dt); // Ao sábado if(dt.day_of_week!=6) { bOptimisationDone=false; return; } // Às 6:00 if(dt.hour<6) return; // Já está feito? if(bOptimisationDone==true) return; // Removemos o arquivo anterior "optimise.ini" FileDelete("Optimiser\\Optimise.ini"); // Criamos e copiamos o arquivo de configuração do EA para a pasta \MQL5\Profiles\Test (instância para teste) if(CreateAndCopyParametersFile(true,false,false,false,0,0,true,false)==false) return; // Copiamos common.ini -> optimise.ini if(CopyAndMoveCommonIni()==false) return; // Adicionamos a inicialização [Tester] a optimise.ini - https://www.metatrader5.com/ru/terminal/help/start_advanced/start if(AddTesterStanza()==false) return; Print("=======================\nOtimização SL-1"); // Inicialização da primeira otimização do SL StartOptimizer(); // Copiamos o arquivo de relatório para o diretório de trabalho if(CopyReport()==false) return; // Analisamos os relatórios if(LoadResults(_SL)==false) return; Print("=======================\nOtimização STO"); // Criamos um arquivo de parâmetros para a otimização do STO (2 parâmetros otimizados ao mesmo tempo) if(CreateAndCopyParametersFile(false,false,true,true,BetterSL,0,true,false)==false) return; // Execução da otimização STO StartOptimizer(); // Copiamos o arquivo de relatório para o diretório de trabalho if(CopyReport()==false) return; if(LoadResults(_STO)==false) return; Print("=======================\nOtimização SL-2"); // Criamos um arquivo de parâmetros para otimização do SL (recálculo com novos valores do parâmetro STO) if(CreateAndCopyParametersFile(true,false,false,false,0,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false) return; // Execução da otimização StartOptimizer(); if(CopyReport()==false) return; if(LoadResults(_SL)==false) return; Print("=======================\nOtimização TP"); // Criamos um arquivo de parâmetros para otimização do TP if(CreateAndCopyParametersFile(false,true,false,false,BetterSL,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false) return; // Execução da otimização StartOptimizer(); if(CopyReport()==false) return; if(LoadResults(_TP)==false) return; // Conclusão PrintFormat("=======================\nSL=%d TP=%d STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf DD=%lf)\n=======================", BetterSL,BetterTP,(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit,BetterDD); // Definimos variáveis globais, pois o Expert Advisor BuddyIlan irá ler e usar esses novos valores. // Se um drawdown de mais de 50% for detectado, o EA parará a negociação if(BetterDD>50.0 && GlobalVariableSet(gVarStop,1.0)==false) { PrintFormat("Erro ao definir a variável global [%s]",gVarStop); } if(GlobalVariableSet(gVarSL,BetterSL)==false) { PrintFormat("Erro ao definir a variável global [%s]=%d",gVarSL,BetterSL); } if(GlobalVariableSet(gVarTP,BetterTP)==false) { PrintFormat("Erro ao definir a variável global [%s]=%d",gVarTP,BetterTP); } if(GlobalVariableSet(gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0)==false) { PrintFormat("Erro ao definir a variável global [%s]=%.1lf",gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0); } if(GlobalVariableSet(gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0)==false) { PrintFormat("Erro ao definir a variável global [%s]=%.1lf",gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0); } bOptimisationDone=true; }
Os nomes das variáveis globais são criados na função OnInit():
int OnInit() { // Variáveis globais gVarStop="BuddyIlan."+_Symbol+".Stop"; gVarSL = "BuddyIlan." + _Symbol + ".SL"; gVarTP = "BuddyIlan." + _Symbol + ".TP"; gVarSTOFilter="BuddyIlan."+_Symbol+".STOFilter"; gVarSTOTimeFrameFilter="BuddyIlan."+_Symbol+".STOTimeFrameFilter";
O seguinte é todo o processo de otimização:
2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_PATH = C:\Program Files\MetaTrader 5 - ActivTrades 2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_DATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\FE0E65DDB0B7B40DE125080872C34D61 2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_COMMONDATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\Common 2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) ======================= 2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-1 2018.07.07 13:20:50.439 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ... 2018.07.07 13:21:05.699 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ... 2018.07.07 13:21:20.859 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ... 2018.07.07 13:21:35.952 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ... 2018.07.07 13:21:38.471 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml 2018.07.07 13:21:38.486 BuddyIlanOptimizer (EURGBP,M15) [0,11032.2600,1032.2600,3.3406,1.7096,1.5083,0.1558,0,6.2173,309,500,] Profit=1032.26 StopLoss=500 DD=6.2173 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [2,11463.8000,1463.8000,4.7837,2.0386,0.8454,0.1540,0,15.4222,306,1000,] Profit=1463.80 StopLoss=1000 DD=15.4222 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [4,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,1500,] Profit=1444.10 StopLoss=1500 DD=15.4493 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [1,11297.1900,1297.1900,4.2392,1.8414,0.8180,0.1400,0,14.1420,306,750,] Profit=1297.19 StopLoss=750 DD=14.1420 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [3,11514.0800,1514.0800,4.9158,2.3170,1.4576,0.2055,0,9.3136,308,1250,] Profit=1514.08 StopLoss=1250 DD=9.3136 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1514.08) 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) ======================= 2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) Optimization STO 2018.07.07 13:22:02.660 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ... 2018.07.07 13:22:17.768 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ... 2018.07.07 13:22:32.856 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ... 2018.07.07 13:22:47.918 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ... 2018.07.07 13:23:02.982 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ... 2018.07.07 13:23:05.485 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml 2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [0,11463.5000,1463.5000,4.4483,2.0614,0.8452,0.1540,0,15.4267,329,false,false,] Profit=1463.50 false false DD=15.4267 2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [1,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,true,false,] Profit=1444.10 true false DD=15.4493 2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [2,11430.5300,1430.5300,5.1090,2.1548,0.8917,0.1717,0,14.4493,280,false,true,] Profit=1430.53 false true DD=14.4493 2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [3,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,true,true,] Profit=1470.71 true true DD=17.3805 2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) -> STOFilter=true STOTimeFrameFilter=true (Profit=1470.71) 2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) ======================= 2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-2 2018.07.07 13:23:29.921 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ... 2018.07.07 13:23:45.043 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ... 2018.07.07 13:24:00.170 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ... 2018.07.07 13:24:15.268 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ... 2018.07.07 13:24:30.340 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ... 2018.07.07 13:24:32.854 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml 2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [0,9269.9000,-730.1000,-2.7760,0.7328,-0.3644,-0.0532,0,19.4241,263,500,] Profit=-730.10 StopLoss=500 DD=19.4241 2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [4,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,1500,] Profit=1470.71 StopLoss=1500 DD=17.3805 2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [3,11475.9500,1475.9500,6.2806,1.8995,0.8175,0.1290,0,17.3718,235,1250,] Profit=1475.95 StopLoss=1250 DD=17.3718 2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [2,11400.7500,1400.7500,5.8609,1.8442,0.7759,0.1292,0,17.3805,239,1000,] Profit=1400.75 StopLoss=1000 DD=17.3805 2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [1,10662.5500,662.5500,2.8807,1.3618,0.3815,0.0862,0,16.7178,230,750,] Profit=662.55 StopLoss=750 DD=16.7178 2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1475.95) 2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) ======================= 2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) Optimization TP 2018.07.07 13:24:57.175 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ... 2018.07.07 13:25:12.311 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ... 2018.07.07 13:25:27.491 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ... 2018.07.07 13:25:42.613 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ... 2018.07.07 13:25:57.690 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ... 2018.07.07 13:26:00.202 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [1,11768.5700,1768.5700,8.2259,2.4484,1.1024,0.2233,0,14.1173,215,40,] Profit=1768.57 TakeProfit=40 DD=14.117300 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [4,12343.5200,2343.5200,13.5464,2.5709,1.3349,0.2519,0,15.0389,173,70,] Profit=2343.52 TakeProfit=70 DD=15.038900 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [0,11243.4600,1243.4600,5.2913,1.6399,0.6887,0.1039,0,17.3805,235,30,] Profit=1243.46 TakeProfit=30 DD=17.380500 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [3,12292.3500,2292.3500,11.8162,2.5837,0.9257,0.2538,0,20.4354,194,60,] Profit=2292.35 TakeProfit=60 DD=20.435400 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [2,12146.3900,2146.3900,11.0639,2.4416,1.2226,0.2292,0,15.0772,194,50,] Profit=2146.39 TakeProfit=50 DD=15.077200 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) -> TP=70 (Profit=2343.52 DD=15.038900) 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) ======================= 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) SL=1250 TP=70 STOFilter=true STOTimeFrameFilter=true (Profit=2343.52 DD=15.038900) 2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) =======================
Fim do artigo
Para implementar esse processo, você precisa de conhecimento mínimo do terminal MetaTrader 5, seus mecanismos de otimização e programação.
O código-fonte desse, o utilitário XML Parser de Paul van Hemmen e o arquivo modificado "EasyXml.mqh" estão anexados ao artigo.
Espero que o artigo seja útil para você.