Auto-aprendizagem da linguagem MQL5 a partir do zero - página 52

 

Preste atenção ao filtro por símbolo e por feiticeiro no laço de posição. Se não houver filtro, mas você arrasta todas as posições abertas em todos os símbolos, e isto é ruim.

Portanto, à primeira vista, tudo parece estar bem.

Совершение сделок - Торговые операции - Справка по MetaTrader 5
Совершение сделок - Торговые операции - Справка по MetaTrader 5
  • www.metatrader5.com
Торговая деятельность в платформе связана с формированием и отсылкой рыночных и отложенных ордеров для исполнения брокером, а также с управлением текущими позициями путем их модификации или закрытия. Платформа позволяет удобно просматривать торговую историю на счете, настраивать оповещения о событиях на рынке и многое другое. Открытие позиций...
 
Andrei Novichkov:

Preste atenção ao filtro por símbolo e por feiticeiro no laço de posição. Se não houver filtro, mas você arrasta todas as posições abertas em todos os símbolos, e isto é ruim.

Portanto, tudo parece estar bem à primeira vista.

Muito obrigado, Andrey! Entendo tudo sobre Magia porque várias posições podem ser abertas para um símbolo, mas surgiu outra questão. O consultor especializado passará pelas posições abertas para todos os símbolos ao mesmo tempo, se não for explicitamente apontado para o símbolo atual? E isto apesar do fato de ser definido para um determinado par de moedas, por exemplo, EURUSD? Honestamente, não entendo bem este ponto.

Cumprimentos, Vladimir.

 
MrBrooklin:

Muito obrigado, Andrey! Entendo tudo sobre Magia, porque várias posições podem ser abertas em um símbolo, mas tenho outra pergunta. A EA passará pelas posições abertas para todos os símbolos ao mesmo tempo, se não for explicitamente apontada para o símbolo atual? E isto apesar do fato de ser definido para um determinado par de moedas, por exemplo, EURUSD? Honestamente, não entendo bem este ponto.

Atenciosamente, Vladimir.


Sim. É definido em todas as posições abertas para todos os símbolos.
De forma consistente para todas as posições em aberto.
Aqui está uma simples rede de arrasto no livro didático.

https://book.mql4.com/ru/build/trading
 
MrBrooklin:

Assim, com base na literatura lida, escrevi um pequeno algoritmo para criar um Expert Advisor com a função trailing stop:

  1. Vamos criar um Expert Advisor para automatizar o trabalho no nível de rastreamento (tracking) Stop Loss de posição já aberta com Take Profit e Stop níveis de perdasespecificados .
  2. No Expert Advisor, criar um bloco de parâmetros de entrada com dois parâmetros: definir "trailing level" e definir "trailing step".
  3. Quando novas citações chegarem, processe-as com a função OnTick( ). O trailing funciona somente quando um novo tick vem para o símbolo atual.
  4. Vamos criar e executar um loop para pesquisar todas as posições.
  5. Se de repente não encontrarmos posições abertas, voltamos ao laço
  6. Nós atualizamos as citações.
  7. Se houver uma posição aberta, nós continuamos.
  8. Definimos o tipo de uma posição aberta: Comprar ou Vender.
  9. Se houver uma posição decompraaberta , definimos onde o preço atual está localizado relativamente à posição aberta .
  10. Se o preço atual for superior ao preço ao qual a posição é aberta, verificamos em que nível ela subiu.
  11. Se o preço atual tiver alcançado o "nível de fuga" definido nos parâmetros de entrada, movemos oStop Loss para o nível sem a perda que é igual ao preço de abertura da posiçãoBuy. Caso contrário, não fazemos nada.
  12. Se o preço atual exceder o nível Trailing Stop pelo valor igual ao nívelTrailing Stop, oStop Perda é movido do nível de preço de abertura da posição Comprar pelo valor igual ao nível Trailing Stop e assim por diante até o preço atingir o nível Take Profit especificado para esta posição .
  13. Se o preço gira e atinge o nível deStop Perdajá movida , a posição é fechada .
  14. Se a posição forVenda, definimos onde o preço atual é relativo à posição aberta .
  15. Se o preço atual for inferior ao preço da posição aberta, verificamos em que nível ele caiu.
  16. Se o preço atual tiver alcançado o nível de resistência especificado nos parâmetros de entrada, movemos Stop Loss para o nível sem a perda igual ao preço de abertura da posiçãoSell. Caso contrário, não fazemos nada.
  17. Se o preço atual exceder o nível Trailing Stop pelo valor igual ao nívelTrailing Stop, oStop Perda é movido do nível de abertura da posição Sell pelo valor igual ao nível Trailing Stop e assim por diante até o preço atingir o nível Take Profit especificado para aquela posição .
  18. Se o preço gira e atinge o nível deStop Loss, a posição é fechada .

Por favor, revise o algoritmo e me dê algumas dicas sobre os pontos que faltaram.

Atenciosamente, Vladimir.

A teoria não é ruim, agora vamos nos concentrar na prática. Será que vai funcionar?

 
Aliaksandr Hryshyn:

A teoria não é ruim, agora a prática. Você pode fazer isso?

Vou tentar. Mas você entende que isto requer um nível de conhecimento totalmente diferente, e eu ainda não o tenho.

Cumprimentos, Vladimir.

 
Aleksey Masterov:

Sim. Em todas as poses abertas em todos os símbolos...
De forma consistente em todas as poses abertas.
Aqui está uma simples rede de arrasto já no livro didático.

https://book.mql4.com/ru/build/trading

Sim, Alexey, eu já vi este código. Está na forma de um arquivo de inclusão. Para ser honesto, eu não encontrei nada sobre o símbolo nele, embora o tenha visto várias vezes. Talvez eu tenha entendido mal alguma coisa ou esteja apenas procurando mal.

Atenciosamente, Vladimir.

 

Por enquanto, vamos continuar com as funções.

Como escrevi anteriormente, as funções estão em todos os lugares, você tem que amá-las e saber escrevê-las. Funções, são nossos pequenos combatentes na solução de problemas globais. Se fôssemos generais em um exército, que tipo de combatentes queríamos controlar? Aqui está uma lista aproximada:

  • Um lutador deve executar claramente uma ordem. O nível médio de inteligência de um soldado de infantaria não é grande coisa. Portanto, é melhor estabelecer objetivos claros e simples para tais lutadores: "pegar um bunker", "pegar uma língua", "minar uma ponte".
  • Se a tarefa for difícil, não procure um lutador super inteligente para realizá-la. É melhor dividir a tarefa em várias subtarefas e levar dois ou três lutadores mais estúpidos, mas mais eficientes. Que todos resolvam suas subtarefas sem nenhuma pergunta, ou melhor ainda, que ignorem o conceito e a tarefa como um todo. Então, se alguém for feito prisioneiro, isso não será um problema, o plano inteiro não será revelado.
  • Um soldado deve seguir a ordem independentemente do entorno: neve, chuva, Paris e mulheres - se esse entorno não tiver efeito na implementação da ordem, então essas condições e o ambiente externo devem ser ignorados.
  • Acontece que as tarefas podem ser difíceis. Eles exigem muitos lutadores para resolvê-los. Um general não pode ser designado a cada lutador. Em vez disso, você deve designar um soldado mais esperto para liderar vários combatentes. Este grupo, por sua vez, se une ao mesmo numa empresa de soldados e os nomeia um oficial superior.

Mas nos desviamos, vamos passar novamente às funções.

Se uma função resolve muitos problemas em geral - seguindo a analogia, é um lutador muito inteligente que, se algo der errado com ela, pode arruinar todo o empreendimento. Se você perguntar o que tal função faz, a resposta pode ser longa. Se o resultado desta função de repente deixar de ser correto, será muito difícil descobrir o que causa um erro nela (porque há muitas tarefas, muito código, muitas chamadas a sub-esquemas e onde exatamente o erro é difícil de entender).

Se uma função calcula resultados corretos às segundas, quartas e domingos e nos dias de descanso dependendo de nosso "humor", podemos contar com esta função? Imagine que a função OrderSend, digamos, abre posições apenas às quintas-feiras e se algum parâmetro mágico 13 for definido. E isto não é nenhum disparate ou fantasia. Este comportamento pode ser organizado com um clique de dedos - é suficiente para tornar a função dependente de alguns parâmetros no ambiente externo.

Suponha a função:

double sum(double a, double b)
{
   return a+b;
}

sempre retornará a soma de dois valores, independentemente do ambiente externo. Isso significa que mesmo se copiarmos essa função em outro roteiro ou consultor especializado, ela funcionará perfeitamente lá. Esta função pode ser escrita uma vez e utilizada em muitos de nossos programas através de uma simples cópia obtusa. Sempre poderemos confiar em seu resultado sabendo que seu funcionamento não depende de nada. Tais funções, cujo resultado não depende de seu ambiente, são chamadas de funções sem efeitos colaterais ou puras. Se nos esforçarmos para escrever funções puras, logo teremos muitas delas. Isto significa que você pode combiná-los em um arquivo e incluí-los em seus novos projetos. Isto é chamado de reutilização de código. Nós não fazemos o trabalho duas vezes. Em vez disso, usamos funções já escritas que conhecemos, e cuja confiabilidade foi testada mais de uma vez.

Vejamos agora o anti-exemplo:

double c = 0.0;
double sum(double a, double b)
{
   return a+b+c;
}

O resultado parece ser o mesmo, porque c é sempre zero. Ou nem sempre é assim? E se alguém mudar c em algum lugar? O que então? E se alguém em algum lugar também usar a variável externa c, mas para seus próprios fins, e ele tiver uma variável c de um tipo diferente, digamos, string? A combinação destas duas funções não é mais possível (o compilador não permitirá declarar duas variáveis com o mesmo nome). Suas dependências comuns também são difíceis de resolver. Eu não sei o que fazer com isso. Por exemplo, eu ainda não conheço uma maneira confiável e fácil de fazer tais funções funcionarem em conjunto.

Mesmo que não haja outra função e apenas uma função leia uma variável externa, não é tão fácil copiá-la em outro lugar. Temos que copiar tanto esta função quanto sua dependência. Mas e se copiarmos essas funções para um arquivo comum? Temos 50 ou 100 dessas funções lá. E cada um deles copia com si mesmo um amontoado de suas próprias variáveis dependentes. Obtemos um emaranhado de variáveis relacionadas com funções pouco claras. Mas para que serve tudo isso? Que problemas são resolvidos? Por que criar dependências desnecessárias quando você pode passar sem elas na grande maioria dos casos?

As funções têm mais uma característica surpreendente. As funções são auto-descritivas. Em outras palavras, você não precisa desenhar um esquema, apenas escolher bons nomes e dividir o algoritmo geral em funções. Aqui está um exemplo:

void OnTick()
{
   if(SelectFirstPendingOrder(ORDER_TYPE_BUY))
       CancelSelectPendingOrder();
}

Eu não sei o que este código faz, porque as funções nem sequer estão escritas. Mas se eu o lesse, provavelmente significaria que se a primeira <primeira> ordem pendente com direção ORDER_TYPE_BUY for selecionada com sucesso, ela seria cancelada (a primeira função seleciona, a segunda cancela). Uma vez que o código seria executado a cada tick, não importa quantas ordens pendentes houvesse, cada uma seria cancelada mais cedo ou mais tarde. Isto também significa que qualquer tentativa de colocar uma ordem de compra pendente seria suprimida - a ordem seria imediatamente removida. Ao mesmo tempo, os pedidos de venda serão feitos sem nenhum problema.

Há apenas duas linhas de código e duas funções. E o algoritmo é não trivial, e o que é mais importante, é confiável.

