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

 
MrBrooklin:

Igor, o desejo de aprender a linguagem MQL5 não se perde, pelo contrário, ele só aumenta. Estou dividido, por que sou tão burro e não consigo entender coisas simples com este operador de laço. O principal é que sem o operador do laço o código funciona perfeitamente, mas com o laço é uma confusão completa. De qualquer forma, vou chegar ao fundo disto. No entanto, tenho muito menos tempo para o auto-estudo desde que o período de quarentena terminou e tenho raros momentos para estudar a língua no trabalho. Na maioria das vezes estudo a língua à noite e à noite.

Preciso resolver 2 tarefas para finalmente escrever o código de Trailing Stop:

  1. Preciso escrever um código com o uso do operador de laço para procurar todas as posições abertas para todos os símbolos, e se não houver nenhuma, então abra uma posição Buy no intervalo das 09:00:00 às 09:01:00, e às 23:50:00 feche-a à força, se durante o dia de negociação não tiver disparado uma stop loss. Sem o operador de laço, como escrevi antes, tudo funciona perfeitamente. Agora eu quero alcançar o mesmo resultado, mas com o uso de loop.
  2. Escreva 2 funções que determinam a direção da abertura da posição pelo primeiro tique que aparece no horário das 09:00:00 às 09:01:00. Se o primeiro tick for para cima, a posição Comprar deve abrir; se o primeiro tick for para baixo, a posição Vender deve abrir de acordo. Não é uma estratégia, é apenas minha "vontade" de não usar a condição aleatória.
Atenciosamente, Vladimir.

Vladimir, você está se metendo em algum tipo de coisa estranha. Foi-lhe dado um modelo: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 Você o ignorou e decidiu seguir em frente com sua perspicácia. Este caminho é difícil e pode levar anos. Em seu caminho, estude C, C++, Ferrugem, C#, polimorfismo, herança, desreferenciamento de ponteiros, conversão dinâmica do tipo: Verificar ou dirigir. Você deve tomar o caminho mais curto para o objetivo. Se você quiser seguir em frente, escreva "trailing". Não é necessário estudar C e C++ para fazer isso. Tudo isso como uma opção eletiva, se você tiver vontade.

A situação com o for loop é ilustrativa. É uma construção poderosa que deve ser aplicada no lugar certo. Você tem uma rede e um algoritmo auxiliar. É por isso que não há enumeração de posições, não há magos, então você não tem este laço. Claro, tudo funcionará sem ele, mas o laço só produz óleo. Mas você teimosamente tenta usá-lo, parece ser um fim em si mesmo: usar o máximo e o máximo possível, ter o máximo possível.

 
Vasiliy Sokolov:

Vladimir, você está entrando em uma espécie de cio. Foi-lhe dado um modelo: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 Você o ignorou e decidiu ir em frente com sua mente. Este caminho é difícil e pode levar anos. Em seu caminho, estude C, C++, Ferrugem, C#, polimorfismo, herança, desreferenciamento de ponteiros, conversão dinâmica do tipo: Verificar ou dirigir. Você deve tomar o caminho mais curto para o objetivo. Se você quiser seguir em frente, escreva "trailing". Não é necessário estudar C e C++ para fazer isso. Tudo isso como uma opção eletiva, se você quiser.

A situação com o for loop é ilustrativa. É uma construção poderosa que deve ser aplicada no lugar certo. Você tem uma rede e um algoritmo auxiliar. É por isso que não há enumeração de posições, não há magos, então você não tem este laço. Claro, tudo funcionará sem ele, mas o laço só faz você se sentir como óleo. Mas você está tentando obstinadamente usá-lo, então parece ser um fim em si mesmo: você pode usar o máximo de tudo e qualquer coisa para manter em estoque o máximo possível.

Olá, Vasily!

Obrigado por se juntar oportunamente ao tema e me orientar da maneira correta como sempre. Agora deixe-me explicar tudo em uma só ordem:

  1. Um modelo no Expert Advisor foi inserido exatamente quando você gentilmente me forneceu, pelo qual quero expressar minha gratidão!
  2. Decidi que um EA com Trailin Stop deveria ser testado no testador de estratégia, mas não sabia como fazê-lo sem abrir automaticamente pelo menos uma posição. É por isso que comecei a me sentir ansioso ao escrever um Consultor Especialista "de pleno direito". Coloquei-o entre aspas porque meu consultor especializado não tem estratégia como tal. Eu simplesmente não queria usar a condição aleatória para abrir uma posição.
  3. Nenhum dos interlocutores do Expert Advisor, exceto você, sugeriu que o loop para procurar posições nesta situação não é necessário. Minha culpa, eu mesmo poderia ter adivinhado há muito tempo e perguntado - era realmente necessário um loop? Como acabou, você não tem. Mais uma vez obrigado pela dica!
  4. Para finalmente ir escrever a parada móvel e não abandonar o processo na metade do caminho, preciso apenas escrever o código de 2 funções que determinam a direção de abertura de uma posição de compra ou venda de uma rede.
  5. Sim, concordo plenamente com você que o auto-estudo está começando a se arrastar. Mas se levarmos em conta que sigo um caminho inexplorado e tortuoso, espero que seja possível fazer um desconto.
  6. Durante todo o período de auto-estudo eu tenho uma enorme quantidade de informações e agora estou tentando não apenas organizá-las, mas também utilizá-las na prática. Para este fim, eu baixei um Expert Advisor da CodeBase, o desenvolvi e o usei por quinze dias em uma conta de demonstração de um negociante Forex. O resultado é exatamente o que eu esperava. Em breve começarei a usá-lo em uma conta real. Isto já é uma vantagem!
  7. Eu não persigo a velocidade do auto-estudo porque já escrevi anteriormente que o excesso de informação de tempos em tempos vem estupor.
  8. Durante todo o período de auto-estudo, pouco a pouco, começou a memorizar palavras e frases em inglês que aparecem após o código de compilação. Agora olho no Google Translate com menos freqüência. Este é também um momento positivo no auto-estudo.
  9. Colocarei tudo o que escrevi no Expert Advisor exatamente quando uma peça completa de trabalho para uma parada de trilha estiver pronta. Vou tentar terminá-lo no sábado. É aqui que começará o trabalho principal de redação do código de parada móvel.

Vasily, sou extremamente grato a você pela orientação e crítica construtiva! Também expresso minha gratidão a todos os participantes deste tema que me ajudam em meu auto-estudo da linguagem de programação MQL5 a partir do zero.

O auto-aprendizagem continua. A ser continuado.

Cumprimentos, Vladimir.

 
Андрей:

Boa tarde a todos!

Se eu quisesse acrescentar algo interessante, acho que a idéia de "auto-treinamento em MQL5 a partir do zero" não é muito correta. Se uma pessoa é um 0 na programação, ela tem que aprender a programar primeiro. Se o objetivo é aprender a programar em MQL do zero, uma pessoa deve primeiro aprender aprogramar em C, pelo menos o básico, e depois aprender a escrever em MQL, porque MQL é de fato C, mas é especializado para uma determinada tarefa, uma pessoa não entende como funcionam os loops, e já está tentando escrever programas. É como tentar aprender latim sem saber russo...

Outra coisa é que C não é uma linguagem muito amigável para aprender programação, é simples, mas é muito concisa, é difícil para um iniciante ler e entender código sem ter um entendimento básico de algoritmos, tipos de dados, álgebra booleana. Em C três caracteres seguidos podem significar várias cadeias de caracteres em outra linguagem.

Para aprender a programar simplesmente do zero, para a base, para aprender a falar com um computador em uma (não importa o que) língua, eu aconselharia começar com Pascal, o livro mais fácil para começar com ele (2-3 semanas à vontade), depois C (lá após Pascal semana máxima se diligente, dominar a sintaxe, quero dizer o conhecimento básico da língua!) e, em seguida, utilizar idiomas especializados como MQL, porque MQL é C, que tem um pouco de torção e simplificação, uma vez que foi projetado para uma única tarefa e o compilador conhece o óbvio. E C, por sua vez, é uma espécie de Pascal comprimido RAR, mas Pascal é quase inglês =).

Agora sobre loops:

Quando aprendi a programação, a analogia com somas em álgebra me ajudou, onde você especifica o valor inicial de n, o valor final de n e a fórmula com este n para calcular.

Olá Andrey, concordo plenamente com você sobre a base. Eu não o tenho e nunca o tive. Mas como diz o ditado - Moscou não foi construída de uma só vez! Obrigado por seus conselhos e dicas!

Cumprimentos, Vladimir.

 
Roman Shiredchenko:

Sim. Eu concordo - seus códigos também são bons! Você está se irritando por nada. Leve seu tempo para ordenar o código sem pressa e pronto. Aqui está uma coisa elementar - selecionar e arrasto: (quanto mais fácil - apenas seu tópico de escolha da posição NECESSIDADE... :-))

Além disso, inclua arquivos - significa que eles também estão em seu código como funções e é isso.

Obrigado, Roman, pelos códigos e links! Estou lidando com os códigos com calma e certamente não se apresse em nenhum lugar!

Atenciosamente, Vladimir.

 

Bom dia e bom humor a todos!

Continuo estudando a linguagem de programação MQL5 . Hoje, como prometido, estou postando para que todos vejam o código do template do Expert Advisor projetado para escrever um trailing stop. Devido ao fato de que o código do modelo do EA acabou sendo bastante complicado, tivemos que reduzir os comentários o máximo possível. A versão completa do Expert Advisor com comentários detalhados sobre cada linha de código, em uma apresentação acessível a um aluno do 1º ano de uma escola de programação, será publicada posteriormente na forma de um arquivo com o nome de trabalho Trailing_Stop.mq5 para que para não produzir outra "panela" no site.

