Guia prático do MQL5: Reduzindo o efeito de sobreajuste e lidando com a falta de cotações
Introdução
Acredito que muitos negociantes têm-se intrigado repetidamente sobre os parâmetros ideais para seus sistemas de negociação. Na verdade, um algoritmo de negociação por si só não é suficiente. É preciso ver como ele ainda pode ser usado. Seja qual for a estratégia de negociação que você use, se é simples ou complexa, com um único ou vários instrumentos, você não pode evitar a questão de quais os parâmetros escolher para garantir os lucros futuros.
Estamos propensos a verificar sistemas de negociação com parâmetros que mostraram bons resultados ao longo do período de otimização (teste retrospectivo) e durante o período subsequente (teste progressivo). O teste de progressão, na verdade, não é tão necessário. Os resultados relevantes podem ser obtidos utilizando dados históricos.
Este método ocasiona uma grande questão a qual não pode ser dada uma resposta definitiva: qual a quantidade de dados históricos que deve ser usado para otimizar um sistema de negociação? A questão é que existem muitas opções. Tudo depende da gama de flutuações de preço que você espera para capitalizar.
Voltando para a quantidade de histórico necessário para a otimização, podemos concluir que os dados disponíveis podem ser suficientes para a negociação intra-hora. Isto nem sempre é válido para intervalos de tempo mais longos. Quanto maior o número de repetições de um padrão consistente, ou seja, quanto mais negociações tivermos, mais verdadeiro é o desempenho do sistema de negociação testado que podemos esperar ver no futuro.
E se os dados dos preços de um determinado instrumento não são suficientes para obter um número suficiente de repetições e se sentir mais seguro? Resposta: use dados de todos os instrumentos disponíveis.
Exemplo em NeuroShell DayTrader Professional
Antes de prosseguirmos com a programação em MetaTrader 5, vamos rever um exemplo em NeuroShell DayTrader Professional. Ele oferece ótimos recursos para otimizar os parâmetros de um sistema de negociação (compilado com um construtor) para vários símbolos. Você pode definir os parâmetros necessários nas configurações do módulo de negociação, otimizar os parâmetros para cada símbolo separadamente ou encontrar um conjunto de parâmetros ideais para todos os símbolos de uma só vez. Esta opção pode ser encontrada no guia de otimização:
Fig. 1. A guia de otimização no módulo de negociação de NeuroShell DayTrader Professional
No nosso caso, qualquer sistema de negociação simples fará com que nós só precisemos comparar resultados de dois métodos de otimização, por isso a escolha do sistema é atualmente de pouca importância.
Você pode encontrar informações sobre como compilar as estratégias de negociação em NeuroShell DayTrader Professional, em outros artigos do meu blog (você pode procurar ou usar os caracteres para localizar a informação relevante). Eu também recomendo que você leia um artigo intitulado "Como preparar cotações do MetaTrader 5 para outros aplicativos", que descreve e demonstra como usando um script você pode baixar as cotações de MetaTrader 5 no formato compatível com NeuroShell DayTrader Professional.
Para fazer este teste, eu preparei dados obtidos a partir de barras diárias de oito símbolos a partir do ano de 2000 até janeiro de 2013:
Fig. 2. Lista de símbolo para um teste em NeuroShell DayTrader Professional
A figura abaixo mostra dois resultados de otimização. A parte superior apresenta o resultado da otimização, onde cada símbolo recebe seus próprios parâmetros, enquanto que a parte inferior mostra o resultado em que os parâmetros são comuns a todos os símbolos.
Fig. 3. Comparação dos resultados de dois modos de otimização de parâmetros
O resultado mostrando os parâmetros comuns não parece tão bom quanto aquele em que os parâmetros são diferentes para cada símbolo. No entanto, ele inspira mais confiança já que o sistema de negociação passa por uma série de vários padrões de comportamento de preços (volatilidade, número de tendências/planos), com os mesmos parâmetros para todos os símbolos.
Continuando no mesmo assunto, podemos encontrar logicamente outro argumento em favor da otimização utilizando uma maior quantidade de dados. Pode muito bem ser, que o comportamento do preço de um determinado par de moedas, por exemplo, EURUSD, será bem diferente depois (em dois, cinco ou dez anos). Por exemplo, a inflação dos preços GBPUSD será semelhante ao comportamento passado do preço do EURUSD e vice-versa. Você deve estar pronto para isso já que é veredito para qualquer instrumento.
Um exemplo em MetaTrader 5
Vamos ver agora quais modos de otimização de parâmetros são oferecidos em MetaTrader 5. Abaixo você pode ver todos os símbolos selecionados no modo de otimização Market Watch com uma seta na lista suspensa de modos de otimização.
Fig. 4. Modo de otimização no Testador de Estratégia do MetaTrader 5
Este modo permite que você apenas teste um EA com os parâmetros atuais de cada símbolo, um por um. Os símbolos utilizados nos testes são os que estão atualmente selecionados na janela Market Watch. Em outras palavras, a otimização de parâmetros é, neste caso, não realizada. No entanto, o MetaTrader 5 e MQL5 permitem que você implemente esta ideia por si próprio.
Agora, precisamos ver como implementar o tal EA. A lista de símbolos será fornecida em um arquivo de texto (*.txt). Além disso, vamos implementar a possibilidade de armazenamento de vários conjuntos das listas de símbolos. Cada conjunto estará em uma seção separada com seu próprio cabeçalho dispondo de um número de seção. Os números são necessários para facilitar a verificação visual.
Nota-se que é importante ter o símbolo # frente ao número a fim de permitir que o Expert Advisor obtenha o conjunto de dados corretos quando preenche o conjunto de símbolos. Geralmente, o cabeçalho pode conter quaisquer símbolos mas deve ter # em todos os momentos. O sinal do número pode ser substituído por qualquer outro símbolo, segundo o qual o Expert Advisor irá determinar/contar as seções. Neste caso, a substituição terá que ser refletida no código.
Abaixo você pode ver o arquivo SymbolsList.txt que contém três conjuntos de símbolos para o teste. Este arquivo, como mostrado, ainda será utilizado ao testar o método.
Fig. 5. Vários conjuntos de símbolos fornecidos em um arquivo de texto para o teste
Nos parâmetros externos, vamos adicionar outro parâmetro, SectionOfSymbolList, para indicar o conjunto de símbolos que o Expert Advisor deve usar no teste atual. Este parâmetro assume o valor (de zero para cima) que define o conjunto de símbolos. Se o valor exceder o número de conjuntos disponíveis, o Expert Advisor irá compor uma entrada correspondente ao registro e teste só será feito no símbolo atual.
SymbolsList.txt deve estar localizado no diretório do terminal local sob Metatrader 5\MQL5\Files. Ele também pode ser colocado na pasta comum mas, neste caso, não estará disponível para a otimização de parâmetros na rede em nuvem do MQL5. Além disso, para permitir o acesso ao arquivo e aos indicadores personalizados relevantes para testes, precisamos compor as seguintes linhas no início do arquivo:
//--- Allow access to the external file and indicator for optimization in the cloud #property tester_file "SymbolsList.txt" #property tester_indicator "EventsSpy.ex5"
Nosso Expert Advisor irá basear-se no Expert Advisor multi-moeda já pronto apresentado no artigo "Guia prático do MQL5: Desenvolvendo um Expert Advisor Multi-Moeda com número de parâmetros ilimitados". A sua estratégia de negociação subjacente é muito simples, mas será suficiente para testar a eficácia do método. Nós só removeremos as partes desnecessárias, adicionaremos o que precisamos e corrigiremos o código relevante existente. Vamos, certamente, melhorar o nosso Expert Advisor com o recurso de relatório de economia amplamente descrito no artigo anterior da série "MQL5 Cookbook: Escrevendo a história de negócios em um arquivo e criando gráficos de balanço para cada símbolo no Excel". Gráficos de balanço para todos os símbolos também serão necessários para avaliar a eficiência do método em questão.
Os parâmetros externos do Expert Advisor devem ser modificados da seguinte maneira:
//--- External parameters of the Expert Advisor sinput int SectionOfSymbolList = 1; // Section number in the symbol lists sinput bool UpdateReport = false; // Report update sinput string delimeter_00=""; // -------------------------------- sinput long MagicNumber = 777; // Magic number sinput int Deviation = 10; // Slippage sinput string delimeter_01=""; // -------------------------------- input int IndicatorPeriod = 5; // Indicator period input double TakeProfit = 100; // Take Profit input double StopLoss = 50; // Stop Loss input double TrailingStop = 10; // Trailing Stop input bool Reverse = true; // Position reversal input double Lot = 0.1; // Lot input double VolumeIncrease = 0.1; // Position volume increase input double VolumeIncreaseStep = 10; // Volume increase step
Todas as matrizes associadas com os parâmetros externos devem ser excluídas, como não serão necessárias, e ainda devem ser substituídas por variáveis externas ao longo do código inteiro. Apenas devemos abandonar a matriz dinâmica de símbolos, InputSymbols[], cujo tamanho vai depender do número de símbolos usados a partir de um dos conjuntos no arquivo SymbolsList.txt. Se o Expert Advisor for utilizado fora do Testador de Estratégia, o tamanho dessa matriz será igual a 1, como no modo em tempo real, o Expert Advisor vai trabalhar com apenas um símbolo.
As alterações correspondentes também devem ser feitas no arquivo de inicialização da matriz - InitializeArrays.mqh. Ou seja, todas as funções responsáveis pela inicialização das matrizes de variáveis externas devem ser deletadas. A função InitializeArraySymbols() parece agora como mostrado abaixo:
//+------------------------------------------------------------------+ //| Filling the array of symbols | //+------------------------------------------------------------------+ void InitializeArraySymbols() { int strings_count =0; // Number of strings in the symbol file string checked_symbol =""; // To check the accessibility of the symbol on the trade server //--- Test mode message string message_01="<--- All symbol names in the <- SymbolsList.txt -> file are incorrect ... --->\n" "<--- ... or the value of the \"Section of List Symbols\" parameter is greater, " "than the number of file sections! --->\n" "<--- Therefore we will test only the current symbol. --->"; //--- Real-time mode message string message_02="<--- In real-time mode, we only work with the current symbol. --->"; //--- If in real-time mode if(!IsRealtime()) { //--- Get the number of strings from the specified symbol set in the file and fill the temporary array of symbols strings_count=ReadSymbolsFromFile("SymbolsList.txt"); //--- Iterate over all symbols from the specified set for(int s=0; s<strings_count; s++) { //--- If the correct string is returned following the symbol check if((checked_symbol=GetSymbolByName(temporary_symbols[s]))!="") { //--- increase the counter SYMBOLS_COUNT++; //--- set/increase the array size ArrayResize(InputSymbols,SYMBOLS_COUNT); //--- index with the symbol name InputSymbols[SYMBOLS_COUNT-1]=checked_symbol; } } } //--- If all symbol names were not input correctly or if currently working in real-time mode if(SYMBOLS_COUNT==0) { //--- Real-time mode message if(IsRealtime()) Print(message_02); //--- Test mode message if(!IsRealtime()) Print(message_01); //--- We will work with the current symbol only SYMBOLS_COUNT=1; //--- set the array size and ArrayResize(InputSymbols,SYMBOLS_COUNT); //--- index with the current symbol name InputSymbols[0]=_Symbol; } }
O código da função ReadSymbolsFromFile() também deve ser modificado. Ele costumava ler toda a lista de símbolos enquanto que agora queremos que ele leia apenas o conjunto do símbolo especificado. Abaixo está o código de função modificado:
//+------------------------------------------------------------------+ //| Returning the number of strings (symbols) from the specified | //| set in the file and filling the temporary array of symbols | //+------------------------------------------------------------------+ //--- When preparing the file, symbols in the list should be separated with a line break int ReadSymbolsFromFile(string file_name) { ulong offset =0; // Offset for determining the position of the file pointer string delimeter ="#"; // Identifier of the section start string read_line =""; // For the check of the read string int limit_count =0; // Counter limiting the number of the possibly open charts int strings_count =0; // String counter int sections_count =-1; // Section counter //--- Message 01 string message_01="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n" "<--- The first string does not contain the section number identifier ("+delimeter+")! --->"; //--- Message 02 string message_02="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n" "<--- There is no line break identifier in the last string, --->\n" "<--- so only the current symbol will be involved in testing. --->"; //--- Message 03 string message_03="<--- The <- "+file_name+" -> file could not be found! --->" "<--- Only the current symbol will be involved in testing. --->"; //--- Open the file (get the handle) for reading in the local directory of the terminal int file_handle=FileOpen(file_name,FILE_READ|FILE_ANSI,'\n'); //--- If the file handle has been obtained if(file_handle!=INVALID_HANDLE) { //--- Read until the current position of the file pointer // reaches the end of the file or until the program is deleted while(!FileIsEnding(file_handle) || !IsStopped()) { //--- Read until the end of the string or until the program is deleted while(!FileIsLineEnding(file_handle) || !IsStopped()) { //--- Read the whole string read_line=FileReadString(file_handle); //--- If the section number identifier has been found if(StringFind(read_line,delimeter,0)>-1) //--- Increase the section counter sections_count++; //--- If the section has been read, exit the function if(sections_count>SectionOfSymbolList) { FileClose(file_handle); // Close the file return(strings_count); // Return the number of strings in the file } //--- If this is the first iteration and the first string does not contain the section number identifier if(limit_count==0 && sections_count==-1) { PrepareArrayForOneSymbol(strings_count,message_01); //--- Close the file FileClose(file_handle); //--- Return the number of strings in the file return(strings_count); } //--- Increase the counter limiting the number of the possibly open charts limit_count++; //--- If the limit has been reached if(limit_count>=CHARTS_MAX) { PrepareArrayForOneSymbol(strings_count,message_02); //--- Close the file FileClose(file_handle); //--- Return the number of strings in the file return(strings_count); } //--- Get the position of the pointer offset=FileTell(file_handle); //--- If this is the end of the string if(FileIsLineEnding(file_handle)) { //--- Go to the next string if this is not the end of the file // For this purpose, increase the offset of the file pointer if(!FileIsEnding(file_handle)) offset++; //--- move it to the next string FileSeek(file_handle,offset,SEEK_SET); //--- If we are not in the specified section of the file, exit the loop if(sections_count!=SectionOfSymbolList) break; //--- Otherwise, else { //--- if the string is not empty if(read_line!="") { //--- increase the string counter strings_count++; //--- increase the size of the array of strings, ArrayResize(temporary_symbols,strings_count); //--- write the string to the current index temporary_symbols[strings_count-1]=read_line; } } //--- Exit the loop break; } } //--- If this is the end of the file, terminate the entire loop if(FileIsEnding(file_handle)) break; } //--- Close the file FileClose(file_handle); } else PrepareArrayForOneSymbol(strings_count,message_03); //--- Return the number of strings in the file return(strings_count); }
Você pode ver que algumas sequências no código acima estão destacadas. Essas sequências contêm a função PrepareArrayForOneSymbol() que simplesmente prepara uma matriz para um símbolo (atual) no caso de erro.
//+------------------------------------------------------------------+ //| Preparing an array for one symbol | //+------------------------------------------------------------------+ void PrepareArrayForOneSymbol(int &strings_count,string message) { //--- Print the message to the log Print(message); //--- Array size strings_count=1; //--- Set the size of the array of symbols ArrayResize(temporary_symbols,strings_count); //--- Write the string with the current symbol name to the current index temporary_symbols[0]=_Symbol; }
Agora tudo está pronto para testar o método de otimização de parâmetros. Mas antes de prosseguirmos com o teste, vamos adicionar outra série de dados ao relatório. Anteriormente, em adição ao balanço de todos os símbolos, o arquivo de relatório continha todos os levantamentos a partir de máximos locais expressados em porcentagem. Agora, o relatório também irá abranger todos os levantamentos de crédito em termos monetários. Ao mesmo tempo, vamos modificar a função CreateSymbolBalanceReport() onde o relatório é gerado.
O código da função CreateSymbolBalanceReport() é fornecido abaixo:
//+------------------------------------------------------------------+ //| Creating test report on deals in .csv format | //+------------------------------------------------------------------+ void CreateSymbolBalanceReport() { int file_handle =INVALID_HANDLE; // File handle string path =""; // File path //--- If an error occurred when creating/getting the folder, exit if((path=CreateInputParametersFolder())=="") return; //--- Create a file to write data in the common folder of the terminal file_handle=FileOpen(path+"\\LastTest.csv",FILE_CSV|FILE_WRITE|FILE_ANSI|FILE_COMMON); //--- If the handle is valid (file created/opened) if(file_handle>0) { int digits =0; // Number of decimal places in the price int deals_total =0; // Number of deals in the specified history ulong ticket =0; // Deal ticket double drawdown_max =0.0; // Drawdown double balance =0.0; // Balance string delimeter =","; // Delimiter string string_to_write =""; // To generate the string for writing static double percent_drawdown =0.0; // Drawdown expressed as percentage static double money_drawdown =0.0; // Drawdown in monetary terms //--- Generate the header string string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME," "PRICE,SWAP($),PROFIT($),DRAWDOWN(%),DRAWDOWN($),BALANCE"; //--- If more than one symbol is involved, modify the header string if(SYMBOLS_COUNT>1) { for(int s=0; s<SYMBOLS_COUNT; s++) StringAdd(headers,","+InputSymbols[s]); } //--- Write the report headers FileWrite(file_handle,headers); //--- Get the complete history HistorySelect(0,TimeCurrent()); //--- Get the number of deals deals_total=HistoryDealsTotal(); //--- Resize the array of balances according to the number of symbols ArrayResize(symbol_balance,SYMBOLS_COUNT); //--- Resize the array of deals for each symbol for(int s=0; s<SYMBOLS_COUNT; s++) ArrayResize(symbol_balance[s].balance,deals_total); //--- Iterate in a loop and write the data for(int i=0; i<deals_total; i++) { //--- Get the deal ticket ticket=HistoryDealGetTicket(i); //--- Get all the deal properties GetHistoryDealProperties(ticket,D_ALL); //--- Get the number of digits in the price digits=(int)SymbolInfoInteger(deal.symbol,SYMBOL_DIGITS); //--- Calculate the overall balance balance+=deal.profit+deal.swap+deal.commission; //--- Calculate the max drawdown from the local maximum TesterDrawdownMaximum(i,balance,percent_drawdown,money_drawdown); //--- Generate a string for writing using concatenation StringConcatenate(string_to_write, deal.time,delimeter, DealSymbolToString(deal.symbol),delimeter, DealTypeToString(deal.type),delimeter, DealEntryToString(deal.entry),delimeter, DealVolumeToString(deal.volume),delimeter, DealPriceToString(deal.price,digits),delimeter, DealSwapToString(deal.swap),delimeter, DealProfitToString(deal.symbol,deal.profit),delimeter, DrawdownToString(percent_drawdown),delimeter, DrawdownToString(money_drawdown),delimeter, DoubleToString(balance,2)); //--- If more than one symbol is involved, write their balance values if(SYMBOLS_COUNT>1) { //--- Iterate over all symbols for(int s=0; s<SYMBOLS_COUNT; s++) { //--- If the symbols are equal and the deal result is non-zero if(deal.symbol==InputSymbols[s] && deal.profit!=0) { //--- Display the deal in the balance for the corresponding symbol // Take into consideration swap and commission symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]+ deal.profit+ deal.swap+ deal.commission; //--- Add to the string StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } //--- Otherwise write the previous value else { //--- If the deal type is "Balance" (the first deal) if(deal.type==DEAL_TYPE_BALANCE) { //--- the balance is the same for all symbols symbol_balance[s].balance[i]=balance; StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } //--- Otherwise write the previous value to the current index else { symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]; StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } } } } //--- Write the generated string FileWrite(file_handle,string_to_write); //--- Mandatory zeroing out of the variable for the next string string_to_write=""; } //--- Close the file FileClose(file_handle); } //--- If the file could not be created/opened, print the appropriate message else Print("Error creating the file! Error: "+IntegerToString(GetLastError())+""); }
Nós usamos para calcular abaixamentos na função DrawdownMaximumToString(). Isto agora é realizado pela função TesterDrawdownMaximum(), enquanto que o valor de abaixamento é convertido em uma sequência utilizando a função DrawdownToString() básica.
O código da função TesterDrawdownMaximum() é como se segue:
//+------------------------------------------------------------------+ //| Returning the max drawdown from the local maximum | //+------------------------------------------------------------------+ void TesterDrawdownMaximum(int deal_number, double balance, double &percent_drawdown, double &money_drawdown) { ulong ticket =0; // Deal ticket string str =""; // The string to be displayed in the report //--- To calculate the local maximum and drawdown static double max =0.0; static double min =0.0; //--- If this is the first deal if(deal_number==0) { //--- There is no drawdown yet percent_drawdown =0.0; money_drawdown =0.0; //--- Set the initial point as the local maximum max=balance; min=balance; } else { //--- If the current balance is greater than in the memory, then... if(balance>max) { //--- Calculate the drawdown using the previous values: // in monetary terms money_drawdown=max-min; // expressed as percentage percent_drawdown=100-((min/max)*100); //--- Update the local maximum max=balance; min=balance; } //--- Otherwise else { //--- Return zero value of the drawdown money_drawdown=0.0; percent_drawdown=0.0; //--- Update the minimum min=fmin(min,balance); //--- If the deal ticket by its position in the list has been obtained, then... if((ticket=HistoryDealGetTicket(deal_number))>0) { //--- ...get the deal comment GetHistoryDealProperties(ticket,D_COMMENT); //--- Flag of the last deal static bool last_deal=false; //--- The last deal in the test can be identified by the "end of test" comment if(deal.comment=="end of test" && !last_deal) { //--- Set the flag last_deal=true; //--- Update the drawdown values: // in monetary terms money_drawdown=max-min; // expressed as percentage percent_drawdown+=100-((min/max)*100); } } } } }
O código da função TesterDrawdownMaximum() é como se segue:
//+------------------------------------------------------------------+ //| Converting drawdown to a string | //+------------------------------------------------------------------+ string DrawdownToString(double drawdown) { return((drawdown<=0) ? "" : DoubleToString(drawdown,2)); }
Agora tudo está configurado e pronto para o teste do Expert Advisor e para a análise dos resultados. Logo no início do artigo, vimos um exemplo de arquivo pronto para uso. Vamos fazer o seguinte: otimizar os parâmetros para os símbolos no segundo conjunto (há três símbolos: EURUSD, AUDUSD e USDCHF), e, seguindo a otimização, executar o teste usando todos os símbolos a partir do terceiro conjunto (sete símbolos no total), a fim de ver os resultados para os símbolos cujos dados não estavam envolvidos na otimização de parâmetros.
Otimizando parâmetros e testando o Expert Advisor
O testador de estratégia precisa ser configurado como mostrado abaixo:
Fig. 6. As configurações do testador de estratégia para a otimização
As configurações do Expert Advisor para a otimização de parâmetros são fornecidas abaixo:
Fig. 7. As configurações do Expert Advisor para a otimização de parâmetros
Uma vez que a otimização envolve três símbolos e o aumento do volume de posição é permitido para cada um deles, definimos o lote mínimo para efeitos de abertura de uma posição e o aumento do volume de posição. No nosso caso, o valor é de 0,01.
Após a otimização, nós selecionamos o primeiro resultado através do fator máximo de recuperação e definimos o parâmetro VolumeIncrease em 0,1 para o lote. O resultado é mostrado abaixo:
Fig. 8. O resultado do teste em MetaTrader 5
Abaixo, você pode ver o resultado como mostrado no Excel 2010:
Fig. 9. O resultado do teste para três símbolos como mostrado no Excel 2010
O abaixamento em termos monetários é exibido como marcas verdes no gráfico inferior em termos da segunda escala (auxiliar).
Você também deve estar consciente dos limites gráficos no Excel 2010 (a lista completa das especificações e limites pode ser encontrada na página de especificações e limites do Excel do site da Microsoft Office).
Fig. 10. Especificações e limites gráficos no Excel 2010
A tabela mostra que podemos executar o teste para 255 símbolos ao mesmo tempo e exibir todos os resultados no gráfico! Nós só somos limitados por recursos do computador.
Vamos agora executar o teste para sete símbolos a partir do terceiro conjunto com os parâmetros atuais e conferir o resultado:
Fig. 11. O resultado do teste para sete símbolos como mostrado no Excel 2010
Com sete símbolos considerados, temos 6.901 negócios. Os dados no gráfico são atualizados muito rapidamente no Excel 2010.
Conclusão
Acredito que o método introduzido é digno de atenção pelo fato de que até mesmo uma estratégia de negociação simples, como a que usamos, mostrou bons resultados. Aqui, devemos ter em mente que a otimização só foi realizada por três símbolos dos sete. Nós podemos tentar melhorar o resultado otimizando os parâmetros para todos os símbolos de uma só vez. No entanto, acima de tudo, devemos ter como objetivo melhorar o sistema de negociação, ou melhor ainda, ter um portfólio de vários sistemas de negociação. Entraremos em contato com essa ideia mais tarde.
Isso é tudo. Temos uma ferramenta bastante útil para estudar os resultados das estratégias de negociação multi-moeda. Abaixo está o arquivo zip para download com os arquivos do Expert Advisor para sua consideração.
Após extrair os arquivos, coloque a pasta ReduceOverfittingEA dentro do diretório MetaTrader 5\MQL5\Experts. Adiante, o indicador EventsSpy.mq5 deve ser colocado dentro do MetaTrader 5\MQL5\Indicators. SymbolsList.txt deve ser colocado sob MetaTrader 5\MQL5\Files.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/652
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso