3 строки кода MQL4 не получается переписать в MQL5 - страница 4

 
Renat Akhtyamov:

человек же сказал хеджинговый счет

про стопы речи не было

Причём здесь хедж и стопы? Что это меняет в нашем обсуждении?

 

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

3 строки кода MQL4 не получается переписать в MQL5

Aleksey Mavrin, 2020.12.05 16:32

Пробовал, нет в истории сделки закрывающей сразу после успешной отправки ордера закрывающего.

Если у вас есть, везёт, может исполнение особое. Но в общем случае нет.

з.ы. в тестере работать будет, там всё сразу есть

не уверен, но наверное не сделка, а ордер, который на закрытие был отправлен можно найти в истории сразу после OrderSend()

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

поменял местами - сначала закрываю ордера, потом позиции - работает как часы

 
Igor Makanu:

брошу в ЛС,  но код рабочий вариант, много правок было, хотя структуру кода должны понять

Моя вставка в Ваш код.

#define MT4ORDERS_TESTER_SELECT_BY_TICKET // Принуждает SELECT_BY_TICKET работать в Тестере только через OrderTicketID().
#include <MT4Orders.mqh>

#define VIRTUAL_LIMITS_TP_SLIPPAGE // Лимитники и TP исполняются по первой цене акцепта - положительные проскальзывания
#define VIRTUAL_TESTER_FAST // Возможно, это ускорит советник в Тестере.
// #define VIRTUAL_TESTER // Запуск в виртуальном торговом окружении
#define VIRTUAL_CLOSEALL_BYEND // Закрывает принудительно все ордера в конце тестирования
#include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/ru/code/22577

  • В OnInit напарываетесь на нюанс со временем. Поэтому нужно отказываться от tick.time  в OnInit в пользу TimeCurrent.
  • Вы часто нарывались на тикет-неоднозначность. Макросом проблема решена. 

После этих правок советник будет работать, как задумано. При этом полностью будет совпадать результат, если запустить в Виртуалке (VIRTUAL_TESTER). В Виртуале производительность возрастет где-то в два раза.


Интересно другое, Вы сеткой открываете одновременно противоположные позиции. Отсюда получаете большие минусы. Режим VIRTUAL_TESTER_FAST позволяет подобные системы торговать гораздо выгоднее по прибыли.

 
fxsaber:

Моя вставка в Ваш код.

  • В OnInit напарываетесь на нюанс со временем. Поэтому нужно отказываться от tick.time  в OnInit в пользу TimeCurrent.
  • Вы часто нарывались на тикет-неоднозначность. Макросом проблема решена. 

После этих правок советник будет работать, как задумано. При этом полностью будет совпадать результат, если запустить в Виртуалке (VIRTUAL_TESTER). В Виртуале производительность возрастет где-то в два раза.


Интересно другое, Вы сеткой открываете одновременно противоположные позиции. Отсюда получаете большие минусы. Режим VIRTUAL_TESTER_FAST позволяет подобные системы торговать гораздо выгоднее по прибыли.

ОК

Спасибо!

ЗЫ: код, для экспериментов, для торговли он не предназначен, да и если торговать, то через виртуал проще оценить робастоть ТС

 

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

3 строки кода MQL4 не получается переписать в MQL5

Igor Makanu, 2020.12.05 16:20

по сабжу - не тестировал, как работает OnTradeTransaction в тестере, может, все таки, там быстрее будет отслеживать закрытие ордера, чем выбор по тикету из истории - постараюсь и эту идею проверить


нужно было на MQL5 попробовать код написать, да и повод был - проверил скорость (500 проходов оптимизатора на слабом ноуте):

 7 min 28 sec    - tst_Select_Pos.mq5

7 min 34 sec     - tst_OnTradeTransaction_Pos.mq5

7 min 32 sec -  tst_MT4_style.mq5

ТС рандомно выставляет ордера, по закрытию позиции анализ профита ордера - если профит <0 , то "перевернемся" и удвоим лот, СЛ и ТП - рандом, в целом общая имитация оптимизации

результаты соизмеримы, так сказать - что нравится, то и юзаем

PS:  MQL5 писан по справке, исходники ниже

 

tst_Select_Pos.mq5

// 7 min 28 sec
#define SLIPPAGE 10
input int OPTIMIZATION = 500; 

struct SPosition
{
   ulong             ticket;
   ulong             position_id;
   ulong             magic;
   double            profit;
   double            volume;
   ENUM_ORDER_TYPE   cmd;
};
SPosition POSITION[4] = {0};
//+------------------------------------------------------------------+
void OnInit()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
      POSITION[i].magic = i;
      POSITION[i].cmd = rand() > 16000 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   }
}
//+------------------------------------------------------------------+
void OnTick()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
//--- если позиция открыта
      if(PositionSelectByTicket(POSITION[i].ticket)) continue;
//--- если позиция закрыта
      if(HistorySelectByPosition(POSITION[i].position_id))
      {
         for(int j = HistoryDealsTotal() - 1; j >= 0; j--)
         {
            ulong ticket = HistoryDealGetTicket(j);
            if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
            {
               POSITION[i].profit += HistoryDealGetDouble(ticket, DEAL_PROFIT);
               POSITION[i].volume += HistoryDealGetDouble(ticket, DEAL_VOLUME);
            }
         }
      }
//--- откроем позицию
      if(POSITION[i].profit < 0.0) // перевернем позицию и удвоим лот
      {
         POSITION[i].volume *= 2.0;
         POSITION[i].cmd = POSITION[i].cmd == ORDER_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
      }
      else POSITION[i].volume = 0.01;
      if(POSITION[i].volume <= 0.0 || POSITION[i].volume > 1.0) POSITION[i].volume = 0.01; // ограничим лот

      ulong ticket = OpenPosition(POSITION[i].cmd, POSITION[i].volume, 100 + rand() % 500, 100 + rand() % 500, POSITION[i].magic);
      if(ticket > 0)
      {
         PositionSelectByTicket(ticket);
         POSITION[i].position_id = PositionGetInteger(POSITION_IDENTIFIER);
         POSITION[i].ticket = ticket;
         POSITION[i].profit = 0.0;
         POSITION[i].volume = 0.0;
      }
   }
}
//+------------------------------------------------------------------+
ulong OpenPosition(const ENUM_ORDER_TYPE _cmd, const double _volume,
                   const int _takeprofit, const int _stoploss, const ulong _magic)
{
   MqlTick  tick;
   SymbolInfoTick(_Symbol, tick);
   double sl = 0.0, tp = 0.0, pr = 0.0;
   MqlTradeResult  result;
   MqlTradeRequest request = {0};
   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.deviation    = SLIPPAGE;
   request.type_filling = CONST_TYPE_FILLING;
   request.magic        = _magic;
   request.comment      = (string)_magic;
   switch(_cmd)
   {
   case ORDER_TYPE_BUY:
      request.type   = ORDER_TYPE_BUY;
      pr = tick.ask;
      tp = _takeprofit == 0 ? 0.0 : pr + _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr - _Point * (double)_stoploss;
      break;
   case ORDER_TYPE_SELL:
      request.type   = ORDER_TYPE_SELL;
      pr = tick.bid;
      tp = _takeprofit == 0 ? 0.0 : pr - _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr + _Point * (double)_stoploss;
      break;
   default:
      return(0);
   };
   request.price = NormalizeDouble(pr, _Digits);
   request.tp    = NormalizeDouble(tp, _Digits);
   request.sl    = NormalizeDouble(sl, _Digits);
   request.volume = NormalizeDouble(_volume, 2);
   if(OrderSend(request, result)) return(result.order);
   return(0);
}
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetFilling(const uint Type = ORDER_FILLING_FOK)
{
   const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE);
   const int FillingMode = (int)::SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);

   return((FillingMode == 0 || (Type >= ORDER_FILLING_RETURN) || ((FillingMode & (Type + 1)) != Type + 1)) ?
          (((ExeMode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (ExeMode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
           ORDER_FILLING_RETURN : ((FillingMode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
          (ENUM_ORDER_TYPE_FILLING)Type);
}
//+------------------------------------------------------------------+
static const ENUM_ORDER_TYPE_FILLING CONST_TYPE_FILLING = GetFilling();
//+------------------------------------------------------------------+
 

tst_OnTradeTransaction_Pos.mq5

// 7 min 34 sec
#define SLIPPAGE 10
input int OPTIMIZATION = 500;

struct SPosition
{
   ulong ticket;
   ulong position_id;
   ulong magic;
   double profit;
   double volume;
   ENUM_ORDER_TYPE cmd;
};
SPosition POSITION[4] = {0};
//+------------------------------------------------------------------+
void OnInit()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
      POSITION[i].magic = i;
      POSITION[i].cmd = rand() > 16000 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   }
}
//+------------------------------------------------------------------+
void OnTick()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
//--- если позиция открыта, пропускаем
      if(PositionSelectByTicket(POSITION[i].ticket)) continue;

//--- откроем позицию
      if(POSITION[i].profit < 0.0) // перевернем позицию и удвоим лот
      {
         POSITION[i].volume *= 2.0;
         POSITION[i].cmd = POSITION[i].cmd == ORDER_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
      }
      else POSITION[i].volume = 0.01;
      if(POSITION[i].volume <= 0.0 || POSITION[i].volume > 1.0) POSITION[i].volume = 0.01; // ограничим лот

      ulong ticket = OpenPosition(POSITION[i].cmd, POSITION[i].volume, 100 + rand() % 500, 100 + rand() % 500, POSITION[i].magic);
      if(ticket > 0)
      {
         PositionSelectByTicket(ticket);
         POSITION[i].position_id = PositionGetInteger(POSITION_IDENTIFIER);
         POSITION[i].ticket = ticket;
         POSITION[i].profit = 0.0;
         POSITION[i].volume = 0.0;
      }
   }
}
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction & trans,
                        const MqlTradeRequest & request,
                        const MqlTradeResult & result)
{
   if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
   {
      ulong    ticket = trans.deal;
      if(HistoryDealSelect(ticket) && HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
      {
         int n = (int)HistoryDealGetInteger(ticket, DEAL_MAGIC);
         POSITION[n].profit += HistoryDealGetDouble(ticket, DEAL_PROFIT);
         POSITION[n].volume += HistoryDealGetDouble(ticket, DEAL_VOLUME);
      }
   }

}
//+------------------------------------------------------------------+
ulong OpenPosition(const ENUM_ORDER_TYPE _cmd, const double _volume,
                   const int _takeprofit, const int _stoploss, const ulong _magic)
{
   MqlTick  tick;
   SymbolInfoTick(_Symbol, tick);
   double sl = 0.0, tp = 0.0, pr = 0.0;
   MqlTradeResult  result;
   MqlTradeRequest request = {0};
   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.deviation    = SLIPPAGE;
   request.type_filling = CONST_TYPE_FILLING;
   request.magic        = _magic;
   request.comment      = (string)_magic;
   switch(_cmd)
   {
   case ORDER_TYPE_BUY:
      request.type   = ORDER_TYPE_BUY;
      pr = tick.ask;
      tp = _takeprofit == 0 ? 0.0 : pr + _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr - _Point * (double)_stoploss;
      break;
   case ORDER_TYPE_SELL:
      request.type   = ORDER_TYPE_SELL;
      pr = tick.bid;
      tp = _takeprofit == 0 ? 0.0 : pr - _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr + _Point * (double)_stoploss;
      break;
   default:
      return(0);
   };
   request.price = NormalizeDouble(pr, _Digits);
   request.tp    = NormalizeDouble(tp, _Digits);
   request.sl    = NormalizeDouble(sl, _Digits);
   request.volume = NormalizeDouble(_volume, 2);
   if(OrderSend(request, result)) return(result.order);
   return(0);
}
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetFilling(const uint Type = ORDER_FILLING_FOK)
{
   const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE);
   const int FillingMode = (int)::SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);

   return((FillingMode == 0 || (Type >= ORDER_FILLING_RETURN) || ((FillingMode & (Type + 1)) != Type + 1)) ?
          (((ExeMode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (ExeMode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
           ORDER_FILLING_RETURN : ((FillingMode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
          (ENUM_ORDER_TYPE_FILLING)Type);
}
//+------------------------------------------------------------------+
static const ENUM_ORDER_TYPE_FILLING CONST_TYPE_FILLING = GetFilling();
//+------------------------------------------------------------------+
 

tst_MT4_style.mq5

// 7 min 32 sec
#define SLIPPAGE 10
input int OPTIMIZATION = 500;
#define MT4ORDERS_TESTER_SELECT_BY_TICKET // Принуждает SELECT_BY_TICKET работать в Тестере только через OrderTicketID().
#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006              
struct SPosition
{
   long              ticket;
   long              position_id;
   ulong             magic;
   double            profit;
   double            volume;
   int               cmd;
};
SPosition POSITION[4] = {0};
//+------------------------------------------------------------------+
void OnInit()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
      POSITION[i].magic = i;
      POSITION[i].cmd = rand() > 16000 ? OP_BUY : OP_SELL;
   }
}
//+------------------------------------------------------------------+
void OnTick()
{
   for(int i = ArraySize(POSITION) - 1; i >= 0; i--)
   {
//--- если позиция открыта
      if(OrderSelect(POSITION[i].ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) continue;
//--- если позиция закрыта
      POSITION[i].volume = OrderLots();
      POSITION[i].profit = OrderProfit();
//--- откроем позицию
      if(POSITION[i].profit < 0.0) // перевернем позицию и удвоим лот
      {
         POSITION[i].volume *= 2.0;
         POSITION[i].cmd = POSITION[i].cmd == OP_BUY ? OP_SELL : OP_BUY;
      }
      else POSITION[i].volume = 0.01;
      if(POSITION[i].volume <= 0.0 || POSITION[i].volume > 1.0) POSITION[i].volume = 0.01; // ограничим лот

      long ticket = OpenPosition(POSITION[i].cmd, POSITION[i].volume, 100 + rand() % 500, 100 + rand() % 500, POSITION[i].magic);
      if(ticket > 0)
      {
         POSITION[i].position_id = ticket;
         POSITION[i].ticket = ticket;
         POSITION[i].profit = 0.0;
         POSITION[i].volume = 0.0;
      }
   }
}
//+------------------------------------------------------------------+
long OpenPosition(const int _cmd, const double _volume,
                  const int _takeprofit, const int _stoploss, const ulong _magic)
{
   MqlTick  tick;
   SymbolInfoTick(_Symbol, tick);
   double sl = 0.0, tp = 0.0, pr = 0.0;
   switch(_cmd)
   {
   case OP_BUY:
      pr = tick.ask;
      tp = _takeprofit == 0 ? 0.0 : pr + _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr - _Point * (double)_stoploss;
      break;
   case OP_SELL:
      pr = tick.bid;
      tp = _takeprofit == 0 ? 0.0 : pr - _Point * (double)_takeprofit;
      sl = _stoploss   == 0 ? 0.0 : pr + _Point * (double)_stoploss;
      break;
   default:
      return(0);
   };
   return(OrderSend(_Symbol, _cmd, NormalizeDouble(_volume, 2), NormalizeDouble(pr, _Digits),
                    SLIPPAGE, NormalizeDouble(sl, _Digits), NormalizeDouble(tp, _Digits), (string)_magic, _magic));
}
//+------------------------------------------------------------------+
 
Igor Makanu:

нужно было на MQL5 попробовать код написать, да и повод был - проверил скорость (500 проходов оптимизатора на слабом ноуте):

 7 min 28 sec    - tst_Select_Pos.mq5

7 min 34 sec     - tst_OnTradeTransaction_Pos.mq5

7 min 32 sec -  tst_MT4_style.mq5

ТС рандомно выставляет ордера, по закрытию позиции анализ профита ордера - если профит <0 , то "перевернемся" и удвоим лот, СЛ и ТП - рандом, в целом общая имитация оптимизации

результаты соизмеримы, так сказать - что нравится, то и юзаем

PS:  MQL5 писан по справке, исходники ниже 

Сколько сделок в истории на этих прогонах?

Хорошо что HistorySelectByPosition не тормозит, значит история индексирована, успокаивает)

в случае  tst_OnTradeTransaction_Pos.mq5 

Всё же можно делать прям в  OnTradeTransaction, т.е. открывать новую позу. И не нужно каждый тик пробегать список, может чуть пошустрее будет.


 
Aleksey Mavrin:

Сколько сделок в истории на этих прогонах?

зависит от размера массива POSITION[] и периода тестирования, пару сотен точно было

Aleksey Mavrin:

в случае  tst_OnTradeTransaction_Pos.mq5 

Всё же можно делать прям в  OnTradeTransaction, т.е. открывать новую позу. И не нужно каждый тик пробегать список, может чуть пошустрее будет.

не будет шустрее, только путаницы в код добавит - действия те же, алгоритм тот же



шустрее будет использовать совет @fxsaber ;) 

в общем исходники выложил, протестировать можно в 2 клика - думаю, что если сделать массив POSITION[]  хотя бы на 30-40 позиций..... в общем код есть, кому интересно проверит

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