Antes de publicar o código, o EA foi testado no testador de estratégia . Nenhum problema foi identificado. O EA usa um sistema de contabilidade de posição de compensação. Este sistema de contabilidade implica que ao mesmo tempo só pode haver uma posição aberta na conta para o mesmo símbolo (instrumento financeiro).

No momento, o EA tem a capacidade de:

  1. Verifique a conta de negociação na qual está planejado instalá-lo. Se o consultor estiver instalado em uma conta demo, a permissão para continuar trabalhando aparecerá na janela de mensagem. Se for feita uma tentativa de instalar o consultor em uma conta real , aparecerá um aviso na janela de mensagem sobre a impossibilidade de continuar o trabalho, após o que será excluído automaticamente da janela de trabalho do terminal de negociação .
  2. Uma vez por dia de negociação exatamente às 9h. de acordo com o horário de Moscou, abra automaticamente uma posição na direção para onde o primeiro tick será direcionado. Por exemplo, se às 9h. Horário de Moscou, o primeiro tick será direcionado para cima, o que significa que uma posição de COMPRA será aberta, se o primeiro tick estiver para baixo, uma posição de VENDA será aberta.
  3. Defina o tamanho da perda de parada.
  4. Defina o tamanho do lote.
  5. Defina outros parâmetros que serão necessários para que o stop móvel funcione.

Além disso, o EA possui um template pré-instalado, gentilmente cedido por Vasily Sokolov, que será preenchido com código durante o processo de autoaprendizagem.

UM AVISO!!!

O Expert Advisor é desenvolvido de acordo com o plano de autoestudo para uma conta demo e apenas para fins educacionais! Não se destina a negociar em uma conta real e obter lucro!

Com os melhores 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 description "Советник создан для демо-счёта исключительно в учебных целях!"
#property description "Не предназначен для торговли на реальном счёте и извлечения прибыли!"
#property version      "1.00"
/* Краткое описание советника Trailing_Stop. Код советника разрабатывается в соответствии с
   планом самообучения языку программирования MQL5. В советнике применена неттинговая система
   учёта позиций. Эта система учета подразумевает, что в один момент времени на счете может быть
   только одна открытая позиция по одному и тому же символу (финансовому инструменту). Алгоритм
   работы советника прост: один раз в торговый день ровно в 9 ч. 00 мин. по московскому времени
   будет открываться одна позиция в ту сторону, куда будет направлен первый тик. Например, если
   первый тик будет направлен вверх, то значит откроется позиция BUY, если первый тик будет вниз,
   то значит откроется позиция SELL. У открытой позиции сразу будет устанавливаться ордер Stop Loss
   фиксированного размера для минимизации потерь в том случае, если цена финансового инструмента
   станет двигаться в убыточном направлении. Если цена инструмента достигнет этого уровня, то
   позиция полностью закроется автоматически. Если цена финансового инструмента будет двигаться
   в прибыльном направлении, то тогда автоматически включится в работу Trailing_Stop (Трейлинг Стоп).
   Схема работы Трейлинг Стоп:
   1. С приходом новых котировок советник проверяет, прибыльна ли открытая позиция.
   2. Как только прибыль (в пунктах) станет равной либо большей той величины, которая указана во
      входном параметре советника "Уровень перестановки Stop Loss в безубыток", автоматически
      поступит команда для перемещения ордера Stop Loss на тот уровень цены, по которому открылась
      существующая позиция, т.е. в безубыток.
   3. Если цена и дальше продолжит движение с увеличением прибыльности позиции, то при превышении
      величины, указаной во входном параметре советника "Уровень перестановки Stop Loss в безубыток"
      на величину, которая указана во входном параметре "Шаг трейлинг стопа", Stop Loss вслед за
      текущей ценой автоматически переместится с уровня безубытка на величину этого шага.
   4. Если прибыльность позиции уменьшится, то модификации ордера происходить не будет. Таким
      образом, будет автоматически фиксироваться прибыль торговой позиции.
   Если в течении торгового дня открытая позиция не закроется по Stop Loss или Trailing_Stop, то в
   23 ч. 50 мин. советник принудительно закроет эту позицию.

   ВАЖНО!!! Советник создан для демо-счёта исключительно в учебных целях!
            Не предназначен для торговли на реальном счёте и извлечения прибыли!*/

//--- Создадим входные параметры советника
input ushort BreakevenLevel= 100 ; //Уровень перестановки Stop Loss в безубыток
input ushort TrailingStop= 10 ;     //Шаг трейлинг стопа
input ushort SL= 200 ;             //Стоп-лосс
input double Lot= 0.1 ;             //Лот
input long    Magic_Number= 3215 ;   //Магический номер
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
/* Функция инициализации советника OnInit с типом данных int. Если возвращаемое значение для функции
   return(-1), то это "неудачная инициализация". Если возвращаемое значение для функции return(0), то
   это "удачная инициализация". INIT_SUCCEEDED означает, что инициализация прошла успешно и дальше
   можно продолжать тестирование эксперта. Этот код означает то же самое, что и нулевое значение, т.е.
   "удачная инициализация".
*/
int OnInit ()
  {
//--- Определим тип счёта на который устанавливаем советник: демо или реальный счет
   ENUM_ACCOUNT_TRADE_MODE account_type=( ENUM_ACCOUNT_TRADE_MODE ) AccountInfoInteger ( ACCOUNT_TRADE_MODE );
//--- теперь превратим значение перечисления в понятный вид
   string trade_mode;               //создадим переменную для торгового режима
   /* Создадим оператор-переключатель switch, который cравнивает значение выражения с константами во всех
      вариантах case и передает управление оператору с соответствующим значением выражения.*/
   switch (account_type)
     {
       case ACCOUNT_TRADE_MODE_DEMO : //если ключевое слово ACCOUNT_TRADE_MODE_DEMO
         trade_mode= "Счёт DEMO" ;     //значит торговый режим счёта - демо
         break ;                     //оператор break прекращает выполнение ближайшего оператора switch
       case ACCOUNT_TRADE_MODE_REAL : //если ключевое слово ACCOUNT_TRADE_MODE_REAL
         trade_mode= "Счёт REAL" ;     //значит торговый режим счёта - реальный
         break ;                     //оператор break прекращает выполнение ближайшего оператора switch
     }
   if (account_type== ACCOUNT_TRADE_MODE_REAL ) //если торговый режим счёта - реальный
     {
       //--- выводим окно сообщений на торговом терминале и закрываем советник
       MessageBox ( "Работа на реальном счете запрещена, выходим!" , "Советник запущен на реальном счете" );
       return (- 1 ); //возвращаем для функции OnInit ненулевое значение означающее "неудачная инициализация"
     }
   if (account_type== ACCOUNT_TRADE_MODE_DEMO ) //если торговый режим счёта - демо
     {
       //--- выводим окно сообщений на торговом терминале и продолжаем работу советника
       MessageBox ( "Работа на демо-счете разрешена!" , "Советник запущен на демо-счете" );
       return ( 0 ); //возвращаем для функции OnInit нулевое значение означающее "удачная инициализация"
     }
   return ( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit ( const int reason)
  {
//--- сообщим код завершения работы эксперта
   Print ( __FILE__ , ": Код причины деинициализации = " ,reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick ()
  {
//--- Зададим время открытия и закрытия позиции
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct ( TimeCurrent (),time_current);
   TimeToStruct (( D'1970.01.01 09:00:00' ),time_open);
   TimeToStruct (( D'1970.01.01 09:01:00' ),time_open1);
   TimeToStruct (( D'1970.01.01 23:50:00' ),time_close);
//--- Зададим условия для открытия позиций BUY и SELL   
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   price= NormalizeDouble (price,digits);
   if ( PositionSelect ( Symbol ())== false
      && PositionGetInteger ( POSITION_MAGIC )!=Magic_Number
      && time_current.hour==time_open.hour
      && time_current.min>=time_open.min
      && time_current.min<time_open1.min
      && (TickUP()==(price+point)))
     {OpenBUY();}
   else
     {
       if ( PositionSelect ( Symbol ())== false
         && PositionGetInteger ( POSITION_MAGIC )!=Magic_Number
         && time_current.hour==time_open.hour
         && time_current.min>=time_open.min
         && time_current.min<time_open1.min
         && (TickDOWN()==(price-point)))
        {OpenSELL();}
     }
   if (time_current.hour==time_close.hour && time_current.min==time_close.min)
      CloseALL();

//+------------------------------------------------------------------+
//| Шаблон трейлинг стопа предоставленный Василием Соколовым         |
//+------------------------------------------------------------------+

//-- Выбираем позиции по текущему символу. Если позиции нет и выбирать нечего, то выходим!
   if (! PositionSelect ( Symbol ()))
       return ;
//-- Стоп-лосс длинной позиции переставляем в безубыток и тралим его
   if ( PositionGetInteger ( POSITION_TYPE ) == POSITION_TYPE_BUY )
     {
      SetBreakevenForBuyPosition(); // установить безубыток для Buy позиции
      TrailingStopLossForBuyPosition(); // перетащить Stop Loss для Buy позиции
     }
//-- Стоп-лосс короткой позиции переставляем в безубыток и тралим его
   else
       if ( PositionGetInteger ( POSITION_TYPE ) == POSITION_TYPE_SELL )
        {
         SetBreakevenForSellPosition(); // установить безубыток для Sell позиции
         TrailingStopLossForSellPosition(); // перетащить Stop Loss для Sell позиции
        }
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer ()
  {
//---

  }
//+------------------------------------------------------------------+
//| Buy Position Open function                                       |
//+------------------------------------------------------------------+

//--- Создадим функцию для открытия позиции Buy и назовём её OpenBUY
void OpenBUY()
  {
//--- Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request= { 0 };
   MqlTradeResult result= { 0 };
//--- Создадим переменные необходимые для работы с сервером
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   request.action= TRADE_ACTION_DEAL ;
   request.symbol= Symbol ();
   request.volume=Lot;
   request.deviation= 2 ;
   request.magic=Magic_Number;
   request.type= ORDER_TYPE_BUY ;
   request.price= NormalizeDouble (price,digits);
   /*Создадим запрос на торговый сервер request.sl, в котором укажем, где должен находиться уровень
     стоп лосс относительно цены, по которой открылась позиция "BUY". Уровень SL должен находиться
     ниже цены, поэтому пишем price-SL*point. Для нормализации уровня SL применим функцию преобразования
     данных NormalizeDouble, где обязательно умножим уровень SL на point (размер одного пункта) и укажем
     digits(количество знаков после запятой).
   */
   request.sl= NormalizeDouble (price-SL*point,digits);
   if (! OrderSend (request,result))
       PrintFormat ( "OrderSend error %d" , GetLastError ());
   PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
  }
//+------------------------------------------------------------------+
//| Sell Position Open function                                      |
//+------------------------------------------------------------------+

//--- Создадим функцию для открытия позиции Sell и назовём её OpenSELL
void OpenSELL()
  {
//--- Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request= { 0 };
   MqlTradeResult result= { 0 };
//--- Создадим переменные необходимые для работы с сервером
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   request.action= TRADE_ACTION_DEAL ;
   request.symbol= Symbol ();
   request.volume=Lot;
   request.deviation= 2 ;
   request.magic=Magic_Number;
   request.type= ORDER_TYPE_SELL ;
   request.price= NormalizeDouble (price,digits);
   /*Точно также создадим запрос на торговый сервер request.sl, в котором укажем, где должен
     находиться уровень стоп лосс относительно цены, по которой открылась позиция "SELL".
     Уровень SL теперь должен находиться выше цены, поэтому пишем price+SL*point. Снова для
     нормализации уровня SL применим функцию преобразования данных NormalizeDouble, где обязательно
     умножим уровень SL на point (размер одного пункта) и укажем digits(количество знаков после запятой).
   */
   request.sl= NormalizeDouble (price+SL*point,digits);
   if (! OrderSend (request,result))
       PrintFormat ( "OrderSend error %d" , GetLastError ());
   PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
  }
//+------------------------------------------------------------------+
//| All Position Close function                                      |
//+------------------------------------------------------------------+

//--- Создадим функцию для закрытия всех позиций и назовем её CloseALL
void CloseALL()
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request;
   MqlTradeResult   result;
//--- перебираем все открытые позиции
   for ( int i= PositionsTotal ()- 1 ; i>= 0 ; i--)
     {
       //--- определяем параметры
       ulong   ticket= PositionGetTicket (i);                                             // тикет позиции
       string symbol= PositionGetString ( POSITION_SYMBOL );                               // символ
       int     digits=( int ) SymbolInfoInteger (symbol, SYMBOL_DIGITS );                     // количество знаков после запятой
       ulong   magic= PositionGetInteger ( POSITION_MAGIC );                               // MagicNumber позиции
       double volume= PositionGetDouble ( POSITION_VOLUME );                               // объем позиции
       ENUM_POSITION_TYPE type=( ENUM_POSITION_TYPE ) PositionGetInteger ( POSITION_TYPE ); // тип позиции
       //--- выводим информацию о позиции
       PrintFormat ( "#%I64u %s  %s  %.2f  %s [%I64d]" ,
                  ticket,
                  symbol,
                   EnumToString (type),
                  volume,
                   DoubleToString ( PositionGetDouble ( POSITION_PRICE_OPEN ),digits),
                  magic);
       //--- если MagicNumber совпадает
       if (magic==Magic_Number)
        {
         //--- обнуляем значения запроса на сервер и результата ответа
         ZeroMemory (request);
         ZeroMemory (result);
         //--- устанавливаем параметры операции
         request.action   = TRADE_ACTION_DEAL ;   // тип торговой операции (немедленное исполнение)
         request.position =ticket;               // тикет позиции
         request.symbol   =symbol;               // символ
         request.volume   =volume;               // объём позиции
         request.deviation= 2 ;                   // допустимое отклонение от цены
         request.magic    =Magic_Number;         // MagicNumber позиции
         if (type== POSITION_TYPE_BUY )             // если тип позиции "покупка"
           {
             //--- запрашиваем лучшее предложение цены на "продажу" по текущему символу
            request.price= SymbolInfoDouble (symbol, SYMBOL_BID );
             //--- запрашиваем тип рыночного ордера на "продажу" и закрываем позицию встречным ордером
            request.type = ORDER_TYPE_SELL ;
           }
         else // в противном случае
           {
             //--- запрашиваем лучшее предложение цены на "покупку" по текущему символу
            request.price= SymbolInfoDouble (symbol, SYMBOL_ASK );
             //--- запрашиваем тип рыночного ордера на "покупку" и закрываем позицию встречным ордером
            request.type = ORDER_TYPE_BUY ;
           }
         //--- выводим информацию о закрытии
         PrintFormat ( "Close #%I64d %s %s" ,ticket,symbol, EnumToString (type));
         //--- отправляем запрос
         if (! OrderSend (request,result))
             PrintFormat ( "OrderSend error %d" , GetLastError ());   // если отправить запрос не удалось, выводим код ошибки
         //--- информация об операции
         PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
         //---
        }
     }
  }
//+------------------------------------------------------------------+
//| Tick Up function                                                 |
//+------------------------------------------------------------------+
double TickUP()
  {
//---
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   double price1= NormalizeDouble (price+point,digits);
   return (price1);
  }
//+------------------------------------------------------------------+
//| Tick DOWN function                                               |
//+------------------------------------------------------------------+
double TickDOWN()
  {
//---
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   double price2= NormalizeDouble (price-point,digits);
   return (price2);
  }
  
//+------------------------------------------------------------------+
//| Шаблон трейлинг стопа предоставленный Василием Соколовым         |
//+------------------------------------------------------------------+
  
//+------------------------------------------------------------------+
//| Устанавливает sl позиции BUY в безубыток                         |
//+------------------------------------------------------------------+
void SetBreakevenForBuyPosition() // установить безубыток для Buy позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Тралит стоп-лосс позиции BUY вслед за ценой                      |
//+------------------------------------------------------------------+
void TrailingStopLossForBuyPosition() // перетащить Stop Loss для Buy позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Устанавливает sl позиции SELL в безубыток                        |
//+------------------------------------------------------------------+
void SetBreakevenForSellPosition() // установить безубыток для Sell позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Тралит стоп-лосс позиции SELL вслед за ценой                     |
//+------------------------------------------------------------------+
void TrailingStopLossForSellPosition() // перетащить Stop Loss для Sell позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
 

Bom dia e bom humor para todos!

Eu continuo estudando a linguagem de programação MQL5. Ontem eu escrevi o código de Stop Loss no Breakeven para posições de Venda e Compra. Estou colando o código sem nenhum comentário ainda. Publicarei a versão completa do Expert Advisor com uma descrição detalhada de cada linha de código, em uma forma acessível aos alunos do 1º ano da escola de programação, mais tarde no arquivo com o título de trabalho Trailing_Stop.mq5. Antes de publicar o código, verificamos o desempenho do Expert Advisor no testador de estratégia. Não foram encontrados problemas.

Cumprimentos, Vladimir.

//+------------------------------------------------------------------+
//| Устанавливает sl позиции BUY в безубыток                         |
//+------------------------------------------------------------------+
void SetBreakevenForBuyPosition() // функция "Установить безубыток для позиции Buy"
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request={0};
   MqlTradeResult result={0};
//--- Запустим цикл перебора всех открытых позиций
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      //--- параметры позиции Buy
      ulong  ticket=PositionGetTicket(i);                         // тикет позиции
      string symbol=PositionGetString(POSITION_SYMBOL);           // символ
      int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // количество знаков после запятой
      ulong  magic=PositionGetInteger(POSITION_MAGIC);            // MagicNumber позиции
      double volume=PositionGetDouble(POSITION_VOLUME);           // объем позиции
      double sl=PositionGetDouble(POSITION_SL);                   // Stop Loss позиции
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);  // тип позиции
      //--- выводим информацию о позиции Buy
      PrintFormat("#%I64u %s  %s  %.2f  %s  sl: %s  tp: %s  [%I64d]",
                  ticket,
                  symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  DoubleToString(sl,digits),
                  magic);
      //--- если MagicNumber совпадает
      if(magic==Magic_Number)
        {
         double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
         double price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         double price_open=PositionGetDouble(POSITION_PRICE_OPEN);
         double price_breakeven=NormalizeDouble(price_open+BreakevenLevel*point,digits);
         //--- зададим условие переноса Stop Loss в безубыток для позиции Buy
         if(type==POSITION_TYPE_BUY && price==price_breakeven)
           {
            sl=NormalizeDouble(price_open,digits);
           }
         //--- обнуляем значения запроса и результата
         ZeroMemory(request);
         ZeroMemory(result);
         //--- устанавливаем параметры операции
         request.action=TRADE_ACTION_SLTP; // тип торговой операции
         request.position=ticket;          // тикет позиции
         request.symbol=symbol;            // символ
         request.sl=sl;                    // Stop Loss позиции
         request.magic=Magic_Number;       // MagicNumber позиции
         //--- выводим информацию о модификации
         PrintFormat("Modify #%I64d %s %s",ticket,symbol,EnumToString(type));
         //--- отправка запроса
         if(!OrderSend(request,result)) // если отправить запрос не удалось
            PrintFormat("OrderSend error %d",GetLastError()); // выводим код ошибки
         //--- информация об операции
         PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает sl позиции SELL в безубыток                        |
//+------------------------------------------------------------------+
void SetBreakevenForSellPosition() // функция "Установить безубыток для позиции Sell"
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request={0};
   MqlTradeResult result={0};
//--- Запустим цикл перебора всех открытых позиций
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      //--- параметры позиции Sell
      ulong  ticket=PositionGetTicket(i);                         // тикет позиции
      string symbol=PositionGetString(POSITION_SYMBOL);           // символ
      int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // количество знаков после запятой
      ulong  magic=PositionGetInteger(POSITION_MAGIC);            // MagicNumber позиции
      double volume=PositionGetDouble(POSITION_VOLUME);           // объем позиции
      double sl=PositionGetDouble(POSITION_SL);                   // Stop Loss позиции
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);  // тип позиции
      //--- выводим информацию о позиции Sell
      PrintFormat("#%I64u %s  %s  %.2f  %s  sl: %s  tp: %s  [%I64d]",
                  ticket,
                  symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  DoubleToString(sl,digits),
                  magic);
      //--- если MagicNumber совпадает
      if(magic==Magic_Number)
        {
         double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
         double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         double price_open=PositionGetDouble(POSITION_PRICE_OPEN);
         double price_breakeven=NormalizeDouble(price_open-BreakevenLevel*point,digits);
         //--- зададим условие переноса Stop Loss в безубыток для позиции Sell
         if(type==POSITION_TYPE_SELL && price==price_breakeven)
           {
            sl=NormalizeDouble(price_open,digits);
           }
         //--- обнуляем значения запроса и результата
         ZeroMemory(request);
         ZeroMemory(result);
         //--- устанавливаем параметры операции
         request.action=TRADE_ACTION_SLTP; // тип торговой операции
         request.position=ticket;          // тикет позиции
         request.symbol=symbol;            // символ
         request.sl=sl;                    // Stop Loss позиции
         request.magic=Magic_Number;       // MagicNumber позиции
         //--- выводим информацию о модификации
         PrintFormat("Modify #%I64d %s %s",ticket,symbol,EnumToString(type));
         //--- отправка запроса
         if(!OrderSend(request,result)) // если отправить запрос не удалось
            PrintFormat("OrderSend error %d",GetLastError()); // выводим код ошибки
         //--- информация об операции
         PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }
     }
  }
//+------------------------------------------------------------------+
 
MrBrooklin:

Bom dia e bom humor para todos!

Eu continuo estudando a linguagem de programação MQL5. Hoje, como prometido, estou colando o código do modelo do meu Conselheiro Especialista projetado para escrever uma parada de trilha. Devido ao fato de o código do modelo EA ser bastante incômodo, tive que cortar os comentários o mais curto possível. A versão completa do Expert Advisor com comentários detalhados sobre cada linha do código, em uma forma acessível para um estudante da 1ª série de programação da escola, será publicada posteriormente como um arquivo com o nome de trabalho Trailing_Stop.mq5, para evitar a criação de outro estrago no site.

...

Muito bom. A idéia principal é bem capturada. Especialmente eu gosto do processo de desenvolvimento:

MrBrooklin:

Bom dia e bom humor para todos!

Eu continuo estudando a linguagem de programação MQL5. Ontem escrevi o código para Stop Loss at Breakeven para posições de Compra e Venda.

Isto é, tudo está correto. Não é preciso resolver o problema de uma só vez em um só lugar. Você deve resolvê-lo gradualmente, assim como fez. Primeiro, você descreve a lógica básica na função OnTick e funções básicas como OpenBUY, OpenSELL, TickUP, TickDown.

Então, quando este código básico é depurado, compilado e funciona dentro de suas capacidades, você começa a descrever as outras funções. Isto pode ser feito no dia seguinte ou até mesmo uma semana. Isto significa que você não precisa mudar o código principal. Acho que você pode ver por quê.

Agora você precisa aperfeiçoar esta forma de desenvolvimento: continue escrevendo funções, ligando a funcionalidade através delas ao código existente. O programa existente deve funcionar corretamente. A complexidade não deve aumentar. As funções a serem adicionadas devem retornar resultados simples e claros. Seus nomes devem ser tão simples e claros para você. Se você não pode fazer isso, pode ser porque você precisa escrever não uma, mas duas ou até mesmo três funções para resolver o problema. A princípio, a estrutura geral do pedido será difícil de definir. É por isso que é melhor pedir conselhos a colegas mais experientes. Com o tempo, você aprenderá a desenvolver tais modelos por conta própria.

Com o passar do tempo,você precisará usar cada vez mais construções lingüísticas dentro das funções para torná-las adequadas às suas necessidades.Neste ponto, você vai gradualmente e o mais importante, estender organicamente seus conhecimentos de construções lingüísticas, aprender loops, arrays e até mesmo trabalhar com apontadores.

Na verdade, você já aprendeu a parte mais difícil da programação, embora ainda não tenha consolidado o material que aprendeu. Tudo o que você precisa fazer agora é repeti-lo muitas vezes para consolidá-lo. Daqui não haverá nada fundamentalmente novo, tudo é o mesmo: Modelo geral -> Descrição dos nomes das funções e seus parâmetros-> Escrita do conteúdo destas funções -> Disposição destas funções na unidade central. É isso aí. Tudo o que resta é aperfeiçoar a habilidade e ser consistente. Várias construções adicionais que você começa a usar como loops e arrays são apenas detalhes, às vezes inteligentemente feitos, mas nada mais do que detalhes.

 
A propósito, preste atenção ao tamanho geral de seu programa. Já é bastante substancial. O que você acha disso? A propósito, um novato não pode escrever um código tão grande: variáveis começam a ficar confusas, parênteses ficam muito grandes, erros de compilação começam a rastejar como cogumelos após a chuva. Após a compilação, um programa desse tamanho começa a apresentar falhas e ninguém consegue entender o que está errado. E tudo funciona em seu código por alguma razão), e é claro nas funções o que está acontecendo e como. Em uma palavra, é uma beleza.
 

Como não há limite para a perfeição, acrescentarei mais alguns comentários sobre o código:

void OnTick()
  {
//--- Зададим время открытия и закрытия позиции
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct(TimeCurrent(),time_current);
   TimeToStruct((D'1970.01.01 09:00:00'),time_open);
   TimeToStruct((D'1970.01.01 09:01:00'),time_open1);
   TimeToStruct((D'1970.01.01 23:50:00'),time_close);
//--- Зададим условия для открытия позиций BUY и SELL   
   double price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   double point=SymbolInfoDouble(Symbol(),SYMBOL_POINT);
   int digits=(int)SymbolInfoInteger(Symbol(),SYMBOL_DIGITS);
   price=NormalizeDouble(price,digits);
   if(PositionSelect(Symbol())==false
      && PositionGetInteger(POSITION_MAGIC)!=Magic_Number
      && time_current.hour==time_open.hour
      && time_current.min>=time_open.min
      && time_current.min<time_open1.min
      && (TickUP()==(price+point)))
     {OpenBUY();}
   else
     {
      if(PositionSelect(Symbol())==false
         && PositionGetInteger(POSITION_MAGIC)!=Magic_Number
         && time_current.hour==time_open.hour
         && time_current.min>=time_open.min
         && time_current.min<time_open1.min
         && (TickDOWN()==(price-point)))
        {OpenSELL();}
     }
   if(time_current.hour==time_close.hour && time_current.min==time_close.min)
      CloseALL();
}

Destaquei dois lugares não triviais em amarelo.

1) Note que o código é repetido no primeiro se e no próximo se. A única diferença está na última linha e na ação final (OpenBUY, OpenSell).

2) As condições para entrar no outro bloco não são óbvias. Eles não são visíveis por causa da abundância de ???. Na verdade, eles dependem apenas da última linha:

TickUP()==(price+point)

Este é um sinal seguro de que uma função está faltando aqui.

Precisamos escrever uma função que retorne verdadeiro se o tempo para abrir a posição corresponder ao dado (escreverei mais tarde)

 
Vasiliy Sokolov:

Muito bom. O ponto principal é capturado corretamente. Gostou especialmente do processo de desenvolvimento:

Isto é, tudo está certo. Você não tem que resolver o problema de uma só vez em um só lugar. Você o faz gradualmente, como aconteceu no seu caso. Primeiro, você descreve a lógica básica na função OnTick e funções básicas como OpenBUY, OpenSELL, TickUP, TickDown.

Então, quando este código básico é depurado, compilado e funciona dentro de suas capacidades, você começa a descrever as outras funções. Isto pode ser feito no dia seguinte ou até mesmo uma semana. Isto significa que você não precisa mudar o código principal. Acho que você pode ver por quê.

Agora você precisa aperfeiçoar esta forma de desenvolvimento: continue escrevendo funções, ligando a funcionalidade através delas ao código existente. O programa existente deve funcionar corretamente. A complexidade não deve aumentar. As funções a serem adicionadas devem retornar resultados simples e claros. Seus nomes devem ser tão simples e claros para você. Se você não puder fazer isso, pode ser que você precise escrever não uma, mas duas ou até mesmo três funções para resolver o problema.

Para que uma função possa realizar sua tarefa pretendida,você precisará eventualmente usar cada vez mais construções lingüísticas dentro de tais funções. É quando você vai gradualmente e o mais importante, estender organicamente seus conhecimentos de construções lingüísticas, aprender loops, arrays e até mesmo trabalhar com apontadores.

Olá, Vasily! Muito obrigado por suas sugestões e apoio oportuno. Seus comentários sobre o papel das funções e princípios de construção do código do programa me ajudaram muito no aprendizado da linguagem de programação MQL5:

  1. https://www.mql5.com/ru/forum/352460/page28#comment_18636493
  2. https://www.mql5.com/ru/forum/352460/page28#comment_18637800
  3. https://www.mql5.com/ru/forum/352460/page29#comment_18641729
  4. https://www.mql5.com/ru/forum/352460/page52#comment_18694985

Agora que a informação em minha cabeça está estruturada, é mais fácil entender o código escrito não só por mim, mas também por outros programadores. Espero que este tópico seja uma boa ajuda para aqueles que estão começando a aprender a linguagem de programação MQL5 a partir do zero.

Cumprimentos, Vladimir.