Ao falar do MCL, devemos mencionar um pouco mais sobre funções puras. Por ser uma linguagem de aplicação, é difícil escrever qualquer coisa sem contar com os dados fornecidos pelo terminal. Afinal de contas, esta é a tarefa principal: interagir adequadamente com o ambiente comercial. Formalmente, qualquer ambiente de negociação é mutável: preços, número de ordens, mudanças de saldo, etc., etc. Portanto, qualquer função que interaja com tal ambiente comercial mutável não é clara. Porque o ambiente comercial externo também pode ser considerado como alguma variável global, que está em constante mudança. Mas quando escrevemos OrderTotal(), não esperamos que esta função retorne sempre o mesmo valor. Em vez disso, esperamos que ele devolva o número de ordens pendentes que naturalmente variarão. Portanto, na MQL, consideraremos as funções como limpas e reutilizáveis, mesmo no caso de chamarem funções de API externas, como OrderTotal(). Será nossa razoável indulgência.

 
Vasiliy Sokolov:

Vamos continuar com as funções...

Muito obrigado, Vasily, pelo conhecimento inestimável que você compartilha não só comigo, mas também com aqueles programadores novatos que lêem ou vão ler este tópico!

Com o mesmo grande respeito, Vladimir.

 

Eu continuo estudando a linguagem de programação MQL5. Embora não tenha havido comentários sérios sobre o algoritmo de escrita de código do Trailing_Stop Expert Advisor (lembro-me do símbolo e da Magic, vou adicioná-lo ao algoritmo mais tarde!), criei parâmetros de entrada para a EA e escrevi o código do laço que inicia a busca de posições abertas.

Quando eu executei o EA, vi um problema - na aba "Experts" do terminal de negociação 2 mensagens idênticas "A loop has started" aparecem em cada tick, apesar do fato de o terminal de negociação ter apenas um gráfico do par de moedas EURUSD e apenas uma posição é aberta nele. E estas mensagens têm o mesmo tempo exato de saída.

Lutei até a meia-noite, mas não consegui vencer. Eu não consigo entender qual é o problema.


O código do Expert Advisor é escrito em inglês, enquanto os comentários são em russo, a fim de facilitar o processo. Neste EA, tentei descrever tudo, como prometi anteriormente, de forma compreensível para um aluno da 1ª série de uma escola de programação.

Cumprimentos, Vladimir.

//+------------------------------------------------------------------+
//|                                                Trailing_Stop.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

input ushort TrailingLevel=100; //Уровень трейлинга (для включения)
input ushort TrailingStep=10;   //Шаг трейлинга (для перемещения)
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   /* Для цикла for создаем локальную переменную i и присваиваем ей значение "торговая функция PositionsTotal",
      которая возвращает нам количество открытых позиций*/
   int i=PositionsTotal();
   /* Разберемся, что такое оператор for.
      Оператор for состоит из трех Выражений и выполняемого Оператора:
      for(Выражение_1; Выражение_2; Выражение_3)
         Оператор;
      Выражение_1 описывает инициализацию цикла. За инициализацию цикла будет отвечать "Торговая функция PositionsTotal".
      Выражение_2 проверяет условия завершения цикла. Если оно истинно, то выполняется Оператор в теле цикла for.
      Все повторяется до тех пор, пока Выражение_2 не станет ложным. Если оно ложно, цикл заканчивается
      и управление передается следующему оператору.
      Выражение_З вычисляется после каждой итерации (т.е. после каждого повторения действия).
   */
   for(i; i>=0; i--) //запускаем цикл перебора открытых позиций (i) от максимума до нуля (i>=0) с шагом минус 1 (i--)
      Print("Запущен цикл");
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---

  }
//+------------------------------------------------------------------+
 
MrBrooklin:


i iguala o número de posições abertas, tantos ciclos serão com impressão

Print("Запущен цикл");
você precisa remover o sinal "=" em
   for(i; i>=0; i--)
por que você precisa passar pelo loop quando o número de posições abertas é 0. esta chamada zero é de onde está vindo a segunda impressão
Razão: