Meu primeiro "graal"

Сергей Ковалев | 18 fevereiro, 2016


"... a arte não pode ser programada, não se pode desenvolver dois sentidos
de poesia. Talentos não podem ser
cultivados pelo plantio
em fileiras. Eles nascem. Eles são um tesouro
nacional, como depósitos de rádio,
como o setembro em Sigulda, ou Bethesda ..."
(Andrey Voznesenskiy)


O Santo Graal é considerado por muitos a taça da qual Cristo bebeu durante a última ceia, mais tarde usada por José de Arimatéia para colher o seu sangue quando ele foi crucificado. Alguns escritores representam o graal como uma pedra que fornece sustento e que previne, durante uma semana, a morte de qualquer um que a veja. Você pode ler mais sobre o assunto aqui ou fazer uma pesquisa em qualquer mecanismo de busca.

Hoje em dia, a palavra "graal" é frequentemente usada entre programadores modernos de forma irônica. Para eles, ela representa a impossibilidade de se criar um programa "universal", adequado a todas as ocasiões. Especificamente em relação à programação no MQL4, esta palavra significa a impossibilidade de se criar um expert capaz de ter efeitos fantásticos em transações reais.

Na realidade, o Forex é o reflexo de um complexo conglomerado de fenômenos: relações econômicas e industriais, personalidades humanas, política. Além disso, e mais importante, ele não pode ser simplesmente formalizado. Trader experientes recomendam a entrada no mercado apenas caso haja de três a cinco, ou até mais, sinais indicando a possível tendência.

Ao mesmo tempo, as regularidades até hoje determinadas não são capazes de fornecer por completo uma base sólida para previsões de mercado com alta probabilidade de sucesso. As previsões contraditórias feitas por famosos analistas de bancos e organizações financeiras eminentes confirmam este fato. Todos os analistas, sem exceção, podem interpretar os eventos que já ocorreram, mas apenas alguns deles podem apresentar uma sequência de previsões realmente sólidas.

Vamos ser justos: Estas pessoas fazem o que podem. A maioria deles possui uma longa experiência trabalhando com transações e um volume invejável de conhecimento. Contudo, vamos ser claros: praticamente todos eles cometem erros com frequência. Eles podem parecer imponentes, desfrutar de popularidade, muitas vezes acumular uma grande fortuna (gurus de todos os tipos são muito bem escritos no livro de Alexander Elder intitulado Transações comerciais como um meio de vida: Psicologia, táticas de transações, gerenciamento financeiro), mas a verdade é que analistas experientes cometem erros com frequência.

Portanto, considerando essas circunstâncias, que chances tem um programador de primeira viagem que está dando os seus primeiros passos no mercado de transações em Forex? Vamos tentar reexaminar a jornada empreendida por aquele iniciante que parte em busca do seu "graal".


1. O que o "graal" compreende

Na lógica forma, a alegação de autoridade não é considerada uma evidência. Com base nisso, o programador de primeira viagem raciocina do seguinte modo: "É possível provar que a criação de "graal" é impossível? Não? Então é possível!". O iniciante não leva em consideração que a possibilidade de criação de tal objeto também nunca foi provada. Assim, sem considerar ou muitas vezes sem sequer examinar a experiência de outros "garimpeiros", mas inspirado pela ideia de "ser capaz", e tendo como base exclusivamente o seu entusiasmo e falta de experiência, começa o trabalho de programação.

1.1. Estratégia formal

Na maior parte dos casos, o programador de primeira viagem não se impõe a tarefa de criar uma estratégia de transações super lucrativa dentro de um curto espaço de tempo. Mesmo empolgado pelo sonho de obter lucros grandes e rápidos no Forex, ele percebe que um conjunto preciso de critérios de transação é necessário para que um expert seja lucrativo.

Para encontrar bons critérios, nosso programador abre o terminal do cliente do MetaTrader 4 e examina o cronograma de M1 no gráfico EURUSD. É bastante fácil notar que as alterações na taxa de câmbio se dão em ondas: para cima e para baixo, para cima e para baixo. O programador decide lucrar com essas ondas. Mas para "pegar" uma onda, é preciso saber, de algum modo, que a onda parou de subir, por exemplo, e começou a descer.

Caso se escolha a taxa de movimento simples como critério de direção, não se obterá qualquer resultado, pois candles pretas e brancas substituem umas às outras com grande frequência, e a amplitude dessas pequenas mudanças está dentro do valor de margem, ou bem próximo a ele. Além disso, seria preferível entrar no mercado na crista da onda, e não em seu declive. E ondas, infelizmente, tem alturas diferentes. Após alguma reflexão, nosso programador define os seguintes critérios:



Figura 1. Critérios de transação para o expert graal_1 (graal 1)

Bem, às vezes a vida nos coloca em situações incríveis e inesperadas: O programador novato levou apenas 3 dias para criar o seu primeiro "graal".

extern int TP=100; extern int SL=100; extern int lim=1; extern int prodvig=3;
extern double  Prots= 10;
int   total, bb=0,ss=0; double max,min,lmax,lmin,Lot; 
int start(){
total=OrdersTotal(); if (total==0){bb=0;ss=0;}
if (max<Bid) max=Bid;if (min>Ask) min=Ask;
if (((max-Bid)>=lim*Point)&&(Bid>lmax )) { for (int i=total;i>=0;i--) { 
if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true && OrderType()==OP_BUY)
{OrderClose(OrderTicket(),OrderLots(),Bid,3,CLR_NONE); bb=0;}} Strateg(1); } 
if (((Ask-min)>=lim*Point)&&(lmin>Ask )) { for (i=total;i>=0;i--) {
if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true && OrderType()==OP_SELL)
{OrderClose(OrderTicket(),OrderLots(),Ask,3,CLR_NONE);ss=0;}}  Strateg(2);}return;}
void Strateg (int vv)                                    
{if (vv==1 && ss==0)                                   
{OrderSend(Symbol(),OP_SELL,Lots(),Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Red); ss=1;}
if (vv==2 && bb==0)                                   
{OrderSend(Symbol(),OP_BUY, Lots(),Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Blue);bb=1;}
lmax=Ask+prodvig*Point; lmin=Bid-prodvig*Point;   return;  }
double Lots(){ Lot=NormalizeDouble(AccountEquity()*Prots/100/1000,1);
double Min_Lot = MarketInfo(Symbol(), MODE_MINLOT);   
if (Lot==0 ) Lot=Min_Lot; return(Lot);  }


Então não devemos criar grandes expectativas. Vamos ser justos: esta é a primeira experiência do programador de primeira viagem, cujo estilo ainda não foi moldado. E vamos respeitar este expert, pois ele funciona e exibe resultados realmente fantásticos.

Vamos apresentar o código sob uma forma mais legível e tentar entender o que é o que. Após uma leve edição, o expert pode ficar assim:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Graal_1.mq4 (Grail 1).
// Used as an example in the article My First "Grail".
// Sergey Kovalyov, Dnepropetrovsk (Ukraine),sk@mail.dnepr.net,ICQ 64015987, http://autograf.dp.ua/
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
extern int     TP = 100;                                 // TakeProfit orders
extern int     SL = 100;                                 // StopLoss orders
extern int     lim=   1;                                 // Distance of the rate return
extern int     prodvig=3;                                // Distance of the rate progress
extern double  Prots= 10;                                 // Percentage of the liquid assets
//--------------------------------------------------------------------------------------------
int
   total,                                                // Count of lots
   bb=0,                                                 // 1 = the Buy order is available
   ss=0;                                                 // 1 = the Sell order is available 
//--------------------------------------------------------------------------------------------
double 
   max,                                                  // Maximum price at the peak (abs.)
   min,                                                  // Minimum price in the trough(abs.)
   lmax,                                                 // Limiting price after the exceeding
                                                         // of which we consider selling(abs.)
   lmin,                                                 // The same for buying
   Lot;                                                  // Count of lots
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int start()
   {   
//============================================================================================
   total=OrdersTotal();                                  // Count of lots
   if (total==0)                                         // If there are no orders, ..
      {
      bb=0;                                              // .. no Buys
      ss=0;                                              // .. no Sells
      }
   if (max<Bid) max=Bid;                                 // Calculate the max. price at the peak 
   if (min>Ask) min=Ask;                                 // Calculate the min. price in the trough
//------------------------------------------------------------- The price turns down ----
   if (((max-Bid)>=lim*Point)&&(Bid>lmax ))              // Turn at a high level
      {
      for (int i=total;i>=0;i--)                         // On all orders
         {                                               
         if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true && OrderType()==OP_BUY)
            {
            OrderClose(OrderTicket(),OrderLots(),Bid,3,CLR_NONE);// Close Buy
            bb=0;                                        // No Buys anymore
            }
         }   
      Strateg(1);                                        // Opening function
      }             
//------------------------------------------------------------ The price turns up ----
   if (((Ask-min)>=lim*Point)&&(lmin>Ask ))              // Turn at the deep bottom
      {
      for (i=total;i>=0;i--)                             // On all orders
         {
         if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==true && OrderType()==OP_SELL)
            {         
            OrderClose(OrderTicket(),OrderLots(),Ask,3,CLR_NONE);// Close Sell   
            ss=0;                                        // No Sells anymore
            }
         }
      Strateg(2);                                        // Opening function
      }
//============================================================================================
   return;

   } 
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
void Strateg (int vv)                                    // Opening function
   {
//============================================================================================
   if (vv==1 && ss==0)                                   // Sell situation and no Sells
      {
      OrderSend(Symbol(),OP_SELL,Lots(),Bid,3,Bid+SL*Point,Bid-TP*Point,"",0,0,Red);// Open
      ss=1;                                              // Now, there is a Sell
      }
//--------------------------------------------------------------------------------------------
   if (vv==2 && bb==0)                                   // Buy situation and no Buys
      {
      OrderSend(Symbol(),OP_BUY, Lots(),Ask,3,Ask-SL*Point,Ask+TP*Point,"",0,0,Blue);// Open
      bb=1;                                              // Now, there is a Buy
      }      
//--------------------------------------------------------------------------------------------
   lmax=Ask+prodvig*Point;                               // Redefine the new limiting ..
   lmin=Bid-prodvig*Point;                               // .. levels for open and close 
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
double Lots()                                            // Calculation of lots
   {
//============================================================================================
   Lot=NormalizeDouble(AccountEquity()*Prots/100/1000,1);// Calculate the amoung of lots  
   double Min_Lot = MarketInfo(Symbol(), MODE_MINLOT);   // Minimum permissible cost of lots
   if (Lot == 0 ) Lot = Min_Lot;                         // For testing on const.min.lots
//============================================================================================
   return(Lot);
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
/*

Em geral, o conteúdo do expert é bastante compreensível.

Na parte superior, antes da função start(), estão dispostas as variáveis. Na função start(), a posição atual da taxa no declive de um pico (baixa) é calculada primeiro, e então a situação a analisada para o acionamento dos critérios de transações. E, caso os critérios sejam acionados, o pedido já processado será fechado. Duas outras funções são usadas no expert: Strateg() para abrir novos pedidos e Lots() para determinar a quantidade de lotes. As variáveis ss e bb são usadas para registrar pedidos abertos.

O provador de estratégia é uma ferramenta muito importante no terminal do cliente MetaTrader 4. O nosso programador testou o expert cuidadosamente de modo a otimizar as entradas, e um dos melhores resultados foi o seguinte:




Figura 2. Um "graal" clássico. O resultado foi obtido no teste do expert chamado Graal_1.mq4 (graal 1) nos dados históricos entre março de 2005 e junho de 2006 em relação ao М1 EURUSD sob as condições de transação do servidor demonstrativo da MetaQuotes Software Corp

Nós podemos facilmente imaginar a felicidade do programador: Ele foi capaz de criar esta obra prima com as suas próprias mãos! Aqui está: Novo, elevado e brilhante em suas várias facetas perfeitas: o seu primeiro "graal"! E o nosso programador chega a uma conclusão simples: "Apenas eu!"

Não é necessário que toda estratégia formal resulte na criação de um "graal", mas é o caso no nosso exemplo. Vamos investigar com atenção o que levou o programador a obter este resultado:

1.2. Investimento avançado

O nosso programador não deixou o trabalho feito pela metade, e decidiu tentar maximizar os valores dos pedidos. Ele aumenta este valor (durante o teste) até 70% (o valor da variável externa Prots=70) dos bens líquidos, mas essa abordagem se mostrou pouco eficiente:


Figura 3. Investimentos agressivos podem resultar em perdas injustificadas


Nosso herói ficou pasmo ao se deparar com este resultado. Ele racionalizou da seguinte forma: "Se o expert é lucrativo, quanto mais você investir nele, mais você irá lucrar!". Mas os resultados do provador mostraram que frequentemente isto não é verdade.

Vamos examinar o que ocasionou tal resultado.

1.2.1. Progressão geométrica

Vamos observar a tecnologia do cálculo de valor do pedido. De acordo com o código acima, o valor do pedido cresce proporcionalmente em relação à quantidade de bens líquidos: O nosso programador está bastante irritado. Ele não compreende as razões desse tratamento injusto dos funcionários, e discorda de quaisquer explicações. Ele se pergunta: Que "limitações técnicas"? O que o "deslizamento" tem a ver com isso?! Como resultado desta primeira experiencia real com transações, o nosso programador chegou a conclusão de que este é um "centro de negócios ruim", e que o(a) trapacearam. Ele rompe o contrato com o centro de negócios.

   Lot=NormalizeDouble(AccountEquity()*Prots/100/1000,1);// Calculate the amount of lots  
   double Min_Lot = MarketInfo(Symbol(), MODE_MINLOT);   // Minimum allowed lot value
   if (Lot == 0 ) Lot = Min_Lot;                         // For testing on const.min.lots

Este algoritmo representa uma progressão geométrica. A variável Prots (porcentagem) permite a regulagem do valor do pedido dependendo da quantidade atual de bens líquidos. Essa forma de calcular os valores de pedidos não é completamente correta, pois ela não leva em consideração as chamadas de margem ao trabalhar com um fornecedor específico. Por outro lado, o fragmento de código acima permite a resolução do problema principal: o problema relativo aos investimentos proporcionais. Portanto, o valor de cada pedido subsequente será proporcionalmente dependente dos resultados obtidos: o valor irá crescer após cada transação lucrativa e diminuir após cada transação desvantajosa. O valor do pedido no código Graal_1.mq4 (graal 1) acima representa 10% dos bens líquidos.

A progressão em si não é um atributo necessário do "graal". Qualquer outro expert normal pode ser criado com o uso dessa tecnologia. Contudo, a progressão geométrica deve ser completamente excluída para que possamos investigar o "graal" mais detalhadamente, focando apenas nos resultados de testes obtidos a um valor constante de pedido mínimo (igual a 0,1 lote, se possível). Neste caso, nós podemos facilmente estimar a quantidade de pontos ganhos.

Vamos configurar o valor da variável Prots como 0 e, em acordo com o código abaixo,

   if (Lot == 0 ) Lot = Min_Lot;                         // For testing on const.min. lots

testar o expert a um valor constante de pedido.

Neste caso, o resultado será o seguinte:

Figura 4. Resultados dos testes do Expert Graal_1.mq4 (graal 1) a valores constantes de lote

A exclusão dos valores progressivos de pedido exibe a verdadeira natureza das mudanças na curva de balanço: surtos, profundos levantamentos de crédito, etc.

1.2.2. Reinvestimento agressivo

Qualquer expert lucrativo sempre irá caçar uma vantagem entre o lucro e a perda. Atualmente não existe tecnologia que permita a realização de apenas transações lucrativas. Transações desvantajosas são uma norma para qualquer estratégia de transações em funcionamento real. O que importa é a razão entre as operações lucrativas e desvantajosas.

Por exemplo, uma razão de 3:1 entre lucro e perda pode ser considerada bastante aceitável. Isso significa que 100 pedidos abertos e fechados consecutivamente devem conter 75 transações lucrativas e 25 desvantajosas. Por outro lado, nós nunca somos capazes de prever a distribuição dos pedidos desvantajosos entre os lucrativos. Essa distribuição possui uma natureza predominantemente aleatória.

А. A distribuição ideal de lucros e perdas seria uniforme ao longo de todo o histórico de transações:

L L L P L L L P L L L P L L L P L L L P L L L P L L L P ...

Contudo, não há garantias de que a distribuição será sempre tão ideal. Muito pelo contrário, é bastante provável que uma longa série de perdas sucessivas ocorra cedo ou tarde.


В.
Abaixo temos um exemplo das situações bastante prováveis nas quais há distribuição não uniforme de transações com lucro e com perda durante transações reais:

L L L L L L L L L L L L L L L PPPPP L L L P L L L P ...


Uma série de 5 perdas consecutivas é mostrada acima, mas uma série do tipo pode ser ainda mais longa. Você deve notar que, em um caso como este, a razão entre os pedidos lucrativos e desvantajosos mantém-se em 3 : 1.

No que pode resultar essa aleatoriedade regular? A resposta depende da qualidade da estratégia de transações escolhida pelo trader. É uma coisa caso o trader realize transações de forma deliberada, respeitando precauções razoáveis, segundo as quais o valor total dos seus pedidos não exceda de 10 a 15% do depósito; mas é outra, completamente diferente, caso o trader permita reinvestimentos agressivos, investindo a maior parte do seu depósito, e apenas uma vez, mas sempre que lucrar.

No caso de reinvestimentos agressivos, o histórico da conta de transações irá se desenvolver de forma imprevisível. Em um caso raro de "sorte", é possível sair ileso. Mas, em muitos casos, o resultado negativo é iminente. Para ilustrar possíveis cenários da forma de funcionamento do expert Graal_1.mq4 (graal 1), vamos analisar duas alternativas de investimentos, sendo que todas as outras condições são iguais (a mesma fase do histórico, entradas configuradas do mesmo modo).

Por favor, preste atenção ao relatório sobre os resultados do teste: A quantidade máxima de perdas consecutivas (uma série de pedidos desvantajosos) para o expert Graal_1.mq4 (graal 1) é de apenas 10. Outras séries desvantajosas ocorreram durante o período inteiro do teste, mas a quantidade de pedidos desvantajosos em cada uma delas não excedeu 10. Estas séries desvantajosas não influenciaram de modo significativo o resultado total das transações na alternativa 1, mas foram desastrosas para a alternativa 2.

Portanto, uma série curta de perdas nos investimentos errados pode resultar em um desastre completo. Há um sistema eficiente desenvolvido para o gerenciamento adequado de capital: O gerenciamento financeiro. De acordo com esse sistema, o valor de um pedido não deve exceder 15% do balanço total, e a quantidade total de investimentos não deve exceder 50% dele. Esse sistema oferece algumas outras regras úteis, que foram lidas pelo nosso programador.

Ele chegou a uma conclusão: realizar transações com o uso de reinvestimentos agressivos é um auto-engano , e resulta em ruína cedo ou tarde. Cada trader deve decidir de modo independente onde colocar o limite. Os resultados ocorrerão de acordo com isso.

Tendo aperfeiçoado o seu "graal", assegurando-se de que tudo está funcionando direito, o nosso programador abre uma conta real e parte para "fazer dinheiro". Após alguns pedidos terem sido abertos e fechados com sucesso, ele percebe que o balanço não está em crescimento, mas em constante queda. Além disso, os funcionários do centro de negócios desabilitam o expert do nosso programador ao fim do dia.


Contudo, o nosso programador não desiste, decide examinar o processo em detalhes, e entra em contato com colegas mais experientes no fórum especializado no MQL4, onde lhe pedem para mostrar o código. Apesar do ressentimento que sente em relação ao código, ele finalmente concorda, pois de todo modo o expert não parece ser lucrativo... O nosso programador entende o seguinte após o assunto ter sido discutido no fórum.


1.3. Erros

O meta editor confirmou constantemente que não havia erros,
Figura 5. Nenhum erro ao compilar

mas, ainda assim, havia.

1.3.1. Digressão da estratégia formal


Ainda que uma estratégia bastante consciente tenha sido usada como base para a criação do expert, ela foi alterada durante a codificação e otimização das variáveis genéricas. Portanto a ideia inicial agora está presente no "graal" em miniatura. De fato, a ideia era lucrar em ondas de 15 a 20 pontos de comprimento, mas este parâmetro se dá com o minúsculo valor de 3 na versão atual do "graal". Não chegam a ser altos e baixos...

Não há linha definida entre o branco e o preto. Todos os estágios intermediários podem ser caracterizados pelo coeficiente da sua brancura ou pretidão. Mas geralmente se pode distinguir se uma cor é mais preta do que branca, e vice-versa. No nosso caso, a ideia inicial "puramente branca" foi tão "enegrecida" que se tornou tão escura quanto o carvão, e perdeu toda a sua força. Nós podemos considerar este o motivo dos resultados obtidos pelo "graal".
1.3.2. Programação incorreta

Observe a forma com que os pedidos são considerados nas variáveis ss e bb. Esta é a forma errada de se considerar pedidos. O pedido é considerado como se já estivesse aberto ao ser formado. Mas não é possível saber de antemão se o pedido será ou não aberto. Para se assegurar deste fato, é preciso esperar até que o servidor responda, e então analisar a disponibilidade do pedido no terminal. Para se adequar a transações reais, esta parte do código deveria ser reescrita, ainda que a modificação apresentada funcione na maioria dos casos, incluindo no provador de estratégia (ver o artigo Consideração de pedidos em um programa amplo).

1.4. Restrições de hardware


O expert foi testado no cronograma para o qual foi projetado: em M1. É preciso ter muita atenção ao modelar a realização de transações do expert no cronograma M1, especialmente em relação a experts sensíveis a preços.

Caso nós queiramos precisar o histórico de uma barra em um cronograma mais amplo, nós podemos usar o histórico de barras de um cronograma menor. Mas em relação ao M1, não há cronogramas menores, pois o histórico de ticks não é armazenado ou usado no terminal do cliente MetaTrader 4 (ver Provador de estratégia: Modos de modelagem durante testes).

A principal diferença entre um modelo de teste e uma estratégia de transações real consiste no fato de que o modo de teste não apresenta deslizamento e novas cotações (quando o fornecedor dá um preço novo, diferente daquele apresentado no pedido do trader).

Centros de transações diferentes trabalham com fluxos de dados diferentes (a serem considerados mais tarde). Quanto mais frequentes forem as mudanças na taxa, o mais provável é que o fornecedor proponha ao trader executar o pedido a um preço diferente. Por outro lado, quanto mais "suave" o tráfego parecer, menos provável é o surgimento de novas cotações. Mas neste caso também há menos espaço para experts que realizem transações com frequência e com lucros pequenos.

O nosso programador testou o Graal_1 (graal 1) no histórico de 1 minuto de outro centro de negócios (com a mesma margem) e viu com seus próprios olhos que o resultado depende muito do tipo de tráfego.


Figura 6. Resultados de testes do Graal_1.mq4 (graal 1) no histórico M1 de EURUSD entre 4 de abril e 26 de julho de 2006 nos termos de transações comerciais do servidor demonstrativo do FX Integralbank a custos constantes de pedidos

A presença de profundos levantamentos de crédito e desenvolvimento de lucro instável mostra que o expert está à beira do prejuízo.

Como regra, os preços de novas cotações diferem em 1 a 2 pontos (mas a quantidade de pontos pode ser maior em um mercado veloz). Esse fenômeno não será capaz influenciar fundamentalmente o sucesso do expert caso o seu lucro esperado for muito maior. Por exemplo, de 10 - 15. Mas não se pode esperar seriamente que um expert que tenha um lucro esperado pequeno, especialmente caso este seja inferior a 2, obtenha sucesso geral, pois ele depende demais da natureza da cota e das novas cotações relacionadas.

A possibilidade de um fornecedor específico realizar ou não novas cotações no tick atual é uma questão separada, que só pode ser respondida pelo próprio fornecedor. Mas, ao iniciar os trabalhos no mercado real, é preciso assumir que a realização de novas cotações é um fenômeno normal e natural, e uma tecnologia de transações que trabalhe em uma conta real deve levar isso em consideração.



1.5. Aspectos econômicos

Uma situação na qual a atenção do trader está completamente focada na sua conta de transações e nos eventos relativos a ela, incluindo estratégias de transações, experts, etc., é comumente encontrada. Contudo, além das preocupações do trader, há as preocupações econômicas do fornecedor.

Em transações "normais", ambas as partes podem ganhar: o trader que utiliza uma estratégia bem pensada e o fornecedor que recebe juros das transações realizadas pelo trader. Neste caso, as partes estão preocupadas uma com a outra, e prontas para apoiar uma a outra.

Contudo, podem ocorrer situações nas quais as atividades de uma parte se opõem aos interesses da outra parte. Por exemplo, se o fornecedor aumentar a margem, desabilitar a realização automática de transações, ou não abrir (fechar) pedidos unilateralmente no momento em que o preço é atingido, ele estará se opondo aos interesses do trader.

Ao mesmo tempo, algumas possíveis atividades do trader podem ir de encontro aos interesses econômicos do fornecedor. Uma dessas atividades é a realização frequente de operações de negociação com o uso de pequenas quantidades de dinheiro.

No todo, a tecnologia de trabalho do fornecedor é bastante simples. O fornecedor recolhe os pedidos de compra e venda do trader e cria relações com um banco ou outra instituição financeira para processar as diferenças em seus preços. Vamos examinar um exemplo simples. Vamos supor que um fornecedor serve um total de 100 traders, sendo que 60 deles compraram por 1 lote de EURUSD, e 40 venderam por 1 lote do mesmo par cambial. Neste caso, o fornecedor deve comprar 20 lotes (a diferença entre 60 e 40) do banco. Além disso, a direção para a qual o preço irá se mover não faz diferença para o fornecedor. Em todo caso, o fornecedor irá receber a totalidade de 80 lotes (40+40) e uma entrega parcial de 20 lotes (uma parte será dada ao banco em troca dos seus serviços).

Neste caso, a fonte do lucro/prejuízo de 40 trader é o prejuízo/lucro de outros 40 traders. A fonte do lucro/prejuízo dos 20 traders restantes é o banco ou, para ser mais preciso, pessoas jurídicas trabalhando com o banco e vendendo/comprando moedas para as suas operações de exportação-importação. Essa é uma forma normal de inter-relação entre os participantes do mercado financeiro.

Mas há mais um detalhe a respeito da forma com que o fornecedor se inter-relaciona com o banco ou a instituição financeira. A questão é que o fornecedor não se interrelaciona com o banco em todas as operações de venda ou compra caso o trader venda ou compre uma quantia insignificante de dinheiro. Operações de negociação entre o fornecedor e o banco são realizadas com uma frequência um pouco menor do que os cliques dos traders no terminal MT4. Normalmente, a quantia mínima nas relações entre o fornecedor e o banco não excede os US$50.000, o que, traduzido ao preço de pedido com uma alavancagem de 1:100, resulta em 0,5 lote. É por isso que, caso o trader sempre trabalhe com quantias pequenas de dinheiro, ele sempre irá, na prática, fazer transações com o fornecedor. Neste caso, a fonte do lucro do trader é o dinheiro do fornecedor!

O fornecedor participa tanto do mercado financeiro quanto qualquer outro. O fornecedor deve observar e analisar o trabalho de todos os traders. É claro que fornecedores, no escopo de suas preocupações financeiras, podem fazer vista grossa a investimentos repetidos irregulares caso eles resultem em prejuízos evidentes ao trader ou o seu resultado total seja neutro por um determinado período de tempo (o resultado diário, por exemplo). Mas nenhum fornecedor razoável permitirá que interrelações continuem caso elas resultem em perdas para ele. Neste caso, o fornecedor precisa reagir de alguma forma, do contrário ele não deveria estar no território econômico do mercado financeiro.

Note, por favor, que a rotina moderna no mercado financeiro não se dá em função das animosidades ou caprichos de um fornecedor. As relações do fornecedor com o banco também são contratuais. E o fornecedor se esforça para ganhar a margem de forma justa (abusos da parte do fornecedor não são discutidos no presente artigo). O fornecedor provavelmente ficaria feliz em realizar transações com o banco o tempo todo, mas tal possibilidade não existe no momento.

Quando operações de negociação pequenas e frequentes são realizadas por um trader, o fornecedor precisa tomar alguma medida. Ela pode vir sob a forma de uma notificação enviada ou comunicada ao trader, dizendo que aquele seu trabalho específico está à beira do prejuízo. O fornecedor pode também desabilitar a realização automática de transações para este trader, ou aumentar a quantidade de operações com novas cotações.

Há mais uma limitação que diferencia transações reais de testes ou transações em uma conta demonstrativa. Trata-se do valor máximo do preço do lote. Nenhum centro de negócios, seja um banco, um agiota ou uma instituição financeira, pode operar de maneira prática com quantidades muito grandes de dinheiro.

Se pedidos custarem cerca de US$10.000 a 20.000 (note, por favor, que há uma alavancagem, geralmente igual a 100), o centro de negócios irá vender/comprar por até US$1.000.000. Essa é uma quantia bastante grande, mas os fornecedores aprenderam a lidar com esse tipo de volume de dinheiro de forma bem sucedida.

Algumas dificuldades podem ocorrer em uma instituição financeira média, caso o preço do pedido chegar a US$50.000 ou mesmo US$100.000. Neste caso, a quantia de 5 a 10 milhões de dólares americanos figura no mercado interbancário. Não é fácil vender/comprar essa quantia de dinheiro em um único movimento.

Podem ocorrer problemas caso o preço de pedido exceder a quantia de US$ 300.000 a 500.000. Neste caso, o centro de negócios certamente irá trabalhar com o trader individualmente. Bem, 50 milhões de dólares é uma quantia bastante grande para qualquer instituição.

No caso de preços de pedido enormes, as garantias firmes do centro de negócios estão fora de questão, e a própria realização de transações tem como base o fato de que o trader entende e aceita isso. (De fato, que fornecedor pode tomar a liberdade de abrir um pedido que custa uma enorme quantia de dinheiro imediatamente sob condições de movimentos de mercado imprevisíveis e fortes?)

Por esta razão, experts de scalping realizando transações envolvendo milhões são evidência de um grande erro por parte do trader e não tem nada a ver com o mundo real.

Esse raciocínio sugeriu ao nosso programador ganhar as cem mil "pratas" iniciais aqui e então procurar um "escritório pior". O programador ficou quieto, pensando que "está tudo sob controle".

Não vamos nos esquecer de que fornecedores são pessoas normais, com seus níveis culturais e de instrução, com negócios sendo geridos de uma ou outra forma. A mesma tecnologia, não lucrativa para fornecedores, pode ser imediatamente detectada quando analistas trabalham com eficiência, e não pode ser facilmente detectada por fornecedores que fazem o seu trabalho pela metade, não possuem experiência o bastante, ou não tem o software necessário. Mas, na maioria dos casos, fornecedores já buscaram o seu "graal" no passado, possuem experiência no mercado e geralmente compreendem muito bem todas as nuances das transações nos mercados financeiros. Então eles sabem o que é progressão geométrica, preocupação financeira, reinvestimento agressivo, e preços de pedidos baixos e altos. Em geral, todo trader precisa enfrentar a afirmação de que as qualificações dos fornecedores são maiores do que as suas, e que qualquer posição ou posição pragmática do fornecedor é fundamentada.

Vocês mesmos podem julgar: Quais (sob as condições econômicas e técnicas acima) podem ser os resultados do trabalho de um expert que abre mais de 20.000 pedidos por ano?



Figura 7. Relatório de testes do expert chamado Graal_1 (graal 1)


O cérebro do nosso programador flutua entre todos esses ticks, barras, pontos, margens, fornecedores e bancos. Ele decide não examinar os detalhes ou "questões únicas". Basta a sua compreensão de que "os resultados dos testes não coincidem com a realização de transações real". E ele decide que uma tecnologia adequada será desenvolvida com base em pedidos pendentes. "Bom, eles não vão conseguir me pegar aqui!", ele pensa.

2. O segundo "graal"

2.1 Estratégia

A ideia de construir o expert com base em pedidos pendentes chega à mente do nosso programador após ele ter estudado o comportamento das taxas cruzadas EURGBP e EURCHF em gráficos de 1 minuto.



Figura 8. Regiões históricas de taxas cruzadas com desvios significativos de preço (picos)

Como é possível notar facilmente, à noite, quando a sessão européia já terminou e a asiática ainda não começou, alguns gráficos de símbolos contêm barras com preços inesperados que são absolutamente diferentes de fluxos de preços "normais". A partir da lógica formal, basta colocar pedidos pendentes do tipo "limite" um pouco acima e um pouco abaixo do fluxo principal, e uma parte deles irá ser aberta, com uma probabilidade alta de sucesso. Para que pedidos pendentes reajam de forma adequada a mudanças no fluxo principal, eles devem ser "arrastados" ao longo de uma determinada linha média e apoiados constantemente a uma dada distância da linha MA (média móvel). O nosso programador escreveu um expert para realizar essa ideia:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Graal_2.mq4 (Grail 2).
// Used as an example in the article My First "Grail".
// Sergey Kovalyov, Dnepropetrovsk (Ukraine),sk@mail.dnepr.net,ICQ 64015987, http://autograf.dp.ua/
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
extern int TakeProfit=5;                            // TakeProfit orders
extern int StopLoss= 29;                            // StopLoss orders
extern int Distan   = 2;                            // Distance from the МА line
extern int Cls      = 2;                            // Close at ** points of profit
extern int period_MA=16;                            // MA period 
//extern int Time_1   = 0;                          // Starting time 
//extern int Time_2   = 0;                          // Finishing time
extern int Prots    = 0;                            // Percentage of free assets
 
//--------------------------------------------------------------------------------------------
int
   Nom_bl,                                          // BuyLimit order number
   Nom_sl,                                          // SellLimit
   total,                                           // Count of lots
   bl = 0,                                          // 1 = BuyLimit order availability
   sl = 0,                                          // 1 = SellLimit order availability
   b  = 0,                                          // 1 = Buy order availability
   s  = 0;                                          // 1 = Sell order availability
//--------------------------------------------------------------------------------------------
double 
   OP,                                              // OpenPrice (absolute points)
   SL,                                              // StopLoss orders (relative points)
   TP,                                              // TakeProfit orders (relative points)
   dist,                                            // Distance from МА (relative points)
   Level,                                           // Min.allowed distance of a pending order
   OP_bl,                                           // OpenPrice BuyLimit (absolute points)
   OP_sl,                                           // OpenPrice SellLimit(absolute points)
   cls,                                             // Close at ** profit (absolute points)
   MA,                                              // MA value (rate)
   spred,                                           // Spread (absolute points)
   Lot;                                             // Count of lots
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int init()
   {   
   Level=MarketInfo(Symbol(),MODE_STOPLEVEL);       // Check what the server shows us
   Level=(Level+1)*Point;                           // ?:)
   SL=StopLoss*Point;                               // StopLoss orders (relative points)
   TP=TakeProfit*Point;                             // TakeProfit orders (relative points)
   dist=Distan*Point;                               // Distance from the MA line(relative points)
   cls=Cls*Point;                                   // Close at ** profit (absolute points)
   spred=Ask-Bid;                                   // Spread (absolute points)
   return;
   } 
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int start()
   {   
//============================================================================================
   total=OrdersTotal();                             // Count of lots
   bl=0;                                            // Zeroize at the start of the pass
   sl=0;                                            // Zeroize at the start of the pass
   b=0;                                             // Zeroize at the start of the pass
   s=0;                                             // Zeroize at the start of the pass
//--------------------------------------------------------------------------------------------
   for (int i=total; i>=0; i--)                     // For all orders
      {                                             
      if (OrderSelect(i,SELECT_BY_POS)==true &&     // Select an order
         OrderSymbol()==Symbol())
         {
      
//--------------------------------------------------------------------------------------------
         if (OrderType()==OP_BUY)                   // Buy order
            {
            b =1;                                   // The order found
            Close_B(OrderTicket(),OrderLots());     // Close the order (the function decides
                                                    // whether it is necessary)
            }
//--------------------------------------------------------------------------------------------
         if (OrderType()==OP_SELL)                   // Sell order
            {
            s =1;                                   // The order found
            Close_S(OrderTicket(),OrderLots());     // Close the order (if necessary)
            }
//--------------------------------------------------------------------------------------------
         if (OrderType()==OP_BUYLIMIT)              // BuyLimit order
            {
            OP_bl=NormalizeDouble(OrderOpenPrice(),Digits);//OpenPrice BuyLimit(absolute points)
            Nom_bl=OrderTicket();
            bl=1;                                   // The order found
            }
//--------------------------------------------------------------------------------------------
         if (OrderType()==OP_SELLLIMIT)             // SellLimit order
            {
            OP_sl=NormalizeDouble(OrderOpenPrice(),Digits);//OpenPrice SellLimit(absolute points)
            Nom_sl=OrderTicket();
            sl=1;                                   // The order found
            }
//--------------------------------------------------------------------------------------------
         }
      }   
//--------------------------------------------------------------------------------------------
   MA = iMA(NULL,0, period_MA, 0,MODE_LWMA, PRICE_TYPICAL, 0);// The MA current value
   Modify_order();                                  // Activate modification
   Open_order() ;                                   // Activate opening
//============================================================================================
   return;
   } 
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
void Close_B(int Nomber, double lots)               // Close Buy orders
   {
//============================================================================================
   if (NormalizeDouble(Bid-OrderOpenPrice(),Digits)>=cls)// If the preset profit is reached
      {
      OrderClose( Nomber, lots, Bid, 1, Yellow);    // Close
      b = 0;                                        // No Buy order anymore
      }
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
void Close_S(int Nomber, double lots)               // Close Sell orders
   {
//============================================================================================
   if (NormalizeDouble(OrderOpenPrice()-Ask,Digits)>=cls)// If the preset order is reached
      {
      OrderClose( Nomber, lots, Ask, 1, Yellow);    // Close
      s = 0;                                        // No Sell order anymore
      }
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
void Modify_order()                                 // Modification of orders
   {
//============================================================================================
   if (bl==1)                                       // If there is BuyLimit
      {
      OP=MA-dist;                                   // it must be located here
      if (MathAbs(OP_bl-OP)>0.5*Point)              // if it is not located here
         {
         OrderModify(Nom_bl,OP,OP-SL,OP+TP,0,DeepSkyBlue);// The order modification 
         }
      }
//--------------------------------------------------------------------------------------------
   if (sl==1)                                       // If there is SeelLimit
      {
      OP=MA+spred+dist;                             // It must be located here
      if (MathAbs(OP_sl-OP)>0.5*Point)              // If it is not located here
         {
         OrderModify( Nom_sl, OP, OP+SL, OP-TP, 0, Pink);// The order modification 
         }
      }
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
void Open_order()                                   // An opening function
   {
//   int Tek_Time=TimeHour(CurTime());              // To test by the time
//   if (Tek_Time>Time_2 && Tek_Time>
//============================================================================================
   if (b==0 && bl==0)                               // No Buy orders, open bl
      {
      OP=MA-dist;                                   // bl order open rate      
      if(OP>Ask-Level) OP=Ask-Level;                // OP precision according to the tolerance
      OP=NormalizeDouble(OP,Digits);                // Normalizing (MA gives the 5th digit) 
      OrderSend(Symbol(),OP_BUYLIMIT, Lots(),OP,3,OP-SL,OP+TP,"",0,0,Blue);// Open
      bl=1;                                         // Now there is a Buy order b1
      }      
//--------------------------------------------------------------------------------------------
   if (s==0 && sl==0)                               // No Sell orders, open sl
      {
      OP=MA+spred+dist;                             // sl order open rate    
      if(OP<Bid+Level) OP=Bid+Level;                // OP precision according to the tolerance
      OP=NormalizeDouble(OP,Digits);                // Normalizing (MA gives the 5th digit) 
      OrderSend(Symbol(),OP_SELLLIMIT,Lots(),OP,3,OP+SL,OP-TP,"",0,0,Red);// Open
      sl=1;                                         // Now there is a Sell order sl
      }
///============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
double Lots()                                       // Calculation of lots
   {
//============================================================================================
   Lot=NormalizeDouble(AccountEquity()*Prots/100/1000,1);// Calculate the amount of lots  
   double Min_Lot = MarketInfo(Symbol(), MODE_MINLOT);   // Minimum lot values
   if (Lot == 0 ) Lot = Min_Lot;                         // For testing on const.min.lots
//============================================================================================
   return(Lot);
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
/*

StopLoss, TakeProfit, Distan (a distância na qual o pedido acompanha o fluxo principal), Cls (a quantidade mínima de pontos ganhos no pedido; o pedido deve ser fechado quando a quantidade de pontos alcançar este valor), period_MA (o período MA; o MA aqui é a linha média de taxas do histórico mais recente), e Prots (a porcentagem de ativos disponíveis) foram escolhidos como variáveis ajustáveis. É mais do que o suficiente para realizar a ideia.
Ao escrever o programa, o nosso personagem notou que ele poderia ser aperfeiçoado infinitamente, e entendeu que a escrita do programa não pode ser completada, mas que é preciso simplesmente pará-la! Os testes do expert em relação ao EURCHF resultaram no seguinte (nós estudaremos este exemplo, mas resultados semelhantes podem ser obtidos em relação ao EURGBP).


Figura 9. Resultados de testes do Graal_2.mq4 (graal 2) no histórico de março de 2005 a junho de 2006, no gráfico М1 EURUSD sob as condições de transação da companhia MIG Investments


2.2. Progressão geométrica

Neste expert, assim como no anterior, a tecnologia de investimento progressivo é usada. Com relação aos preços constantes de pedidos, o diagrama de balanço terá a seguinte aparência:


Figura 10.
Resultados de testes do Graal_2.mq4 (graal 2) no histórico de março de 2005 a junho de 2006, no gráfico М1 EURUSD sob as condições de transação da companhia MIG Investments a preços constantes de pedidos

Originalmente, o nosso programador planejava ganhar dinheiro apenas durante a noite, mas então ele foi surpreendido pelo fato do expert trabalhar de forma bem sucedida durante todo o dia de comércio. Precisamos dizer que depois disso ele repetiu: "Apenas eu!" e partiu para "fazer dinheiro" novamente? Mas nada do tipo acabou acontecendo... Desta vez, o programador precisa se familiarizar com "picos".

2.3. Erros

No exemplo de expert acima, há uma grande quantidade de defeitos e de soluções de programação incorretas. No Modify_order(), a distância mínima permitida para pedidos pendentes não é levada em consideração, a consideração dos pedidos abertos é organizada incorretamente, o TakeProfit não é modificado separadamente para "enfatizar" o lucro para o Cls, a parte analítica do expert está "espalhada" por todo o código, etc.

A programação incorreta e, mais do que isso, pouco cuidadosa, frequentemente resulta em erros indistintos e, às vezes, na replicação do erro, caso o código seja integrado a outros experts.

2.4. Restrições técnicas (picos)

Todas as restrições, técnicas ou organizacionais, se transformarão, no fim, em perdas econômicas, como regra. Surge a questão: à custa de quem essas perdas serão cobertas?

Um gráfico de candle normal, que é visto pelo trader no seu monitor, é um resultado médio do desenvolvimento do mescado em um território específico (entre bancos europeus, por exemplo). O comportamento da taxa durante um curto período do histórico com diferentes fornecedores pode ser analisado. Além disso, como se pode ver facilmente, todos esses gráficos serão diferentes uns dos outros, mesmo que sutilmente. Alguns gráficos de fornecedores irão conter várias candles longas multidirecionais, enquanto outros gráficos de fornecedores exibirão "calma e sossego".

Um gráfico de ticks também é um objeto de venda. Ele é o resultado do trabalho de algum programa de processamento que filtra ticks de preço excessivos e não-naturais. E eles (os ticks "não-naturais") surgem. Isso acontece quando uma pessoa em um banco, por algum motivo pessoal (tudo pode acontecer, certo?), realiza uma compra ou venda de uma certa quantia a um preço muito diferente do preço do mercado. O programa de processamento aceita esta informação e, caso uma transação do tipo só tenha ocorrido uma vez, não a considera na formação do gráfico final. Em alguns casos, o programa encontra dificuldades em entender qual preço é "normal" e qual não é. Por este motivo, candles simples de comprimentos diferentes (dependendo do algoritmo do programa de processamento) aparecem às vezes no gráfico. Esses são os picos. Há diferentes tipos deles, mas eles não mostram a situação real do mercado financeiro.

Não é muito difícil criar um expert capaz de detectar esses "pinos", "espinhas" e "picos", e abrir pedidos quando o preço é mais lucrativo. Mas é preciso compreender que, sob os contratos fechados entre o fornecedor e o banco, o banco geralmente não paga este tipo de transação ao fornecedor. Isso significa que a fonte de lucro do trader é, novamente, o bolso do fornecedor! E o fornecedor não quer que isso aconteça, é claro, então ele se esforça para fazer com que os traders realizem operações comerciais a preços de mercado "normais".

Em relação a medidas que criem essa oportunidade ao fornecedor, o contrato entre ele e o trader geralmente contém clausulas a respeito dos direitos do fornecedor, incluindo a possibilidade de mudanças na cotação, a abertura não garantida de pedidos quando há movimentos fortes nos preços, a abertura de pedidos pendentes no segundo toque, e outras precauções. Em alguns casos, o fornecedor pode cancelar um pedido já aberto caso, na sua opinião, ele tiver sido aberto durante um pico.

É isso o que ocorreu com o nosso personagem. Por melhor que fosse na conta demonstrativa, o graal foi novamente corrigido pela vida real. Desta vez, o nosso programador não bate o telefone, e dá ouvidos aos fornecedores, prestando bastante atenção a cada explicação dos motivos pelos quais pedidos foram fechados forçosamente. Mas quando o fornecedor desabilitou os experts, o programador não aguentou e novamente rompeu o seu contrato.

Agora o nosso personagem imagina que os cronogramas de um minuto são os culpados pelos seus vários fracassos. Após ler postagens em fóruns e se comunicar com outros traders, o programador nota que a maioria deles trabalha em cronogramas maiores com os mesmos símbolos. "Isso deve fazer sentido", ele pensa. Gradualmente o programador chega à conclusão de "Mozart e eu" e parte para desenvolver a sua terceira criação ("nunca, nunca mais!").

3. O terceiro "graal"

3.1 Estratégia formal

Após estudar cuidadosamente o gráfico H1 EURUSD e usar vários indicadores para analisá-lo, o nosso programador descobriu uma regularidade bastante atraente: Caso a MA (média móvel) de um período menor se encontre com a MA de um período maior, o mercado geralmente se move na direção à qual o MA do período menor se move.

Figura 11. Representação gráfica da estratégia baseada no entrecruzamento de MAs com períodos diferentes

O nosso programador também notou que essa correlação surge em todos os cronogramas, mas decidiu trabalhar apenas com os maiores. Para ele, resta apenas traduzir o conhecimento extraído ao MQL4, para informar ao expert em qual direção e sob quais condições este deve abrir pedidos. E, quando o expert estiver pronto, será necessário otimizar os seus parâmetros, de modo a encontrar os comprimentos de MA mais eficientes e colocar o StopLoss e o TakeProfit de modo correto.

Desta vez, o seguinte expert foi criado:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Graal_3.mq4 (Grail 3).
// Used as an example in the article My First "Grail".
// Sergey Kovalyov, Dnepropetrovsk (Ukraine),sk@mail.dnepr.net,ICQ 64015987, http://autograf.dp.ua/
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//
//
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
extern int    MA1 = 11;                                  // Period of the first MA
extern int    MA2 = 23;                                  // Period of the second MA
extern double TP =  50;                                  // TakeProfit orders
extern double SL =  15;                                  // StopLoss orders
extern double Prots= 0;                                  // Percentage of free assets
//--------------------------------------------------------------------------------------------
int
   ret,                                                  // Direction of intersection
   total;                                                // Count of open orders
//--------------------------------------------------------------------------------------------
double 
   Lot,                                                  // Count of lots
   Pred,                                                 // Preceding value of the 1st MA(red)
   Tek,                                                  // Current value of the 1st MA (red)
   Golub;                                                // Current value of the 2nd MA (blue)
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int init()  
   {
//============================================================================================
   SL = SL*Point;                                        // StopLoss in points
   TP = TP*Point;                                        // TakeProfit in points
   return;
//============================================================================================
   }  
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int start()  
   {
//============================================================================================
   total=OrdersTotal();                                  // Total amount of orders
   if (total==2)return;                                  // Both orders are already open
//--------------------------------------------------------------------------------------------
   Tek  =iMA(NULL,0, MA1, 0,MODE_LWMA, PRICE_TYPICAL, 0);// Current value of the 1st MA
   Pred =iMA(NULL,0, MA1, 0,MODE_LWMA, PRICE_TYPICAL, 1);// Preceding value of the 2nd MA
   Golub=iMA(NULL,0, MA2, 0,MODE_LWMA, PRICE_TYPICAL, 0);// Current value of the 2nd MA
//--------------------------------------------------------------------------------------------
   if (Peresechenie()==1) Open_Buy();                    // Movement bottom-up = open Buy
   if (Peresechenie()==2) Open_Sell();                   // Movement top-down  = open Sell
//============================================================================================
   return;
   }  
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Peresechenie()                                       // Function determining intersection
   {
//============================================================================================
   if ((Pred<=Golub && Tek> Golub) ||
       (Pred< Golub && Tek>=Golub)  ) ret=1;             // Intersection bottom-up       
//--------------------------------------------------------------------------------------------
   if ((Pred>=Golub && Tek< Golub) ||
       (Pred> Golub && Tek<=Golub)  ) ret=2;             // Intersection top-down
//============================================================================================
   return(ret);                                          // Return the intersection direction
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Open_Buy()                                           // Function opening Buy
   {
//============================================================================================
   if (total==1)                                         // If there is only one order...
      {                                                  // ... it means another can be opened
      OrderSelect(0, SELECT_BY_POS);                     // Select the order
      if (OrderType()==0)return;                         // If it is Buy, do not open
      }
   OrderSend(Symbol(),0, Lots(), Ask, 0, Ask-SL, Ask+TP, "", 0, 0, Blue);// open
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Open_Sell()                                          // Function opening Sell
   {
//============================================================================================
   if (total==1)                                         // If there is only one order...
      {                                                  // ... it means another can be opened
      OrderSelect(0, SELECT_BY_POS);                     // Select the order
      if (OrderType()==1)return;                         // If it is Sell, do not open
      }
   OrderSend(Symbol(),1, Lots(), Bid, 0, Bid+SL, Bid-TP, "", 0, 0, Red);// Open
//============================================================================================
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
double Lots()                                            // Calculation of lots
   {
//============================================================================================
   Lot=NormalizeDouble(AccountEquity()*Prots/100/1000,1);// Calculate the amount of lots  
   double Min_Lot = MarketInfo(Symbol(), MODE_MINLOT);   // Minimum lot values
   if (Lot == 0 ) Lot = Min_Lot;                         // For testing on const. min. lots
//============================================================================================
   return(Lot);
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
/*

Este expert, como todos os seus predecessores, é bastante simples.

O expert começa com um bloco que descreve variáveis. Na função start(), é definida a quantidade total de pedidos, assim como os valores de MA dos períodos maior e menor Caso os MAs se encontrem, a função correspondente é chamada, e esta irá abrir pedidos: Open_*(). Para a afirmação de que os MAs se encontraram, a função Peresechenie() é usada. Para descobrir os valores do lote, a função Lots() é usada.

O nosso programador examina o seu expert novamente, não encontra nenhum defeito ("simples, mas eficiente!") e começa os testes. Após a otimização das variáveis, o resultado foi extraordinário:

Figura 12. Resultados de testes do Graal_3.mq4 (graal 3) no histórico de março de 2005 a julho de 2005,
no gráfico H1 EURUSD sob as condições de transação do servidor demonstrativo da
MetaQuotes Software Corp

Três milhões em cinco meses! Maravilha! Mas alguma coisa neste diagrama de balanço lembra o nosso personagem da sua amarga experiência anterior. E o programador decide ir com mais calma.

3.2. Progressão

Após o mesmo expert ser testado a preços constantes de pedido, ele exibiu um diagrama de balanço bastante aceitável.



Figura 13. Resultados de testes do Graal_3.mq4 (graal 3) no histórico de março de 2005 a julho de 2005no gráfico H1 EURUSD
sob as condições de transação do servidor demonstrativo da
MetaQuotes Software Corp a preços constantes de lotes

Seis mil pontos em cinco meses. É possível sentir a eletricidade no ar. Mais de mil pontos por mês! Mas o nosso personagem fica em dúvida em relação a usar o expert em transações reais. Afinal, ele já esteve errado duas vezes...

Portanto o programador decide examinar mais atentamente o cronograma com marcadores de abertura e fechamento de pedidos. Para a sua surpresa ele descobre que o expert abre pedidos não apenas nas intersecções de MAs, mas também em outros pontos, sem qualquer motivo!

Figura 14. Abertura de pedidos pelo expert chamado Graal_3.mq4 (graal 3) em situações não previstas na estratégia inicial

3.3. Erros

"Que estranho! Deve haver algo de errado com o MetaEditor!" foi o que lhe ocorreu. Mas então, após estudar gradualmente e repetidamente o código, o programador volta a encontrar erros. Vamos entendê-los também.

3.3.1 Desvios da estratégia inicial - Erros algorítmicos

Veja a função simples abaixo:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Peresechenie()                                       // Function that detects the intersection
   {
//=================================================================================================
   if ((Pred<=Golub && Tek> Golub) ||
       (Pred< Golub && Tek>=Golub)  ) ret=1;             // Bottom-up intersection       
//-------------------------------------------------------------------------------------------------
   if ((Pred>=Golub && Tek< Golub) ||
       (Pred> Golub && Tek<=Golub)  ) ret=2;             // Top-down intersection
//=================================================================================================
   return(ret);                                          // Return the intersection direction
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

Tudo parece estar bastante claro, o que poderíamos estar procurando ali? Mas ainda há um erro ali. Ele consiste no fato de que, quando a variável global ret é utilizada, o seu valor é armazenado como igual ao último calculado, ou seja, 1 ou 2. Por este motivo, a função Peresechenie(), independentemente da situação atual, simplesmente devolve o último valor calculado. É por isso que se ordena constantemente que ela abra na função start().

   if (Peresechenie()==1) Open_Buy();                    // Bottom-up movement = open Buy
   if (Peresechenie()==2) Open_Sell();                   // Top-down movement  = open Sell

Para fazer mudanças, basta "zeroizar" a variável ret no início da função Peresechenie(). Tendo encontrado o erro algorítmico, o nosso personagem o corrige e simultaneamente escreve um fragmento que permite a abertura apenas em uma barra. Agora, o expert está assim:
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Graal_31.mq4 (Grail 31)
// Used as an example in the article My First "Grail"
// Sergey Kovalyov, Dnepropetrovsk, sk@mail.dnepr.net, ICQ 64015987, http://autograf.dp.ua/.
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
//
//
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
extern int    MA1 = 11;                                  // Period of the 1st MA
extern int    MA2 = 23;                                  // Period of the 2nd MA
extern double TP =  50;                                  // TakeProfit orders
extern double SL =  15;                                  // StopLoss orders
extern double Prots= 0;                                  // Percentage of free assets
//--------------------------------------------------------------------------------------------
int
   New_Bar,                                              // 0/1 The fact of new bar forming
   Time_0,                                               // The new bar beginning time
   ret,                                                  // Intersection direction
   total;                                                // Count of open orders
//--------------------------------------------------------------------------------------------
double 
   Lot,                                                  // Count of lots
   Pred,                                                 // Previous value of the 1st MA (red)
   Tek,                                                  // Current value of the 1st MA (red)
   Golub;                                                // Current value of the 2nd MA (blue)
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int init()  
   {
//============================================================================================
   SL = SL*Point;                                        // SL in points
   TP = TP*Point;                                        // ТР in points
   return;
//============================================================================================
   }  
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int start()  
   {
//============================================================================================
   total=OrdersTotal();                                  // Total count of orders
   if (total==2)return;                                  // Both orders already opened
 
//----------------------------------------------------------------------------- New bar ------
   New_Bar=0;                                            // First zeroize
   if (Time_0 != Time[0])                                // If the bar beginning time changed
      {
      New_Bar= 1;                                        // Here we have a new bar
      Time_0 = Time[0];                                  // Remember the new bar beginning time
      } 
      
//--------------------------------------------------------------------------------------------
   Tek  =iMA(NULL,0, MA1, 0,MODE_LWMA, PRICE_TYPICAL, 0);// Current value of the 1st MA
   Pred =iMA(NULL,0, MA1, 0,MODE_LWMA, PRICE_TYPICAL, 1);// Previous value of the 2nd MA
   Golub=iMA(NULL,0, MA2, 0,MODE_LWMA, PRICE_TYPICAL, 0);// Current value of the 2nd MA
   
//--------------------------------------------------------------------------------------------
   if (Peresechenie()==1 && New_Bar==1) Open_Buy();      // Bottom-up movement = open Buy
   if (Peresechenie()==2 && New_Bar==1) Open_Sell();     // Top-down movement  = open Sell
//============================================================================================
   return;
   }  
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Peresechenie()
   {
   ret=0;                                                // That's the heart of the matter!:)
//============================================================================================
   if ((Pred<=Golub && Tek> Golub) ||
       (Pred< Golub && Tek>=Golub)  ) ret=1;             // Bottom-up intersection       
//--------------------------------------------------------------------------------------------
   if ((Pred>=Golub && Tek< Golub) ||
       (Pred> Golub && Tek<=Golub)  ) ret=2;             // Top-down intersection
//============================================================================================
   return(ret);                                          // Return the intersection direction
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Open_Buy()  
   {
   if (total==1)
      {
      OrderSelect(0, SELECT_BY_POS);                     // Select the order
      if (OrderType()==0)return;                         // If it is buy, don't open
      }
   OrderSend(Symbol(),0, Lots(), Ask, 0, Ask-SL, Ask+TP, "", 0, 0, Blue);// Open
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
int Open_Sell() 
   {
   if (total==1)
      {
      OrderSelect(0, SELECT_BY_POS);                     // Select the order
      if (OrderType()==1)return;                         // If it is sell, don't open
      }
   OrderSend(Symbol(),1, Lots(), Bid, 0, Bid+SL, Bid-TP, "", 0, 0, Red);// Open
   return;
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
double Lots()
   {
   Lot = NormalizeDouble( AccountEquity()*Prots/100/1000, 1);// Calculate the amount of lots  
   if (Lot<0.1)Lot = 0.1;                                // For testing on const. min. lots
   return(Lot);
   }
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

Os testes deste expert a preços constantes de lotes tiveram um sucesso limitado:

Figura 15. Resultados de testes do Graal_31.mq4 (graal 31) no histórico de março de 2005 a julho de 2005, no gráfico H1 EURUSD
sob as condições de transação do servidor demonstrativo da
MetaQuotes Software Corp a preços constantes de lotes


Nosso programador fica completamente desanimado. Tanto trabalho, e tudo em vão. O tempo passa, e o nosso programador continua em sua busca pelo "graal". Após alguns meses, ele decide voltar a trabalhar no expert chamado Graal_3.mq4 (graal 3). "Bem, ele tinha um erro, mas criou bons resultados. Talvez tudo seja assim mesmo! O expert pode abrir os pedidos que quiser, contanto que apenas os bons resultados sejam mantidos". E os testes começam novamente.

Qual não foi a surpresa do programador ao ver o expert começar a perder o deposito monotonamente, por si só, sem que qualquer mudança tenha sido feita ao código!

Figura 16. Resultados de testes do Graal_3.mq4 (graal 3) no histórico de março de 2005 a julho de 2006, no gráfico H1 EURUSD
sob as condições de transação do servidor demonstrativo da
MetaQuotes Software Corp a preços constantes de lotes

3.4. Ajuste de resultados

O nosso personagem começa a ignorar as más notícias. Ele percebe que não é difícil colocar parâmetros otimizados em um expert pouco eficiente em um segmento de histórico. O mesmo expert sempre fornecerá resultados diferentes em diferentes períodos do histórico.

A questão se torna simplesmente a seguinte: como encontrar este tipo de entrada otimizada para o expert, sendo que, se possível, pequenas flutuações do mercado em relação à velocidade do preço não devem influenciar o funcionamento e a eficiência do expert. Em geral, é preciso focar em uma estratégia que resista a quaisquer mudanças no mercado, e a otimização de parâmetros deve apenas auxiliar em parte a se chegar aos melhores resultados possíveis.

A busca pelas configurações ideais do expert chamado Graal_3.mq4 (graal 3) não resultou em nada. O teste do expert com diferentes valores de variáveis externas resultou ou em perdas ou em configurações significativamente diferentes para diferentes períodos do histórico. Por este motivo, o nosso personagem não conseguiu encontrar as configurações ideais. Então ele concluiu que esta estratégia não possui configurações universais para todas as ocasiões.

Ele voltou a trabalhar no expert chamado Graal_31.mq4 (graal 31), agonizando para conseguir os resultados desejados. Mas os melhores resultados foram os seguintes:




Figura 17. Resultados de testes do Graal_31.mq4 (graal 31) no histórico de março de 2005 a julho de 2006, no gráfico H1 EURUSD
sob as condições de transação do servidor demonstrativo da
MetaQuotes Software Corp a preços constantes de lotes


Isto não lhe parece nem um pouco com um "graal". Por conta da profunda redução, visível a olho nu, no meio do gráfico, o expert não pode ser utilizado em uma conta real. Mas ele ainda é um expert funcional que mostra resultados positivos, ainda que nada fantásticos.

Isso encoraja o nosso personagem.

4. Conclusão


A desilusão sempre é dura, especialmente se as ilusões forem otimistas e alegres. Mas a vida põe tudo em seu devido lugar, cedo ou tarde. As preocupações constantes acabaram afetando o nosso personagem: O programador prejudicou as suas relações com dois centros de negócios, além de perder uma certa quantia de dinheiro suado... Tendo adquirido uma experiência inestimável em relação à programação e à realização de transações no Forex, o nosso personagem quase chega à conclusão de que "Apenas Mozart...", mas se detém e decide parar de tirar conclusões precipitadas.

Ao invés disso, ele pega uma folha de papel limpa e formula as conclusões às quais chegou com base nas lições tomadas:


SK. Dnepropetrovsk. 2006.