Arrastar a média do robô de Média Móvel

 

Boa tarde, pessoal.

Gostaria de fazer assim:

- Arrastar a média: a cada 100 pontos que o preço for para o lado errado, quero que ele dobre a quantidade de contratos. Por exemplo: se vendeu 2 contratos a 96000 no WIN e o preço subiu para 96100, eu quero que ele venda mais 4 contratos. A cada 100 pontos do lado errado, ele vai dobrando a quantidade de contratos.

Este é o trecho do meu código que faz as compras e vendas:

 if(smaArray[0] < rates[0].open && smaArray[0] >= ultimoTick.last && !posAberta && !ordPendente && HoraNegociacao())
         {
            PRC = NormalizeDouble(ultimoTick.ask, _Digits);
            STL = NormalizeDouble(PRC - stopLoss, _Digits);
            TKP = NormalizeDouble(PRC + takeProfit, _Digits);
                 
            if(trade.Buy(lote, _Symbol, PRC, STL, TKP, ""))
               {
                  Print("Ordem de Compra - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
            else
               {
                  Print("Ordem de Compra - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
         }
      else if(smaArray[0] > rates[0].open && smaArray[0] <= ultimoTick.last && !posAberta && !ordPendente && HoraNegociacao())
         {
         
            PRC = NormalizeDouble(ultimoTick.bid, _Digits);
            STL = NormalizeDouble(PRC + stopLoss, _Digits);
            TKP = NormalizeDouble(PRC - takeProfit, _Digits);
              
            if(trade.Sell(lote, _Symbol, PRC, STL, TKP, ""))
               {
                  Print("Ordem de Venda - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
            else
               {
                  Print("Ordem de Venda - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
         }

Se precisar, posso mandar o código completo também.

Obrigado.

 
Evandro Goncalves:

Boa tarde, pessoal.

Gostaria de fazer assim:

- Arrastar a média: a cada 100 pontos que o preço for para o lado errado, quero que ele dobre a quantidade de contratos. Por exemplo: se vendeu 2 contratos a 96000 no WIN e o preço subiu para 96100, eu quero que ele venda mais 4 contratos. A cada 100 pontos do lado errado, ele vai dobrando a quantidade de contratos.

Este é o trecho do meu código que faz as compras e vendas:

Se precisar, posso mandar o código completo também.

Obrigado.

Matematicamente falando você esta estrategia eh muito perigosa. Sugiro que leia a thread abaixo.

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

Martingale

Trader_Patinhas, 2019.04.23 22:45

Furada total, meu amigo. Saia dessa, antes que perca todo o seu dinheiro. 

Como disse o colega acima, só quem não adquiriu um conhecimento mínimo de estatística (ou adquiriu mas nunca parou pra pensar e fazer as contas) pode acreditar que Martingale seja uma estratégia boa.

Não se iluda com o desempenho histórico, pois essa estratégia é feita para gerar lucro diariamente com alta probabilidade de sucesso. Se bem elaborada, pode gerar gráficos lindos por meses a fio. O problema é que, no dia em que ela falhar, vai te levar tudo.

É como o peru: acorda feliz todos os dias e na véspera do Natal perde a cabeça.


 
Joscelino Celso de Oliveira:

Matematicamente falando você esta estrategia eh muito perigosa. Sugiro que leia a thread abaixo.


Se puder me ajudar a desenvolver, de acordo com o meu código, eu agradeço. O robô terá os parâmetros de meta de lucro e prejuízo diário em dinheiro. Neste sentido, se falhar eu já tenho o máximo de prejuízo diário configurado nos parâmetros do robô.

 
Evandro Goncalves:

Если вы можете помочь мне развиваться, в соответствии с моим кодом, я благодарю вас. Робот будет иметь параметры прибыли, цели и ежедневных потерь наличными. В этом смысле, если я терплю неудачу, у меня уже есть максимальная ежедневная потеря, настроенная в параметрах робота.

exiba o código-fonte completo para que você possa testar e dar-Lhe recomendações

 
Denis Nikolaev:

exiba o código-fonte completo para que você possa testar e dar-Lhe recomendações

Bom dia, Denis Nikolaev.


Segue o código completo:

#include <Trade\Trade.mqh>
CTrade trade;

input int                     ma_periodo = 20;//Período da Média
input int                     ma_desloc = 0;//Deslocamento da Média
input ENUM_MA_METHOD          ma_metodo = MODE_SMA;//Método Média Móvel
input ENUM_APPLIED_PRICE      ma_preco = PRICE_CLOSE;//Preço para Média
input ulong                   magicNum = 123456;//Magic Number
input ulong                   desvPts = 50;//Desvio em Pontos
input ENUM_ORDER_TYPE_FILLING preenchimento = ORDER_FILLING_RETURN;//Preenchimento da Ordem

input double                  lote = 5.0;//Volume
input double                  stopLoss = 5;//Stop Loss
input double                  takeProfit = 20;//Take Profit
input double                  gatilhoBE = 2;//Gatilho BreakEven
input double                  gatilhoTS = 6;//Gatilho TrailingStop
input double                  stepTS = 2;//Step TrailingStop

input int                     horaInicioAbertura = 10;//Hora de Inicio de Abertura de Posições
input int                     minutoInicioAbertura = 30;//Minuto de Inicio de Abertura de Pisoções
input int                     horaFimAbertura = 16;//Hora de Encerramento de Abertura de Posições
input int                     minutoFimAbertura = 45;//Minuto de Encerramento de Abertura de Posições
input int                     horaInicioFechamento = 17;//Hora de Inicio de Fechamento de Posições
input int                     minutoInicioFechamento = 20;//Minuto de Inicio de Fechamento de Posições

double                        PRC;//Preço normalizado
double                        STL;//StopLoss normalizado
double                        TKP;//TakeProfit normalizado

double                        smaArray[];
int                           smaHandle;

bool                          posAberta;
bool                          ordPendente;
bool                          beAtivo;

MqlTick                       ultimoTick;
MqlRates                      rates[];
MqlDateTime                   horaAtual;

int OnInit()
  {
      smaHandle = iMA(_Symbol, _Period, ma_periodo, ma_desloc, ma_metodo, ma_preco);
      if(smaHandle==INVALID_HANDLE)
         {
            Print("Erro ao criar média móvel - erro", GetLastError());
            return(INIT_FAILED);
         }
      ArraySetAsSeries(smaArray, true);
      ArraySetAsSeries(rates, true);     
      
      trade.SetTypeFilling(preenchimento);
      trade.SetDeviationInPoints(desvPts);
      trade.SetExpertMagicNumber(magicNum);
      
      if(horaInicioAbertura > horaFimAbertura || horaFimAbertura > horaInicioFechamento)
         {  
            Alert("Inconsistência de Horários de Negociação!");
            return(INIT_FAILED);
         }
      if(horaInicioAbertura == horaFimAbertura && minutoInicioAbertura >= minutoFimAbertura)
         {
            Alert("Inconsistência de Horários de Negociação!");
            return(INIT_FAILED);
         }
      if(horaFimAbertura == horaInicioFechamento && minutoFimAbertura >= minutoInicioFechamento)
         {
            Alert("Inconsistência de Horários de Negociação!");
            return(INIT_FAILED);
         }
      
      return(INIT_SUCCEEDED);
  }
void OnTick()
  {               
      if(!SymbolInfoTick(Symbol(),ultimoTick))
         {
            Alert("Erro ao obter informações de Preços: ", GetLastError());
            return;
         }
         
      if(CopyRates(_Symbol, _Period, 0, 3, rates)<0)
         {
            Alert("Erro ao obter as informações de MqlRates: ", GetLastError());
            return;
         }
      
      if(CopyBuffer(smaHandle, 0, 0, 3, smaArray)<0)
         {
            Alert("Erro ao copiar dados da média móvel: ", GetLastError());
            return;
         }
         
      posAberta = false;
      for(int i = PositionsTotal()-1; i>=0; i--)
         {
            string symbol = PositionGetSymbol(i);
            ulong magic = PositionGetInteger(POSITION_MAGIC);
            if(symbol == _Symbol && magic == magicNum)
               {  
                  posAberta = true;
                  break;
               }
         }
         
      ordPendente = false;
      for(int i = OrdersTotal()-1; i>=0; i--)
         {
            ulong ticket = OrderGetTicket(i);
            string symbol = OrderGetString(ORDER_SYMBOL);
            ulong magic = OrderGetInteger(ORDER_MAGIC);
            if(symbol == _Symbol && magic == magicNum)
               {
                  ordPendente = true;
                  break;
               }
         }
      
      if(!posAberta)
         {
            beAtivo = false;
         }
         
      if(posAberta && !beAtivo)
         {
            BreakEven(ultimoTick.last);
         }
         
      if(posAberta && beAtivo)
         {
            TrailingStop(ultimoTick.last);
         }
      
      if(HoraFechamento())
         {
            Comment("Horário de Fechamento de Posições!");
            FechaPosicao();
         }
      else if(HoraNegociacao())
         {
            Comment("Dentro do Horário de Negociação!");
         }
      else
         {
            Comment("Fora do Horário de Negociação!");
         }
            
      if(ultimoTick.last>smaArray[0] && rates[1].close>rates[1].open && !posAberta && !ordPendente && HoraNegociacao())
         {
            PRC = NormalizeDouble(ultimoTick.ask, _Digits);
            STL = NormalizeDouble(PRC - stopLoss, _Digits);
            TKP = NormalizeDouble(PRC + takeProfit, _Digits);
            if(trade.Buy(lote, _Symbol, PRC, STL, TKP, ""))
               {
                  Print("Ordem de Compra - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
            else
               {
                  Print("Ordem de Compra - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
         }
      else if(ultimoTick.last<smaArray[0] && rates[1].close<rates[1].open && !posAberta && !ordPendente && HoraNegociacao())
         {
            PRC = NormalizeDouble(ultimoTick.bid, _Digits);
            STL = NormalizeDouble(PRC + stopLoss, _Digits);
            TKP = NormalizeDouble(PRC - takeProfit, _Digits);
            if(trade.Sell(lote, _Symbol, PRC, STL, TKP, ""))
               {
                  Print("Ordem de Venda - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
            else
               {
                  Print("Ordem de Venda - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
               }
         }   
  }
//---
//---
bool HoraFechamento()
   {
      TimeToStruct(TimeCurrent(), horaAtual);
      if(horaAtual.hour >= horaInicioFechamento)
         {
            if(horaAtual.hour == horaInicioFechamento)
               {
                  if(horaAtual.min >= minutoInicioFechamento)
                     {
                        return true;
                     }
                  else
                     {
                        return false;
                     }
               }
            return true;
         }
      return false;
   }
//---
//---
bool HoraNegociacao()
   {
      TimeToStruct(TimeCurrent(), horaAtual);
      if(horaAtual.hour >= horaInicioAbertura && horaAtual.hour <= horaFimAbertura)
         {
            if(horaAtual.hour == horaInicioAbertura)
               {
                  if(horaAtual.min >= minutoInicioAbertura)
                     {
                        return true;
                     }
                  else
                     {
                        return false;
                     }
               }
            if(horaAtual.hour == horaFimAbertura)
               {
                  if(horaAtual.min <= minutoFimAbertura)
                     {
                        return true;
                     }
                  else
                     {
                        return false;
                     }
               }
            return true;
         }
      return false;
   }
//---
//---
void FechaPosicao()
   {
      for(int i = PositionsTotal()-1; i>=0; i--)
         {
            string symbol = PositionGetSymbol(i);
            ulong magic = PositionGetInteger(POSITION_MAGIC);
            if(symbol == _Symbol && magic == magicNum)
               {
                  ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
                  if(trade.PositionClose(PositionTicket, desvPts))
                     {
                        Print("Posição Fechada - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                     }
                  else
                     {
                        Print("Posição Fechada - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                     }
               }
         }
   }
//---
//---
void TrailingStop(double preco)
   {
      for(int i = PositionsTotal()-1; i>=0; i--)
         {
            string symbol = PositionGetSymbol(i);
            ulong magic = PositionGetInteger(POSITION_MAGIC);
            if(symbol == _Symbol && magic==magicNum)
               {
                  ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
                  double StopLossCorrente = PositionGetDouble(POSITION_SL);
                  double TakeProfitCorrente = PositionGetDouble(POSITION_TP);
                  if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                     {
                        if(preco >= (StopLossCorrente + gatilhoTS) )
                           {
                              double novoSL = NormalizeDouble(StopLossCorrente + stepTS, _Digits);
                              if(trade.PositionModify(PositionTicket, novoSL, TakeProfitCorrente))
                                 {
                                    Print("TrailingStop - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                              else
                                 {
                                    Print("TrailingStop - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                           }
                     }
                  else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                     {
                        if(preco <= (StopLossCorrente - gatilhoTS) )
                           {
                              double novoSL = NormalizeDouble(StopLossCorrente - stepTS, _Digits);
                              if(trade.PositionModify(PositionTicket, novoSL, TakeProfitCorrente))
                                 {
                                    Print("TrailingStop - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                              else
                                 {
                                    Print("TrailingStop - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                           }
                     }
               }
         }
   }
//---
//---

void BreakEven(double preco)
   {
      for(int i = PositionsTotal()-1; i>=0; i--)
         {
            string symbol = PositionGetSymbol(i);
            ulong magic = PositionGetInteger(POSITION_MAGIC);
            if(symbol == _Symbol && magic == magicNum)
               {
                  ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
                  double PrecoEntrada = PositionGetDouble(POSITION_PRICE_OPEN);
                  double TakeProfitCorrente = PositionGetDouble(POSITION_TP);
                  if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                     {
                        if( preco >= (PrecoEntrada + gatilhoBE) )
                           {
                              if(trade.PositionModify(PositionTicket, PrecoEntrada, TakeProfitCorrente))
                                 {
                                    Print("BreakEven - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                    beAtivo = true;
                                 }
                              else
                                 {
                                    Print("BreakEven - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                           }                           
                     }
                  else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                     {
                        if( preco <= (PrecoEntrada - gatilhoBE) )
                           {
                              if(trade.PositionModify(PositionTicket, PrecoEntrada, TakeProfitCorrente))
                                 {
                                    Print("BreakEven - sem falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                    beAtivo = true;
                                 }
                              else
                                 {
                                    Print("BreakEven - com falha. ResultRetcode: ", trade.ResultRetcode(), ", RetcodeDescription: ", trade.ResultRetcodeDescription());
                                 }
                           }
                     }
               }
         }
   }
 
Evandro Goncalves:

Bom dia, Denis Nikolaev.


Segue o código completo:

Não chamaria isso de robô...

Você vai virar Babá de Script... Jamais deixaria esse código solto sozinho por aí... Cuidado!


;)

 
Flavio Jarabeck:

Não chamaria isso de robô...

Você vai virar Babá de Script... Jamais deixaria esse código solto sozinho por aí... Cuidado!


;)

Não entendi, amigo.

- Por que não chamaria isso de robô?

- O que significa a expressão "Babá de Script"?

- Por que não devo deixar esse código solto por aí?

 
Evandro Goncalves:

Não entendi, amigo.

- Por que não chamaria isso de robô?

- O que significa a expressão "Babá de Script"?

- Por que não devo deixar esse código solto por aí?

Seu código está cheio de furos.

Você não trata as exceções que podem ocorrer no Mercado, Corretora, Bolsa, Conexão com internet, etc...

Seu script é de alto risco... (de dar m*)

Pelo que li do seu código você assume que o Mercado/Bolsa/Internet é um Mar de Rosas...

;)

 
Flavio Jarabeck:

Seu código está cheio de furos.

Você não trata as exceções que podem ocorrer no Mercado, Corretora, Bolsa, Conexão com internet, etc...

Seu script é de alto risco... (de dar m*)

Pelo que li do seu código você assume que o Mercado/Bolsa/Internet é um Mar de Rosas...

;)

Flavio, pelo que percebi você é bastante experiente nessa linguagem de programação. Então, através do seu conhecimento, visto que faz apenas um mês e meio que comecei a aprender essa linguagem, poderia me ajudar a resolver esses dois problemas. Sendo o primeiro deles a minha dúvida inicial, que é desenvolver o martingale nesse meu código. O segundo é me ajudar a implementar o tratamento dessas exceções apontadas, pelo menos as mais importantes, ao menos me apresentando um artigo que explique como tratá-las. Obrigado.

 
Evandro Goncalves:

Flavio, pelo que percebi você é bastante experiente nessa linguagem de programação. Então, através do seu conhecimento, visto que faz apenas um mês e meio que comecei a aprender essa linguagem, poderia me ajudar a resolver esses dois problemas. Sendo o primeiro deles a minha dúvida inicial, que é desenvolver o martingale nesse meu código. O segundo é me ajudar a implementar o tratamento dessas exceções apontadas, pelo menos as mais importantes, ao menos me apresentando um artigo que explique como tratá-las. Obrigado.

@Evandro Goncalves,

Quando se vai desenvolver um robô deve-se pensar em situações de desconexão, problemas de sincronização de dados com a corretora, níveis mínimos de stop, se a corretora esta permitindo negociações automatizadas, gerenciamento de riscos, validações de conta, etc etc etc. A menor parte do código geralmente fica para a estrategia.

Neste sentido, procure não colocar um EA para rodar sem que o mesmo faca dezenas de verificações e tenha tratamento para cada uma delas. O alerta do Flavio eh relevante.

Mas quem pode definir o que vai avaliar e tratar eh você. Se, por exemplo,  acha que não deve tratar problemas de conexão de internet, o risco fica contigo.

Por outro lado, você menciona Martingale (não sei o que você entende por Martingale). Neste sentido, sugiro que leia a thread abaixo.

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

Martingale

Trader_Patinhas, 2019.05.07 11:41

@Rogerio Figurelli 

Não me parece difícil demonstrar, com base em estatística elementar, que, mesmo limitando perdas de diferentes formas, o retorno médio esperado do Martingale após um grande número de operações tende a se igualar ao retorno médio esperado da estratégia subjacente que estiver sendo utilizada para decidir o momento de entrar e de sair.

Portanto, para se ter um retorno médio esperado positivo no longo prazo(*) com Martingale, é necessário que a estratégia subjacente também tenha retorno médio esperado positivo no longo prazo(*).

(*) obs: eu uso o termo "longo prazo" aqui significando "após um número muito grande de operações", nada a ver com manter posição por longo prazo, ok?

Ou seja, Martingale não sobrevive ao princípio filosófico da Navalha de Occam, uma vez que o mesmo retorno de longo prazo pode ser alcançado pelo uso puro e simples da estratégia subjacente, com menor risco e menor capital imobilizado como margem para as operações.

Com relação às variantes que usam fatores de multiplicação diferentes de 2 ou que usam médias de volume, isso pode servir para diminuir o risco ou alavancar o lucro (conforme o fator/média usado), mas não me parece que isso altere o retorno médio esperado, por se tratarem de transformações lineares do método original, que obedecem ao princípio da superposição (homogeneidade + aditividade), de modo que o retorno do Martingale com fator modificado, ou mesmo com média de volume, será positivo se e somente se o retorno do Martingale com fator 2 (e consequentemente o da estratégia original subjacente) também for positivo, o que nos conduz à mesma conclusão anterior.

Pelo menos no daytrade de ações e de contratos futuros, cuja curva Lucro versus Variação do Preço é linear (desconsiderando custos operacionais), me parece que pode ser facilmente demonstrada a inexistência de vantagem de se usar Martingale, em comparação com usar a mesma estratégia que toma a decisão de entrar e de sair do mercado sozinha, sem Martingale.

Se eu tivesse mais tempo livre, tentaria escrever um artigo sepultando definitivamente essa ideia por "A mais B".

Um artigo assim seria um tiro no próprio pé, uma vez que, para nós, scalpers de tiro curto, a liquidez oferecida nos minicontratos pelos usuários de Martingale entrando forte no lado oposto de uma tendência que acabou de virar é um "chantilly" caído dos céus ... mas felizmente o meu lado humanitário, que não gosta de ver o meu próximo se ferrando, algumas vezes ofusca a minha ganância, de modo que ainda há esperança para a minha alma, kkk! 

Ressalva: num mercado não-linear, como o mercado de opções, talvez haja algum valor na estratégia Martingale, uma vez que a curva Lucro versus Variação do Preço (preço do ativo, e não da opção) é não-linear e pode-se operar tanto no lado convexo da curva (comprando opções) como no lado côncavo (vendendo opções) e também nos dois lados simultaneamente ... acho que vou pensar sobre isso ... alguém já pensou nisso? ... o problema é que daytrade de opções aqui no Brasil só é viável em ações muito líquidas como PETR e VALE, e mesmo assim só pra strikes bem pertinho do dinheiro, que é justamente a região em que a curva é quase linear e a operação fica semelhante a um daytrade de contratos futuros ... nos EUA talvez seja mais viável ... algum maluco aqui já pensou em fazer Martingale em opções? ... deve ser mais arriscado que escovar dente de crocodilo, mas, se puder ser demonstrado que o retorno de longo prazo é positivo, é só manter a mão pequena e ter paciência.


 
Evandro Goncalves:

Flavio, pelo que percebi você é bastante experiente nessa linguagem de programação. Então, através do seu conhecimento, visto que faz apenas um mês e meio que comecei a aprender essa linguagem, poderia me ajudar a resolver esses dois problemas. Sendo o primeiro deles a minha dúvida inicial, que é desenvolver o martingale nesse meu código. O segundo é me ajudar a implementar o tratamento dessas exceções apontadas, pelo menos as mais importantes, ao menos me apresentando um artigo que explique como tratá-las. Obrigado.

De novo, respondendo de uma maneira mais Politicamente Correta, já que levei uma reprimenda pela minha crueldade no meu post original,

Não, não vou te ajudar...

Você está vendendo um produto no Marketplace - QUE VOCÊ NÃO CRIOU,  segundo você - o que constitui um mega-amadorismo só para ganhar dinheiro. E, se os seus clientes precisarem de ajuda, e se o seu produto precisar de bug-fixing? O quê você vai dizer a eles??

Se você fosse um trader sério, você ganharia dinheiro com Trade, não com EAs...

E, se você fosse um desenvolvedor sério precisando de ajuda, eu te ajudaria...

Razão: