Usando arquivos de texto para armazenar parâmetros de entrada dos Expert Advisors, indicadores e scripts

23 setembro 2016, 14:54
Andrei Novichkov
0
550

Introdução

Ao desenvolver e utilizar várias ferramentas de negociação, às vezes nos deparamos com casos onde o meio convencional de criação através dos modificadores extern e input não são suficientes o bastante. Embora tenhamos uma solução universal para satisfazer todas as necessidades, ocasionalmente essa solução acaba por ser bastante complicada e inflexível. Considere os seguintes casos como exemplos.

  • Uso das ferramentas tradicionais para criar os parâmetros que raramente serão alterados ou não serão alterados de qualquer modo (por exemplo, número mágico da ordem ou valor de desvio).

  • Se somente uma fonte de dados deve ser selecionada entre uma dúzia de indicadores como RSI, WPR entre outros ou propriedades do EA, os parâmetros de cada um deles devem ser criados e disponibilizados na janela de propriedades, porém precisamos dos parâmetros de apenas um deles. Outro exemplo desse tipo seria uma agenda semanal de operação do EA. Não há muito sentido em armazenar os dados relevantes na segunda-feira e terça-feira (ou serão relevantes na sexta-feira), mas ainda temos que fazer isso, pois a agenda completa precisa ser localizada nas entradas. Em outras palavras, descrever objetos criados dinamicamente nos parâmetros é uma tarefa muito difícil e ineficiente.

  • Se precisamos colocar uma nota, comentário ou cabeçalho na lista de propriedades das ferramentas, temos que criar uma nova propriedade de string com um conteúdo apropriado. Isso pode ser inconveniente algumas vezes. 


Como armazenar parâmetros em arquivos de texto

Os arquivos de texto podem ser utilizados como um complemento ao método padrão de criar e armazenar os parâmetros de entrada. Podemos colocar o que quisermos neles, além do fato de que eles facilmente podem ser editados e movidos. A estrutura pode ser arranjada de modo semelhante aos arquivos INI. Por exemplo, aqui vemos como um array que salva um tipo integer num arquivo de texto pode parecer:

/*array size*/
{array_size},5
/*array*/
{array_init},0,1,2,3,4

No exemplo acima, a "âncora" ou o "nome da seção" é escrito no início da string, seguido pelo conteúdo da seção e separados por vírgulas. Qualquer string única de caracteres pode servir como uma "âncora". Esse arquivo é gerado e salvo no "sandbox" do terminal. Em seguida, vamos abrir este arquivo somente no modo de leitura (como um arquivo CSV) no bloco de inicialização de um indicador, EA ou script.

Quando for o momento de ler o array salvo, buscamos pela "âncora" no arquivo usando o nome conhecido {array_size}. Nós devemos mover o ponteiro do arquivo pelo início do arquivo chamando FileSeek(handle,0,SEEK_SET). Agora, vamos procurar a próxima "âncora" usando um nome conhecido {array_init}. Ao encontrá-la, basta ler nas strings o número necessário de vezes, modificando de acordo com o tipo de array (neste caso, a alteração para integer é realizada). O arquivo incluído ConfigFiles.mqh contém algumas funções simples de aplicação da "âncora" para pesquisa e leitura de dados.

Em outras palavras, um objeto salvo no arquivo geralmente deve ser descrito pela "âncora" com a string seguinte contendo dados separados por vírgulas, conforme exigido pelo formato CSV. Você pode utilizar diversas "âncoras" e strings com os dados seguintes conforme seja necessário, entretanto tenha em mente que uma "âncora" corresponde somente a uma string.

Comentários, assim como várias notas e instruções podem ser escritos em um arquivo de quase todos os formatos e em qualquer local. No entanto, existe uma exigência óbvia: o texto não deve perturbar a "âncora" - sequência de dados. Outra condição desejável - qualquer texto grande deve estar localizado no final do arquivo para simplificar a procura das "âncoras".

Abaixo você pode ver o um possível arranjo para armazenar a agenda de operação do EA, mencionado acima:

….......
{d0},0,0,22
{d1},0,0,22
{d2},1,0,22
…........
{d6},0,0,22

Aqui, o nome "âncora" reflete os dias da semana, utilizando um certo número (por exemplo, {d1} representa o número do dia, e assim por diante). O nome "âncora" é seguido por um valor de tipo bool que define se o EA deve negociar naquele dia ou não (neste caso, não negociar em d1). Se não houver nenhuma negociação, os seguintes valores podem ser ignorados, no entanto eles são deixados. Finalmente, os dois últimos valores de tipo integer representam o início da operação EA e terminam algumas horas depois.

Na abertura de um candle diári, o EA lê a agenda da operação para um novo dia. Certamente, a string de dados para cada dia pode ser alterada e completada por quaisquer outros valores, dependendo da operação lógica. Assim, apenas os dados do dia atual são armazenados na memória.

Você pode definir qualquer nome para a "âncora", no entanto é recomendado utilizar o senso comum. Não há nenhum ponto na atribuição de nomes abstratos para "âncoras". Em vez disso, elas devem transmitir algum significado, permanecendo únicas. Esteja ciente de que a busca de dados é realizada por nomes. Dependendo de uma implementação em particular, um único arquivo pode ter várias "âncoras" com mesmo nome.

Vamos examinar os fragmentos de código extraídos de um indicador totalmente operacional. O indicador precisa dos dados de vários pares de moedas para o seu funcionamento adequado. Assim, ele solicita dados pelo tempo e, em seguida, os processa de acordo com a sua lógica (a lógica do indicador não é importante aqui para nós). Por favor, lembre-se que as corretoras, algumas vezes adicionam vários sufixos e prefixos para nomes simbólicos (por exemplo, EURUSD pode ser transformado em #.EURUSD.ch). Isto deve ser levado em consideração, de modo que o EA possa se referir a outros símbolos corretamente. A sequência de nossas ações é a seguinte.

1. Criar um arquivo de texto broker.cfg com o seguinte conteúdo: 

[PREFIX_SUFFIX],#.,.ch
2. Criar um arquivo de texto <indicator_name>.cfg com o seguinte conteúdo:
/*Número de pares de moedas com a string da "âncora" [CHARTNAMES] */
[CHARTCOUNT],7
/*Nomes dos pares de moedas, cujo os gráficos são utilizados pelo indicador para ler os dados*/
[CHARTNAMES],USDCAD,AUDCAD,NZDCAD,GBPCAD,EURCAD,CADCHF,CADJPY
/*Posição de um par de moeda base (CAD, neste caso) - primeira ou segunda*/ 
[DIRECT],0,0,0,0,0,1,1
3. Coloque os dois arquivos no "sandbox".

4. Definindo várias funções auxiliares no código do indicador (ou incluindo um arquivo ConfigFiles.mqh):

// Abra o arquivo pelo nome especificado como um arquivo CSV e retorna seu manipulador
   int __OpenConfigFile(string name)
     {
      int h= FileOpen(name,FILE_READ|FILE_SHARE_READ|FILE_CSV,',');
      if(h == INVALID_HANDLE) PrintFormat("Invalid filename %s",name);
      return (h);
     }

//+-------------------------------------------------------------------------------------+
//| A função lê um valor iRes de tipo "long" na seção que contém                        |
//| o nome da "âncora" strSec no arquivo manipulado. Se for bem-sucedido,               |
//| o retorno é verdadeiro, caso contrário – falso.                                     |
//+-------------------------------------------------------------------------------------+
   bool _ReadIntInConfigSection(string strSec,int handle,long &iRes)
     {
      if(!FileSeek(handle,0,SEEK_SET) ) return (false);
      string s;
      while(!FileIsEnding(handle))
        {
         if(StringCompare(FileReadString(handle),strSec)==0)
           {
            iRes=StringToInteger(FileReadString(handle));
            return (true);
           }
        }
      return (false);
     }

//+-------------------------------------------------------------------------------------+
//| A função lê o sArray ao contar o tamanho da seção contendo                          |
//| o nome de "âncora" strSec no arquivo manipulado. Se for bem-sucedido,               |
//| o retorno é verdadeiro, caso contrário – falso.                                     |
//+-------------------------------------------------------------------------------------+
   bool _ReadStringArrayInConfigSection(string strSec,int handle,string &sArray[],int count)
     {
      if(!FileSeek(handle,0,SEEK_SET) ) return (false);
      while(!FileIsEnding(handle))
        {
         if(StringCompare(FileReadString(handle),strSec)==0)
           {
            ArrayResize(sArray,count);
            for(int i=0; i<count; i++) sArray[i]=FileReadString(handle);
            return (true);
           }
        }
      return (false);
     }

//+-------------------------------------------------------------------------------------+
//| A função lê bArray do tipo bool ao contar o tamanho da seção contendo               |
//| o nome de "âncora" strSec no arquivo manipulado. Se for bem-sucedido,               |
//| o retorno é verdadeiro,  caso contrário – falso.                                    |                                                .
//+-------------------------------------------------------------------------------------+
   bool _ReadBoolArrayInConfigSection(string strSec,int handle,bool &bArray[],int count)
     {
      string sArray[];
      if(!_ReadStringArrayInConfigSection(strSec, handle, sArray, count) ) return (false);
      ArrayResize(bArray,count);
      for(int i=0; i<count; i++)
        {
         bArray[i]=(bool)StringToInteger(sArray[i]);
        }
      return (true);
     }
Além disso, é incluído o seguinte código para o indicador:
   …..
   input string strBrokerFname  = "broker.cfg";       // Nome do arquivo contendo os dados da corretora
   input string strIndiPreFname = "some_name.cfg";    // Nome do arquivo que contém as configurações do indicador 
   …..

   string strName[];         // Array com nomes de símbolo ([CHARTNAMES])
   int    iCount;            // Número de pares de moeda
   bool   bDir[];            // "Sequência" do array ([DIRECT])

   …..
   int OnInit(void) 
     {

      string prefix,suffix;     // Prefixo e sufixo. As variáveis variáveis necessários para
                                // inicialização, mas usando apenas uma vez.
      prefix= ""; suffix = "";
      int h = _OpenConfigFile(strBrokerFname);
      // Lê dados sobre prefixo e sufixo a partir do arquivo de configuração. Se erros 
      // são corrigidos, continuam com valores padrão.
      if(h!=INVALID_HANDLE) 
        {
         if(!_GotoConfigSection("[PREFIX_SUFFIX]",h)) 
           {
            PrintFormat("Error in config file %s",strBrokerFname);
              } else {
            prefix = FileReadString(h);
            suffix = FileReadString(h);
           }
         FileClose(h);
        }
      ….
      // Lê as configurações do indicator. 
      if((h=__OpenConfigFile(strIndiPreFname))==INVALID_HANDLE)
         return (INIT_FAILED);

      // lê o número dos símbolos
      if(!_ReadIntInConfigSection("CHARTCOUNT]",h,iCount)) 
        {
         FileClose(h);
         return (INIT_FAILED);
        }
      // lê o array com nomes de símbolo depois da leitura do seu número
      if(!_ReadStringArrayInConfigSection("[CHARTNAMES]",h,strName,iCount)) 
        {
         FileClose(h);
         return (INIT_FAILED);
        }

      // transforma o nome de símbolo para o nome padrão
      for(int i=0; i<iCount; i++) 
        {
         strName[i]=prefix+strName[i]+suffix;
        }

      // lê os parâmetros do array de tipo bool
      if(!_ReadBoolArrayInConfigSection("[DIRECT]",h,bDir,iCount)) 
        {
         FileClose(h);
         return (INIT_FAILED);
        }
      ….
      return(INIT_SUCCEEDED);
     }

Dois arrays dinâmicas e duas variáveis ​​locais críticas foram inicializados durante a execução do código. O arquivo gerado broker.cfg virá a calhar, muitas vezes liberando a necessidade de introduzir constantemente um prefixo e sufixo manualmente.

Possíveis áreas de aplicação. Incovenientes e alternativas

Além dos casos já mencionados, o método proposto permite uma gerência conveniente de várias instâncias de um indicador ou um EA trabalhando com diferentes pares de moedas. Ele também pode ser utilizado para tarefas semelhantes que requerem um único "centro de controle". O método também pode ser conveniente quando for necessário qpenas para editar ou substituir um arquivo de texto para uma configuração remota, sem acesso ao terminal em si. Não é incomum quando o FTP é o único meio de acesso a um PC com o terminal instalado.

Outra área de possível aplicação surge quando uma negociação administra uma dúzia de terminais localizados em lugares diferentes (talvez até mesmo em diferentes países). Basta preparar o arquivo de configuração uma vez e enviá-lo para os "sandboxes" de todos os terminais. Se voltarmos ao exemplo mencionado anteriormente, envolvendo a agenda, é possível organizar a sua entrega uma vez por semana para garantir a sicronização da operação dos EAs em todos os PCs. O indicador, cujos fragmentos do código foram mostrados acima, funciona em 28 pares e gerido de forma síncronizada apenas pelos dois arquivos mencionados.

Outra área interessante de aplicação envolve o armazenamento simultâneo de uma variável num arquivo e numa área da propriedade. Neste caso, você poderá implementar uma espécie de lógica de prioridade da leitura. Para ilustrar isso, vamos considerar um fragmento de pseudocódigo baseado na inicialização do número mágico:

…..
extern int Magic=0;
…..
int OnInit(void) 
  {
   …..
   if(Magic==0) 
     {
      // Isto significa que o usuário não inicializou o Número Mágico e
      // o valor padrão permaneceu. Vamos então procurar a variável do Número Mágico num arquivo, 
      …...
     }
   if(Magic==0) 
     {
      // Ainda zero. Assim, não existe tal variável no arquivo
      // Processar a situação atual,
      // saindo com um erro
      return (INIT_FAILED);
     }


Este exemplo revela outra vantagem deste método. No caso, o arquivo é utilizado para o gerenciamento de várias instâncias de indicadores/EA, o método permite a realização mais completa de cada instância separadamente, enquanto ignora a configuração centralizada a partir do arquivo. 

Com a finalidade de manter o objetivo, vamos descrever as desvantagens do método.

O primeiro é a baixa velocidade, porém isso pode não ser um grande problema se você aplicar o método somente durante a inicialização do indicador/EA ou periodicamente (por exemplo, na abertura de uma vela do dia).

O segundo – abordagem minuciosa e cuidadosa da documentação de apoio é crítica. Pode ser muito difícil de demonstrar aos traders como gerenciar ferramentas personalizadas desta forma. Esta é outra razão para raramente armazenar as configurações alteradas em tais arquivos. Claro, a maior atenção deve ser dada à preparação e edição dos próprios de arquivos de texto. Erros nesta fase podem causar graves consequências financeiras.

Agora, vamos examinar as soluções alternativas para as tarefas mencionadas.

Primeiramente, são utilizados arquivos INI. Este é um método confiável de armazenamento de dados. Arquivos INI são utilizados quando você não quer escrever no regitro. Sua estrutura é clara e facilmente compreensível. Abaixo você pode ver o nosso primeiro exemplo (agenda de operação) escrito em arquivo INI:

….......
[d0]
Allowed=0
BeginWork=0
EndWork=22
.........
[d2]
Allowed=1
BeginWork=0
EndWork=22

Também em todos os outros aspectos é semelhante ao trabalho com os arquivos INI - eles devem ser colocados na "sandbox", onde sua velocidade de operação também é bem baixa (embora um pouco melhor do que a dos arquivos CSV). Assim como com arquivos CSV, recomenda-se utilizá-los durante uma inicialização ou em nova abertura da candle. Tenha em mente que você não pode colocar comentários no arquivo de texto INI da maneira que quiser, os arquivos INI têm as suas próprias regras sobre comentários. Enfim, você provavelmente vai enfrentar problemas com a documentação, consequência do formato do arquivo.

A desvantagem deste formato é que você precisa incluir bibliotecas de terceiros. A línguagens MQL não fornecem meios para trabalhar com arquivos INI diretamente, portanto você terá que importá-los do kernell32.dll Você pode encontrar várias bibliotecas fornecendo essa possibilidade no site MQL5, então não colocamos nenhum outro ponto aqui. Essas bibliotecas são simples, já que apenas duas funções são importadas. No entanto, eles ainda podem conter erros. Além disso, você nunca terá certeza de que toda a construção é compatível com o Linux. Se você não tem medo de bibliotecas de terceiros, então você está convidado a usar arquivos INI em par de igualdade com os CSV.

Além dos arquivos INI, existem outras soluções possíveis. Vamos examiná-las em breve.

  1. Usando o registro. Na minha opinião, esta é a solução mais questionável, uma vez que o registro é fundamental para o funcionamento normal do sistema operacional, portanto seria estrategicamente incorreto escrever nele scripts e indicadores.
  2. Utilizando a base de dados. Este é um método seguro de armazenar qualquer volume de dados. Entretanto, um EA ou um indicador realmente precisa de tal quantidade de dados? Na maioria dos casos, a resposta é "não". A funcionalidade das bases de dados é claramente redundante para atingir os nossos objetivos No entanto, bancos de dados ainda são úteis quando você realmente tem de armazenar vários gigabytes de dados.
  3. Usando XML. Na verdade, estes são os mesmos arquivos de texto com síntese diferente que você primeiramente precisa dominá-los. Além disso, você deve desenvolver uma biblioteca (ou baixar uma já pronta) para trabalhar com arquivos XML. A tarefa mais difícil é preparar a documentação de apoio, no final do trabalho. Eu acredito que os resultados dificilmente valem a pena neste caso.

Conclusão

Em conclusão, gostaria de relatar que os arquivos de texto já são amplamente utilizados em vários aspectos da negociação, por exemplo, nos mecanismos de cópia da negociação. Terminais MetaTrader geram e utilizam uma variedade de arquivos de texto diferentes, incluindo arquivos de configuração, vários registros, e-mails e modelos.

O artigo apresentou uma tentativa de aplicar arquivos de texto CSV comuns na configuração das ferramentas de negociação - EAs, indicadores e scripts. Eu usei alguns exemplos simples para ilustrar novas oportunidades proporcionadas por esses arquivos. Além disso, algumas alternativas e inconvenientes detectadas foram analisadas.

De qualquer forma, o método de armazenamento de entradas devem sempre ser selecionado de acordo com as tarefas atuais do desenvolvedor. A eficiência de tal escolha é um dos fatores que demonstram a experiência do desenvolvedor.



Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/2564

Arquivos anexados |
configfiles.mqh (14.7 KB)
Criação de estratégias de negociação manuais usando lógica fuzzy Criação de estratégias de negociação manuais usando lógica fuzzy

No artigo é considerada a possibilidade de melhorar as estratégias de negociação manuais usando a teoria dos conjuntos difusos (fuzzy). Como exemplo, é descrito passo a passo o motor de busca de estratégias e a seleção de seus parâmetros, o uso de lógica fuzzy para diluir os critérios demasiado formais de entrada no mercado. Assim, Depois da modificação da estratégia, nós obtemos condições flexíveis de abertura de posição que respondem melhor à situação de mercado.

Proteção contra falsos positivos do robô de negociação Proteção contra falsos positivos do robô de negociação

A rentabilidade dos sistemas de negociação é determinada não só pela lógica e precisão da dinâmica dos instrumentos financeiros, mas também pela qualidade do algoritmo de execução dessa lógica. Os falsos positivos são uma manifestação característica da má execução da lógica fundamental do robô de negociação. Neste artigo trataremos várias opções para resolver esse problema.

Aprimorando o Testador de Estratégia para Otimizar Indicadores Exclusivamente nos Exemplos dos Mercados Lateral e de Tendência Aprimorando o Testador de Estratégia para Otimizar Indicadores Exclusivamente nos Exemplos dos Mercados Lateral e de Tendência

É essencial detectar se um mercado é lateral ou se o mesmo não está para muitas estratégias. Usando o conhecido ADX, demonstraremos como podemos usar o Testador de Estratégia, tanto para otimizar esse indicador quanto ao nosso objetivo específico, como também podemos decidir se este indicador irá satisfazer as nossas necessidades quanto a variação média dos mercados lateral e de tendência, que são muito importantes para determinar os stops e os alvos dos mercados.

A contribuição de Thomas Demark para a análise técnica A contribuição de Thomas Demark para a análise técnica

Este artigo descreve os pontos TD e as linhas TD inventadas por Thomas Demark, mostra sua aplicação na prática, bem como demostra o processo de escrita de três indicadores e dois EAs usando as ideias dele.