Особенности языка mql5, тонкости и приёмы работы - страница 184

 
enum EAct{PUSH,POP};

template<typename T>
void TempCondition(T &value,EAct act){
   static T temp=T();
   switch(act){
      case PUSH: temp=value; break;
      case POP: value=temp;
   }
}

#define sortArray(_lArray,_lField) do {                     \
   for(int i = 0; i < ArraySize(_lArray); i++) {            \
      TempCondition(_lArray[i],PUSH);                       \
      for(int a = 1; a <= i; a++) {                         \
         if(_lArray[i]._lField < _lArray[a - 1]._lField){   \
            for(int b = i; b >= a; b--) {                   \
               _lArray[b] = _lArray[b - 1];                 \
               }                                            \
               TempCondition(_lArray[a - 1],POP);           \
               break;}}}} while(false)


struct STest{
   double a;
   int b;
};

void OnStart()
{
    STest test[700];
    sortArray(test,a);
}

По идее должно работать. Но не советую так делать)))

 
Koldun Zloy:

Вообще-то это оптимально. И позволяет задать более сложные условия сортировки.

Например:

Да и других решений всё равно нет.

Суть шаблона в том, чтобы быть универсальным. Если в вашем примере у вас будет передана другая структура не содержащая хотя бы одно поле a,b,c то оно не скомпиллируется. Тоесть функция работать одновременно с двумя разными типами данных не сможет.

 
Комментарии, не относящиеся к этой теме, были перенесены в "Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам".
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Панель управления для торговли. ТРЕБУЕТСЯ ПОМОЩЬ MQL5

Vladimir Karputov, 2020.08.18 09:04

Этот код не мог работать - нельзя сравнивать котлеты и квадратное:

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong OrderTicket=OrderGetTicket(i);
      if(OrderTicket>0 && PositionSelectByTicket(OrderTicket))
        {
         // Stop long позиции------------------------------------------
         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
           {
            int cur_tr; //трейлинг
            double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
            double newSl = ask - cur_tr*_Point;
            double positionSl = PositionGetDouble(POSITION_SL);
            double positionTP = PositionGetDouble(POSITION_TP);
            if(newSl > positionSl || positionSl == 0)
              {
               CTrade trade;
               trade.PositionModify(OrderTicket,newSl,positionTP);
              }
           }
        }
     }

Это условие сработает, если отложенный ордер исполнился частично и породил позицию. Тогда одновременно будут существовать ордер и позиция с одним и тем же тикетом.

По этой причине  следующая конструкция имеет смысл в некоторых ситуациях.

::PositionSelectByTicket(::OrderGetInteger(ORDER_TICKET))
 
Если нужно обнулить MQL-данные выбранной позиции или ордера.
PositionSelectByTicket(0); // Обнуляет PositionGet*
OrderSelect(0);            // Обнуляет OrderGet*
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: MT4Orders

fxsaber, 2020.08.20 15:44

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

Это несложно выяснить.

Alert: 60 - Too many trade requests


Будьте аккуратны, можно упереться в ограничение.

 
fxsaber:

Ренат еще давно говорил, что можно не только в лимит упереться, еще и блокировку словить от ДЦ

 
fxsaber:

Это условие сработает, если отложенный ордер исполнился частично и породил позицию. Тогда одновременно будут существовать ордер и позиция с одним и тем же тикетом.

Следующим кодом на демо-счете RannForex-Server можно сразу воспроизвести эту ситуацию, если запустить этот советник.

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

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

MqlTradeResult Result = {0};
MqlTradeRequest Request = {0};

int OnInit()
{

        Request.action = TRADE_ACTION_PENDING;
        Request.symbol = _Symbol;
        Request.volume = 100;
        Request.price = Ask;
        Request.type = ORDER_TYPE_BUY_LIMIT;
        
        return(!OrderSend(Request, Result)); // Выставили лимитник по текущей цене.
}

#define TOSTRING(A) #A + " = " + DoubleToString(A, _Digits)

void OnTradeTransaction( const MqlTradeTransaction&, const MqlTradeRequest&, const MqlTradeResult& )
{
  if (OrderSelect(Result.order) && (OrderGetInteger(ORDER_STATE) == ORDER_STATE_PARTIAL)) // Если наш лимитник исполнился частично
  {
    if (Ask - OrderGetDouble(ORDER_PRICE_OPEN) < 100 * _Point)                            // и находится близко от текущей цены
    {
        Request.action = TRADE_ACTION_MODIFY;
        Request.order = Result.order;
        Request.price = Ask - 1000 * _Point;

      // тогда передвигаем его подальше.
      if (OrderSend(Request, Result)) // Если синхронный OrderSend выполнился успешно, то торговое окружение должно соответствовать.
      {
        // Проверка соответствия торгового окружения.
        if (OrderSelect(Request.order) &&                                                                // Если получилось взять данные нашего ордера
            NormalizeDouble(OrderGetDouble(ORDER_PRICE_OPEN) - Request.price, _Digits))                  // и цена ордера не равна цене успешного OrderSend
          Alert("Bug:" + TOSTRING(OrderGetDouble(ORDER_PRICE_OPEN)) + " != " + TOSTRING(Request.price)); // сообщаем о баге MT5.
      }
    }
    else
      ExpertRemove();
  }     
}


Результат.


Попутно скрипт показывает (не всегда с первого раза) баг выполнения синхронного OrderSend.

Alert: Bug:OrderGetDouble(ORDER_PRICE_OPEN) = 0.89837 != Request.price = 0.88837

После выполнения OrderSend в течение нескольких десятков/сотен миллисекунд цена ордера старая, а не та, что успешно выставил OrderSend.


Возвращаясь к теме одинаковых тикетов, можно сделать некоторые выводы.

  1. Если висит partial-лимитник, то во вкладке "Ордера и сделки" не будет видно порожденной сделки.
  2. На хедже один ордер может породить несколько IN-сделок с разными ценами. В итоге получится дробная (относительно пунктов) цена открытия позиции.
  3. Вы можете закрыть сформированную позицию, не удаляя Partial-отложку. Но если после этого отложка сработает, то откроет сделка с тикетом, равным тикету до этого закрытой позиции. Т.е. может быть ситуация, когда вы закрываете позицию с определенными тикетом. А потом появляется позиция снова с этим же тикетом.
  4. Частичное исполнение может быть по-разному реализовано, в зависимости от софта брокера. Выше описал стандартную MT5-реализацию.

ЗЫ Если у кого-то получилось воспроизвести на другом торговом сервере, поделитесь названием.

Строка для поиска: Oshibka 010.

 
fxsaber:


  1. Вы можете закрыть сформированную позицию, не удаляя Partial-отложку. Но если после этого отложка сработает, то откроет сделка с тикетом, равным тикету до этого закрытой позиции. Т.е. может быть ситуация, когда вы закрываете позицию с определенными тикетом. А потом появляется позиция снова с этим же тикетом.

Не уникальный тикет? Как такое может быть?

Хоть у ордеров и сделок тикеты уникальны?

 
Andrey Khatimlianskii:

Не уникальный тикет? Как такое может быть?

Для себя можно найти такое объяснение, что пока существует ордер открытия, то всегда существует позиция. Просто она не всегда видна - нулевой объем. И у этой позиции уникальный тикет. Ну и на хедже по этой причине вполне возможно наличие in-сделок одной и той же позиции после соответствующих in и out сделок.

Хоть у ордеров и сделок тикеты уникальны?

Уникальны. Но, конечно, ORDER_TICKET может быть равен DEAL_TICKET.

Причина обращения: