Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам - страница 522

 
PolarSeaman:

Вот это поворот!)))

Ордер 1 (from# нету, to#2) -- > Ордер2 (from#1, to#3) -- >Ордер3 (from#2, to# нету)

Вот исходя из этого можно найти всю цепочку.

Смотрим у открытого комментарий и, если есть from#XXX, значит он ранее был закрыт частично - смотрим тикет XXX из комментария и ищем его в истории. Смотрим там комментарий - если есть from#YYY - значит он ранее тоже был закрыт частично - смотрим тикет YYY из комментария и ищем его в истории. Смотрим там комментарий - если есть from#ZZZ - значит и он ранее тоже был закрыт частично -повторяем поиск. Если же нет там from#..., значит - это самый первый из всей цепочки.

 
Artyom Trishkin:

Ордер 1 (from# нету, to#2) -- > Ордер2 (from#1, to#3) -- >Ордер3 (from#2, to# нету)

Вот исходя из этого можно найти всю цепочку.

Смотрим у открытого комментарий и, если есть from#XXX, значит он ранее был закрыт частично - смотрим тикет XXX из комментария и ищем его в истории. Смотрим там комментарий - если есть from#YYY - значит он ранее тоже был закрыт частично - смотрим тикет YYY из комментария и ищем его в истории. Смотрим там комментарий - если есть from#ZZZ - значит и он ранее тоже был закрыт частично -повторяем поиск. Если же нет там from#..., значит - это самый первый из всей цепочки.

Спасибо, может ордер быть и в противоположном направлении который тоже буду кромсать. Боюсь запутаться. Функцию Профита закрытого с определённой даты использовать, думаю, будет проще, конечно если есть возможность узнать когда была открыта позиция, ведь при частичном закрытии дата меняется

 
Artyom Trishkin:

Ордер 1 (from# нету, to#2) -- > Ордер2 (from#1, to#3) -- >Ордер3 (from#2, to# нету)

Вот исходя из этого можно найти всю цепочку.

Смотрим у открытого комментарий и, если есть from#XXX, значит он ранее был закрыт частично - смотрим тикет XXX из комментария и ищем его в истории. Смотрим там комментарий - если есть from#YYY - значит он ранее тоже был закрыт частично - смотрим тикет YYY из комментария и ищем его в истории. Смотрим там комментарий - если есть from#ZZZ - значит и он ранее тоже был закрыт частично -повторяем поиск. Если же нет там from#..., значит - это самый первый из всей цепочки.

Артём вы же знаете, что это не всегда так. И для того чтобы на отслеживании цепочки не переспрашивать терминал трижды - история всё равно загоняется в свои массивы и структуры. От ведения собственной базы не отличается ничем, кроме лишних действий

Терминал и его API - это минимально возможный низкий уровень. А для реализации логики робота логично вести учёт в её его терминах ( трейд, цепочка, группа, транзакция - всяк по разному называет). некая логически завершённая последовательность действий. Просто разумно вести такое отдельно и не пытаться восстанавливать при каждом чихе (тике/баре).

 
Maxim Kuznetsov:

Артём вы же знаете, что это не всегда так. И для того чтобы на отслеживании цепочки не переспрашивать терминал трижды - история всё равно загоняется в свои массивы и структуры. От ведения собственной базы не отличается ничем, кроме лишних действий

Терминал и его API - это минимально возможный низкий уровень. А для реализации логики робота логично вести учёт в её его терминах ( трейд, цепочка, группа, транзакция - всяк по разному называет). некая логически завершённая последовательность действий. Просто разумно вести такое отдельно и не пытаться восстанавливать при каждом чихе (тике/баре).

У меня-то давно всё такое сделано - не читаю я историю каждый раз - но она всегда есть в актуальном состоянии, и там я легко и очень быстро могу всё мне нужное найти. Но, чтобы советовать человеку сделать то же самое, мне нужно как минимум пару-тройку статей написать. А так я логику поиска всей цепочки расписал.

 
PolarSeaman:

Спасибо, может ордер быть и в противоположном направлении который тоже буду кромсать. Боюсь запутаться. Функцию Профита закрытого с определённой даты использовать, думаю, будет проще, конечно если есть возможность узнать когда была открыта позиция, ведь при частичном закрытии дата меняется

Для поиска цепочки достаточно знать тикет ордера, всю цепочку которого вы хотите знать - в функцию поиска передаёте параметром тикет, а на выходе - заполненный массив или массив структур со всеми данными каждого ордера всей цепочки.

 
Artyom Trishkin:

заполненный массив или массив структур со всеми данными каждого ордера всей цепочки.

Даже приблизительно не знаю о чём вы сейчас сказали.

Покажите хоть пример, как должно быть.

 
PolarSeaman:

Даже приблизительно не знаю о чём вы сейчас сказали.

Покажите хоть пример, как должно быть.

Я решаю проблему следующим образом: ищу цепочки по истории. Ну а чтобы история была однозначно доступна, то использую два варианта:

  1. Если без DLL, то в описании к программе 24-м жирным шрифтом )))) указываю, что история счета всегда должна быть загружена полностью (вкладка "История счета" окна "Терминал", контекстное меню - "Вся история").
  2. С DLL - эксперт сам поддерживает вкладку "История счета" в актуальном состоянии, невзирая на какие-либо действия пользователя.

Функции для определения родительских ордеров, если текущий ордер не первичный:

int GetSignOfPartialOrCloseByClose()
{
   string comment = OrderComment();
   if (comment == "")
      return 0;
   
   // Ордер образовался вследствии частичного закрытия
   int fromStart = StringFind(comment, "from #");
   if (fromStart >= 0)
      return GetTicketByPartialClose(comment, fromStart, OrderType(), OrderOpenTime());
   
   // Ордер образовался вследствии встречного закрытия
   if (StringFind(comment, "partial close") >= 0)
   {
      datetime openTime = OrderOpenTime();
      int type = OrderType();
      for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
      {
         if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
            continue;
            
         if (OrderOpenTime() != openTime)
            continue;
            
         if (OrderType() != type)
            continue;
            
         if (StringFind(OrderComment(), "partial close") < 0)
            continue;
            
         return OrderTicket();
      }
   }
   
   return 0;
}


int GetTicketByPartialClose(string comment, int fromStart, int orderType, datetime openTime)
{
   string sTicket = StringSubstr(comment, fromStart + 6);
   int iTicket = (int)StringToInteger(sTicket);
   int type = OrderType();
   if (!OrderSelect(iTicket, SELECT_BY_TICKET))
      return 0;
      
   if (OrderType() == type)                                                                        // Дочерний ордер указывает на родителя - уходим
      return iTicket;
      
   // Дочерний ордер указывает на противоположный ордер. Необходимо искать родительский
   for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;
         
      if (OrderType() != orderType || OrderOpenTime() != openTime)
         continue;
         
      int iFind = StringFind(OrderComment(), "close hedge by #");
      if (iFind < 0)
         continue;
         
      sTicket = StringSubstr(OrderComment(), iFind + 16);
      int iNewTicket = (int)StringToInteger(sTicket);
      if (iNewTicket != iTicket)
         continue;
         
      return OrderTicket();
   }
   
   return 0;
}

Пользоваться - просто:

   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS))
         continue;

      ....         

      int nFromTicket = GetSignOfPartialOrCloseByClose();                // Обязательно последней строкой в теле цикла, т. к. может измениться текущий выбранный ордер
   }


 
Ihor Herasko:

Наиболее грубая ошибка здесь - это указание значения 100 вместо тикета в аргументе функции OrderDelete().

Далее ошибка не такая грубая, но связанная с тем, что проверяется расчетное значение Stop Loss, а не его фактическое значение.

Еще не проверяется тип ордера. Вдруг выбрали рыночный ордер? Как же его удалить то? Не проверен символ ордера. 

С учетом этих ошибок, получаем такой код удаления отложенного ордера при достижении ценой его Stop Loss:

Также в Вашем коде проверка достижения Stop Loss следует сразу после открытия ордера. Складывается впечатление, что после открытия отложенного ордера больше этот код уже не исполняется. То есть Вам нужно разделить ветки исполнения. Одна отвечает за установку ордера, а вторая - за его сопровождение.

Огромное Вам спасибо за подробный ответ!

По Вашему совету разделил ветки и все получилось.

Потом столкнулся с проблемой что одновременно открывало по 10-15 отложенных ордеров, решил проблему добавив после вашего кода:

if (OrdersTotal ()>0) return;

Уверен, есть более грамотный способ.

По Вашему коду, не поясните пожалуйста, что значит 1; i >=0; --i ?

for (int i = OrdersTotal() - 1; i >= 0; --i)
 

Помогите разобраться пожалуйста, как написать индикатор. Вот набросал такую болванку, каким образом сделать так чтобы отобразить линию индикатора длинной lenght, которая будет рисоваться на size пунктов выше текущего Bid, начиная с того момента, как индикатор поставлен на график? Может ошибка в том что я сдвигаю этот массив не в том направлении?

Я знаю что это по "канону", без всяких prev_calculated и прочего, но мне нужно именно вот так


#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//---- plot 
#property indicator_label1  "myInd"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

double buff[], Bid;
input int lenght = 50, size = 5;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   ArrayResize(buff, 50);
   ArrayInitialize(buff, 0);
   SetIndexBuffer(0, buff, INDICATOR_DATA);
   //--- установим метку для отображения в DataWindow
   PlotIndexSetString(0,PLOT_LABEL,"myInd");   
//--- установим имя для показа в отдельном подокне и во всплывающей подсказке
   IndicatorSetString(INDICATOR_SHORTNAME,"myInd");
//--- укажем точность отображения значений индикатора
   IndicatorSetInteger(INDICATOR_DIGITS, _Point);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   for(int i = lenght-1; i>0; i--){
      buff[i] = buff[i-1];
   }
   buff[0] = Bid+size;
   


   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Roman Sharanov:

Помогите разобраться пожалуйста, как написать индикатор. Вот набросал такую болванку, каким образом сделать так чтобы отобразить линию индикатора длинной lenght, которая будет рисоваться на size пунктов выше текущего Bid, начиная с того момента, как индикатор поставлен на график? Может ошибка в том что я сдвигаю этот массив не в том направлении?

Я знаю что это по "канону", без всяких prev_calculated и прочего, но мне нужно именно вот так


какой такой канон ? есть оф.док - там именно как у вас..всё остальное от лукавого.

1. стоит внутри OnCalculate задавать серийность вcех используемых массивов

2. до входа в цикл поставьте buff[length]=Bid+size; - получится примерно как хотите. Кривая линия и в конце "козырёк" на уровне Bid+size

3. следите за границами массивов. Конечно вряд-ли rates_total < length, но чем чёрт не шутит :-)

4.
buff[i] = buff[i+1]; // если тайм-серия (а вы подразумеваете их) то +
Причина обращения: