English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Trademinator 3: ascensão das máquinas comerciais

Trademinator 3: ascensão das máquinas comerciais

MetaTrader 5Negociação | 20 fevereiro 2014, 15:09
1 032 0
Roman Zamozhnyy
Roman Zamozhnyy

Prólogo

Era uma vez em um fórum distante (MQL5) dois artigos: ""Algoritmos Genéticos - é fácil!"" por Joo e "Dr. Tradelove..." que por mim foram publicados. No primeiro artigo, o autor nos equipou com uma poderosa ferramenta para otimizar qualquer coisa que você precisasse, incluindo estratégias de negociação - um algoritmo genético implementado por meio da linguagem MQL5.

Usando este algoritmo, no segundo artigo eu tentei desenvolver um Expert Advisor com auto-otimização baseado nele. O artigo termina com a formulação da seguinte tarefa: criar um Expert Advisor (auto-otimização, é claro), o que não só é possível selecionar os melhores parâmetros para um sistema de negociação particular, mas também escolher a melhor estratégia de todas as estratégias desenvolvidas. Vamos ver se é possível e, se for, como então.

Contos de robôs comerciais

Em primeiro lugar, nós formulamos os requisitos gerais para um Expert Advisor com auto-otimização.

Deve ser capaz de (com base em dados históricos):

  • Selecionar a melhor estratégia entre as descritas;
  • Escolher o melhor instrumento financeiro;
  • Escolher o melhor tamanho do depósito para o comércio com correção de alavanca;
  • Escolher os melhores parâmetros de indicadores da estratégia selecionada.

Além disso, na vida real, ela deve ser capaz de:

  • Abrir e fechar posições;
  • Escolher o tamanho da posição;
  • Decidir se uma nova otimização é necessária.

A figura abaixo mostra um diagrama esquemático do Expert Advisor proposto.


Um esquema detalhado com limites está no arquivo anexado Scheme_en.

Tendo em mente que é impossível compreender a imensidão, nós introduzimos restrições na lógica Expert Advisor. Concordamos que (importante):

  1. O Expert Advisor tomará decisões comerciais mediante a ocorrência de uma nova barra (em qualquer período de tempo que selecionarmos).
  2. Com base no p.1, mas não limitado a ele, o Expert Advisor fechará negócios apenas nos sinais indicadores não usando o Obter Lucro e Parada Protetora e, consequentemente, não usando o Limite Móvel.
  3. A condição para iniciar uma nova otimização: um abaixamento do saldo é maior que o valor predefinido durante a inicialização do nível. Por favor, note que esta é a minha condição pessoal, e cada um pode escolher sua condição específica.
  4. A função de aptidão modela comércio no histórico e maximiza o balanço modelado, desde que o abaixamento relativo do saldo das operações simuladas está abaixo de um determinado nível predefinido. Também note que esta é a minha função de aptidão pessoal, e você pode escolher a sua específica.
  5. Nós limitamos o número de parâmetros a serem otimizados, com exceção dos três mais gerais (estratégia, instrumento e quota de depósito) para cinco para os parâmetros de indicadores buffers. Essa limitação segue logicamente o número máximo de indicadores buffers para os indicadores técnicos internos. Se você for descrever as estratégias que usam indicadores personalizados com um grande número de indicadores buffers, basta alterar a variável OptParamCount no arquivo main.mq5 para a quantidade desejada.

Agora que os requisitos são especificados e limitações selecionadas, você pode examinar o código que implementa tudo isso.

Vamos começar com a função onde tudo é executado.

void OnTick()
{
  if(isNewBars()==true)
  {
    trig=false;
    switch(strat)
    {
      case  0: {trig=NeedCloseMA()   ; break;};                      //The number of case strings must be equal to the number of strategies
      case  1: {trig=NeedCloseSAR()  ; break;};
      case  2: {trig=NeedCloseStoch(); break;};
      default: {trig=NeedCloseMA()   ; break;};
    }
    if(trig==true)
    {
      if(GetRelDD()>maxDD)                                           //If a balance drawdown is above the max allowed value:
      {
        GA();                                                        //Call the genetic optimization function
        GetTrainResults();                                           //Get the optimized parameters
        maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);               //Now count the drawdown not from the balance maximum...
                                                                     //...but from the current balance
      }
    }
    switch(strat)
    {
      case  0: {trig=NeedOpenMA()   ; break;};                       //The number of case strings must be equal to the number of strategies
      case  1: {trig=NeedOpenSAR()  ; break;};
      case  2: {trig=NeedOpenStoch(); break;};
      default: {trig=NeedOpenMA()   ; break;};
    }
    Print(TimeToString(TimeCurrent()),";","Main:OnTick:isNewBars(true)",
          ";","strat=",strat);
  }
}

O que é aqui? Tal como foi estabelecido no diagrama, observamos cada tick, se existe uma nova barra. Se houver, então, sabendo qual estratégia é escolhida agora, chamamos a sua função específica para verificar se há uma posição aberta e fechá-la, se necessário. Suponha agora que a melhor estratégia de avanço é SAR, respectivamente, a função NeedCloseSAR será chamada:

bool NeedCloseSAR()
{
  CopyBuffer(SAR,0,0,count,SARBuffer);
  CopyOpen(s,tf,0,count,o);
  Print(TimeToString(TimeCurrent()),";","StrategySAR:NeedCloseSAR",
        ";","SAR[0]=",SARBuffer[0],";","SAR[1]=",SARBuffer[1],";","Open[0]=",o[0],";","Open[1]=",o[1]);
  if((SARBuffer[0]>o[0]&&SARBuffer[1]<o[1])||
     (SARBuffer[0]<o[0]&&SARBuffer[1]>o[1]))
  {
    if(PositionsTotal()>0)
    {
      ClosePosition();
      return(true);
    }
  }
  return(false);
}

Qualquer função de fechamento de posição deve ser booleana e retornar verdadeira quando fechar uma posição. Isso permite o próximo bloco de código da função OnTick() decidir se uma nova otimização é necessária:

    if(trig==true)
    {
      if(GetRelDD()>maxDD)                                           //If the balance drawdown is above the max allowed one:
      {
        GA();                                                        //Call the genetic optimization function
        GetTrainResults();                                           //Get optimized parameters
        maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);                   //Now count the drawdown not from the balance maximum...
                                                                     //...but from the current balance
      }
    }

Obter o atual abaixamento de balanço e compará-lo com o máximo permitido. Se ele excedeu o valor máximo, executar uma nova otimização (GA()). A função GA() por sua vez, chama o centro do Expert Advisor - a função de aptidão FitnessFunction(int chromos) do módulo GAModule.mqh:

void FitnessFunction(int chromos)                                    //A fitness function for the genetic optimizer:...
                                                                     //...selects a strategy, symbol, deposit share,...
                                                                     //...parameters of indicator buffers;...
                                                                     //...you can optimize whatever you need, but...
                                                                     //...watch carefully the number of genes
{
  double ff=0.0;                                                     //The fitness function
  strat=(int)MathRound(Colony[GeneCount-2][chromos]*StratCount);     //GA selects a strategy
 //For EA testing mode use the following code...
  z=(int)MathRound(Colony[GeneCount-1][chromos]*3);                  //GA selects a symbol
  switch(z)
  {
    case  0: {s="EURUSD"; break;};
    case  1: {s="GBPUSD"; break;};
    case  2: {s="USDCHF"; break;};
    case  3: {s="USDJPY"; break;};
    default: {s="EURUSD"; break;};
  }
//..for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window)
/*
  z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));//GA selects a symbol
  s=SymbolName(z,true);
*/
  optF=Colony[GeneCount][chromos];                                   //GA selects a deposit share
  switch(strat)
  {
    case  0: {ff=FFMA(   Colony[1][chromos],                         //The number of case strings must be equal to the number of strategies
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    case  1: {ff=FFSAR(  Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    case  2: {ff=FFStoch(Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
    default: {ff=FFMA(   Colony[1][chromos],
                         Colony[2][chromos],
                         Colony[3][chromos],
                         Colony[4][chromos],
                         Colony[5][chromos]); break;};
  }
  AmountStartsFF++;
  Colony[0][chromos]=ff;
  Print(TimeToString(TimeCurrent()),";","GAModule:FitnessFunction",
        ";","strat=",strat,";","s=",s,";","optF=",optF,
        ";",Colony[1][chromos],";",Colony[2][chromos],";",Colony[3][chromos],";",Colony[4][chromos],";",Colony[5][chromos]);
}

Dependendo da estratégia selecionada, o módulo de cálculo da função de aptidão que é específico para uma determinada estratégia, é chamado. Por exemplo, o GA escolheu um estocástico, FFStoch() será chamado, e otimização de parâmetros de indicadores buffers será transferido a ele:

double FFStoch(double par1,double par2,double par3,double par4,double par5)
{
  int    b;
  bool   FFtrig=false;                                               //Is there an open position?
  string dir="";                                                     //Direction of the open position
  double OpenPrice;                                                  //Position Open price
  double t=cap;                                                      //Current balance
  double maxt=t;                                                     //Maximum balance
  double aDD=0.0;                                                    //Absolute drawdown
  double rDD=0.000001;                                               //Relative drawdown
  Stoch=iStochastic(s,tf,(int)MathRound(par1*MaxStochPeriod)+1,
                         (int)MathRound(par2*MaxStochPeriod)+1,
                         (int)MathRound(par3*MaxStochPeriod)+1,MODE_SMA,STO_CLOSECLOSE);
  StochTopLimit   =par4*100.0;
  StochBottomLimit=par5*100.0;
  dig=MathPow(10.0,(double)SymbolInfoInteger(s,SYMBOL_DIGITS));
  leverage=AccountInfoInteger(ACCOUNT_LEVERAGE);
  contractSize=SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE);
  b=MathMin(Bars(s,tf)-1-count-MaxMAPeriod,depth);
  for(from=b;from>=1;from--)                                         //Where to start copying of history
  {
    CopyBuffer(Stoch,0,from,count,StochBufferMain);
    CopyBuffer(Stoch,1,from,count,StochBufferSignal);
    if((StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1])||
       (StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1]))
    {
      if(FFtrig==true)
      {
        if(dir=="BUY")
        {
          CopyOpen(s,tf,from,count,o);
          if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0;
          if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
          if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt;
        }
        if(dir=="SELL")
        {
          CopyOpen(s,tf,from,count,o);
          if(t>0) t=t+t*optF*leverage*(OpenPrice-o[1])*dig/contractSize; else t=0;
          if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
          if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt;
        }
        FFtrig=false;
      }
   }
    if(StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1]&&StochBufferMain[1]>StochTopLimit)
    {
      CopyOpen(s,tf,from,count,o);
      OpenPrice=o[1];
      dir="SELL";
      FFtrig=true;
    }
    if(StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1]&&StochBufferMain[1]<StochBottomLimit)
    {
      CopyOpen(s,tf,from,count,o);
      OpenPrice=o[1];
      dir="BUY";
      FFtrig=true;
    }
  }
  Print(TimeToString(TimeCurrent()),";","StrategyStoch:FFStoch",
        ";","K=",(int)MathRound(par1*MaxStochPeriod)+1,";","D=",(int)MathRound(par2*MaxStochPeriod)+1,
        ";","Slow=",(int)MathRound(par3*MaxStochPeriod)+1,";","TopLimit=",StochTopLimit,";","BottomLimit=",StochBottomLimit,
        ";","rDD=",rDD,";","Cap=",t);
  if(rDD<=trainDD) return(t); else return(0.0);
}

A função de aptidão do estocástico retorna um equilíbrio simulado para a função principal, que vai passá-lo para o algoritmo genético. Em algum ponto no tempo a GA decide acabar com a otimização, e usando a função GetTrainResults(), retornamos os melhores valores atuais da estratégia (por exemplo - médias móveis), símbolo, a quota de depósito e parâmetros dos indicadores de buffers para o programa básico, bem como criamos indicadores para comércio real adicional:

void GetTrainResults()                                               //Get the best parameters
{
  strat=(int)MathRound(Chromosome[GeneCount-2]*StratCount);          //Remember the best strategy
//For EA testing mode use the following code...
  z=(int)MathRound(Chromosome[GeneCount-1]*3);                       //Remember the best symbol
  switch(z)
  {
    case  0: {s="EURUSD"; break;};
    case  1: {s="GBPUSD"; break;};
    case  2: {s="USDCHF"; break;};
    case  3: {s="USDJPY"; break;};
    default: {s="EURUSD"; break;};
  }
//...for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window)
/*
  z=(int)MathRound(Chromosome[GeneCount-1]*(SymbolsTotal(true)-1));  //Remember the best symbol
  s=SymbolName(z,true);
*/
  optF=Chromosome[GeneCount];                                        //Remember the best deposit share
  switch(strat)
  {
    case  0: {GTRMA(   Chromosome[1],                                //The number of case strings must be equal to the number of strategies
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    case  1: {GTRSAR(  Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    case  2: {GTRStoch(Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
    default: {GTRMA(   Chromosome[1],
                       Chromosome[2],
                       Chromosome[3],
                       Chromosome[4],
                       Chromosome[5]) ; break;};
  }
  Print(TimeToString(TimeCurrent()),";","GAModule:GetTrainResults",
        ";","strat=",strat,";","s=",s,";","optF=",optF,
        ";",Chromosome[1],";",Chromosome[2],";",Chromosome[3],";",Chromosome[4],";",Chromosome[5]);
}

void GTRMA(double par1,double par2,double par3,double par4,double par5)
{
  MAshort=iMA(s,tf,(int)MathRound(par1*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
  MAlong =iMA(s,tf,(int)MathRound(par2*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
  CopyBuffer(MAshort,0,from,count,ShortBuffer);
  CopyBuffer(MAlong, 0,from,count,LongBuffer );
  Print(TimeToString(TimeCurrent()),";","StrategyMA:GTRMA",
        ";","MAL=",(int)MathRound(par2*MaxMAPeriod)+1,";","MAS=",(int)MathRound(par1*MaxMAPeriod)+1);
}

Agora que tudo está de volta ao lugar onde tudo está funcionando (OnTick()): sabendo que estratégia é agora a melhor, é verificado se é hora de ir para o mercado:

bool NeedOpenMA()
{
  CopyBuffer(MAshort,0,0,count,ShortBuffer);
  CopyBuffer(MAlong, 0,0,count,LongBuffer );
  Print(TimeToString(TimeCurrent()),";","StrategyMA:NeedOpenMA",
        ";","LB[0]=",LongBuffer[0],";","LB[1]=",LongBuffer[1],";","SB[0]=",ShortBuffer[0],";","SB[1]=",ShortBuffer[1]);
  if(LongBuffer[0]>LongBuffer[1]&&ShortBuffer[0]>LongBuffer[0]&&ShortBuffer[1]<LongBuffer[1])
  {
    request.type=ORDER_TYPE_SELL;
    OpenPosition();
    return(false);
  }
  if(LongBuffer[0]<LongBuffer[1]&&ShortBuffer[0]<LongBuffer[0]&&ShortBuffer[1]>LongBuffer[1])
  {
    request.type=ORDER_TYPE_BUY;
    OpenPosition();
    return(false);
  }
  return(true);
}

O círculo fechou-se.

Vamos ver como funciona. Aqui está um relatório de 2011 sobre o período de tempo de 1 hora, com quatro pares principais: EURUSD, GBPUSD, USDCHF, USDJPY:

Relatório do testador de estratégia
InstaForex-Server (Build 567)
Configurações
Especialista: Principal
Símbolo: EURUSD
Período: H1 (2011.01.01 - 2011.12.31)
Parâmetros de entrada: trainDD=0.50000000
maxDD=0.20000000
Corretor: Empresas do grupo InstaForex
Moeda: USD
Depósito Inicial: 10 000.00
Alavancagem: 1:100
Resultados
Qualidade do histórico: 100%
Barras: 6197 Ticks: 1321631
Lucro total da rede: -538,74 Lucro bruto: 3 535.51 Prejuízo bruto: -4 074.25
Fator lucro: 0,87 Pagamento esperado: -89,79 Nível de margem: 85,71%
Fator de recuperação: -0,08 Taxa do especialista: 0,07 Resultado onTester: 0
Queda de balanço:
Queda absoluta de balanço: 4 074.25 Queda máxima de balanço: 4 074.25 (40.74%) Queda relativa de balanço: 40.74% (4 074.25)
Queda de lucro líquido:
Queda absoluta de lucro líquido: 4 889.56 Queda máxima de lucro líquido: 6 690.90 (50.53%) Queda relativa de lucro líquido: 50.53% (6 690.90)
Total de negócios: 6 Negócios curtos ( ganho 0%): 6 (16.67%) Negócios longos ( ganho 0%): 0 (0.00%)
Total de negócios: 12 Negócios lucrativos ( % do total): 1 (16.67%) Negócios com prejuízo ( % do total): 5 (83.33%)
Negócio com maior lucro: 3 535.51 Negócio com maior perda: -1 325.40
Lucro médio de negociação: 3 535.51 Perda comercial média: -814,85
Máximo de ganhos consecutivos: 1 (3 535.51) Máximo de perdas consecutivas: 5 (-4 074.25)
Máximo de lucro consecutivo (contagem): 3 535.51 (1) Máximo de prejuízo consecutivo (contagem): -4 074.25 (5)
Médias de ganhos consecutivos: 1 Médias de perdas consecutivas: 5


Pedidos
Tempo aberto Ordem Símbolo Tipo Volume Preço S / L T / P Tempo Estado Comentário
2011.01.03 01:002USDCHFvenda28.21 / 28.210,93212011.01.03 01:00preenchido
2011.01.03 3:003USDCHFcompra28.21 / 28.210,93652011.01.03 3:00preenchido
2011.01.03 6:004USDCHFvenda24.47 / 24.470,93522011.01.03 6:00preenchido
2011.01.03 9:005USDCHFcompra24.47 / 24.470,93722011.01.03 9:00preenchido
2011.01.03 13:006USDCHFvenda22.99 / 22.990,93522011.01.03 13:00preenchido
2011.01.03 16:007USDCHFcompra22.99 / 22.990,93752011.01.03 16:00preenchido
2011.01.03 18:008USDJPYvenda72.09 / 72.0981,572011.01.03 18:00preenchido
2011.01.03 21:009USDJPYcompra72.09 / 72.0981,662011.01.03 21:00preenchido
2011.01.04 01:0010USDJPYvenda64.54 / 64.5481,672011.01.04 01:00preenchido
2011.01.04 2:0011USDJPYcompra64.54 / 64.5481,782011.01.04 2:00preenchido
2011.10.20 21:0012USDCHFvenda56.30 / 56.300,89642011.10.20 21:00preenchido
2011.10.21 12:0013USDCHFcompra56.30 / 56.300,89082011.10.21 12:00preenchido
Negócios
Tempo Negócio Símbolo Tipo Direção Volume Preço Ordem Comissão Troca Lucro Saldo Comentário
2011.01.01 00:001saldo0,000,0010 000.0010 000.00
2011.01.03 01:002USDCHFvendaem28,210,932120,000,000,0010 000.00
2011.01.03 3:003USDCHFcomprafora28,210,936530,000,00-1 325.408 674.60
2011.01.03 6:004USDCHFvendaem24,470,935240,000,000,008 674.60
2011.01.03 9:005USDCHFcomprafora24,470,937250,000,00-522,198 152.41
2011.01.03 13:006USDCHFvendaem22,990,935260,000,000,008 152.41
2011.01.03 16:007USDCHFcomprafora22,990,937570,000,00-564,027 588.39
2011.01.03 18:008USDJPYvendaem72,0981,5780,000,000,007 588.39
2011.01.03 21:009USDJPYcomprafora72,0981,6690,000,00-794,536 793.86
2011.01.04 01:0010USDJPYvendaem64,5481,67100,000,000,006 793.86
2011.01.04 2:0011USDJPYcomprafora64,5481,78110,000,00-868,115 925.75
2011.10.20 21:0012USDCHFvendaem56,300,8964120,000,000,005 925.75
2011.10.21 12:0013USDCHFcomprafora56,300,8908130,00-3,783 539.299 461.26
0,00 -3,78 -534,96 9 461.26
Copyright 2001-2011, MetaQuotes Software Corp.

Deixe-me explicar a zona que é marcada na tabela (explicações são tomadas a partir da análise do log):

  1. Após o início do Expert Advisor, o algoritmo genético selecionou a estratégia revolucionária SAR no USDCHF com uma parte do depósito no comércio igual a 28%, então negociou até a noite de 3 de Janeiro, perdeu mais de 20% do saldo e começou a reotimização.
  2. Em seguida, o Expert Advisor decidiu negociar SAR revolucionário no USDJPY, mas com todo o depósito (98%). Naturalmente, não poderia negociar longo e, portanto, começou a sua terceira otimização na manhã do dia 04 de janeiro.
  3. Desta vez, decidiu comercializar cruzamento dourado e morto de médias móveis no USDCHF mais uma vez para todo o depósito. E esperou pelo primeiro cruzamento morto até 20 de outubro, e vendeu-o ao máximo, e ganhou de volta tudo o que perdeu. Depois disso, até o final do ano, o Expert Advisor não viu condições favoráveis ​​para entrar no mercado.

Para ser continuado?

Pode ser continuado? Qual seria a próxima geração de Expert Advisors? O Expert Advisor que inventa estratégias e seleciona a melhor entre elas. E, além disso, pode administrar dinheiro, comprar o mais poderoso hardware, canal e assim por diante ...

Aviso de risco:

Esta breve declaração não revela completamente todos os riscos e outros aspectos significativos da moeda de negociação forex na margem. Você deve entender a natureza da negociação e da extensão da sua exposição ao risco. Você deve considerar cuidadosamente se o comércio é adequado para você, tendo em conta a sua experiência, objetivos, recursos financeiros e outras circunstâncias relevantes.

Forex não é apenas um mercado lucrativo, mas também altamente arriscado. Em termos de margem comercial, flutuações relativamente pequenas do câmbio podem ter um impacto significativo sobre a conta do comerciante, o que resulta em uma perda igual ao depósito inicial e quaisquer fundos adicionalmente depositados na conta para manter posições em aberto. Você não deve investir dinheiro que você não pode arcar com as despesas de perder. Antes de decidir negociar, por favor, certifique-se de que você compreendeu todos os riscos e leve em conta o seu nível de experiência. Se necessário, procure aconselhamento independente.

Licenças:

Módulo UGAlib.mqh é desenvolvido e distribuído sob a licença BSD por Andrey Dik aka Joo.

O Expert Advisor e módulos auxiliares ligados a este artigo são desenvolvidos e distribuído sob a licença BSD pelo autor Roman Rich. O texto da licença está disponível no arquivo Lic.txt.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/350

Arquivos anexados |
lic.txt (1.43 KB)
sheme_en.gif (147.11 KB)
gamodule.mqh (7.24 KB)
main.mq5 (4.99 KB)
musthave.mqh (7.79 KB)
strategyma.mqh (5.13 KB)
strategysar.mqh (4.09 KB)
strategystoch.mqh (6.04 KB)
ugalib.mqh (33.36 KB)
Código MQL5 de segurança: proteção de senha, geradores de chaves, limites de tempo, licenças remotas e técnicas de codificação de chave de licença de EA avançadas Código MQL5 de segurança: proteção de senha, geradores de chaves, limites de tempo, licenças remotas e técnicas de codificação de chave de licença de EA avançadas
A maioria dos desenvolvedores precisa ter seu código protegido. Este artigo apresentará alguns meios diferentes para proteger o software MQL5 - ele apresenta métodos para fornecer recursos de licenciamento para Scripts do MQL5, Exper Advisors e Indicadores. Ele cobre a proteção de senha, geradores de chave, licença de conta, avaliação de limite de tempo e proteção remota usando chamadas MQL5-RPC.
Criando Expert Advisors usando o assistente visual Expert Advisor Criando Expert Advisors usando o assistente visual Expert Advisor
Assistente visual Expert Advisor para MetaTrader 5 fornece um ambiente gráfico altamente intuitivo com um conjunto abrangente de blocos comerciais predefinidos que permitem que você crie Expert Advisors em minutos. A abordagem clique, arraste e solte do Assistente visual Expert Advisor permite criar representações visuais de estratégias de negociação Forex e sinais de como você faria com lápis e papel. Esses diagramas comerciais são analisados automaticamente pelo gerador de código Molanis’ MQL5 que os transforma em Expert Advisors prontos para serem usados. O ambiente gráfico interativo simplifica o processo de design e elimina a necessidade de escrever código MQL5.
Promova seus projetos de desenvolvimento utilizando bibliotecas EX5 Promova seus projetos de desenvolvimento utilizando bibliotecas EX5
Ocultando os detalhes de implementação de classes/funções em um arquivo .ex5 vai permitir que você compartilhe seus algoritmos experientes com outros desenvolvedores, defina projetos comuns e promova-os na Internet. E enquanto a equipe MetaQuotes não mede esforços para viabilizar a possibilidade de herança direta de classes de biblioteca ex5, vamos implementá-la agora.
Previsão de séries temporais utilizando suavização exponencial (continuação) Previsão de séries temporais utilizando suavização exponencial (continuação)
Este artigo busca atualizar o indicador criado anteriormente e lida brevemente com um método para estimar intervalos de confiança de previsão usando auto inicialização e quantis. Como resultado, teremos o indicador de previsão e os scripts a serem usados para estimar a precisão da previsão.