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

 

Frames:

Чтение фреймов из mqd-файлов результатов Оптимизации.

Автор: fxsaber

 
Этот пример существенно дополняет Документацию по фреймам, поэтому здесь

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

Тестирование стратегий по расписанию с автоподстановкой результата в советника

Slava, 2013.04.10 15:04

Вот пример. В OnTester советник отсылает 2 фрейма - история сделок и история, на которой он работал.

double OnTester()
  {
   BalanceInTime balance[];
   double        balance_current=TesterStatistics(STAT_INITIAL_DEPOSIT);
   uint          data_count=0;
   MqlRates      rates[];
//---
   CopyRates(Symbol(),Period(),D'2010.12.01 0:00',D'2013.01.01 0:00',rates);
//--- запросим всю торговую историю
   HistorySelect(0,TimeCurrent());
   uint deals_total=HistoryDealsTotal();
   if(deals_total!=257)
     {
      if(deals_total>0)
        {
         ulong ticket=0;
         ArrayResize(balance,deals_total);
         //--- собираем данные о сделках
         for(uint i=0; i<deals_total; i++)
           {
            if((ticket=HistoryDealGetTicket(i))>0)
              {
               long   entry =HistoryDealGetInteger(ticket,DEAL_ENTRY);
               double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
               if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT)
                  balance_current+=profit;
               balance[data_count].date=HistoryDealGetInteger(ticket,DEAL_TIME);
               balance[data_count].entry=(ENUM_DEAL_ENTRY)entry;
               balance[data_count].price=HistoryDealGetDouble(ticket,DEAL_PRICE);
               balance[data_count].balance=balance_current;
               data_count++;
              }
           }
         if(data_count<deals_total)
            ArrayResize(balance,data_count);
        }
      FrameAdd(MQL5InfoString(MQL5_PROGRAM_NAME),1,data_count,balance);
      //---
      FrameAdd(MQL5InfoString(MQL5_PROGRAM_NAME),2,ArraySize(rates),rates);
     }
//---
   return(double(deals_total));
  }

В OnTesterDeinit приём и обработка всех фреймов первого и второго типа

void OnTesterDeinit()
  {
   string        name;
   ulong         pass;
   long          id;
   double        value;
   int           handle,i;
   BalanceInTime balance[];
   MqlRates      rates[];
//---
   FrameFirst();
   FrameFilter("",1);
   while(FrameNext(pass,name,id,value,balance))
     {
      handle=FileOpen(name+"_"+string(id)+"_"+IntegerToString(pass,5,'0')+".txt",FILE_WRITE|FILE_CSV|FILE_ANSI);
      if(handle!=INVALID_HANDLE)
        {
         for(i=0; i<ArraySize(balance); i++)
            FileWrite(handle,balance[i].date,EnumToString(balance[i].entry),DoubleToString(balance[i].price,5),DoubleToString(balance[i].balance,2));
         FileClose(handle);
        }
     }
//---
   FrameFirst();
   FrameFilter("",2);
   while(FrameNext(pass,name,id,value,rates))
     {
      handle=FileOpen(name+"_"+string(id)+"_"+IntegerToString(pass,5,'0')+".txt",FILE_WRITE|FILE_CSV|FILE_ANSI);
      if(handle!=INVALID_HANDLE)
        {
         for(i=0; i<ArraySize(rates); i++)
            FileWrite(handle,rates[i].time,DoubleToString(rates[i].open,5),DoubleToString(rates[i].high,5),DoubleToString(rates[i].low,5),DoubleToString(rates[i].close,5),string(rates[i].tick_volume));
         FileClose(handle);
        }
     }
//---
  }

И пояснение к нему

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

Ошибки, баги, вопросы

Slava, 2019.04.18 07:44

OnTesterPass вызывается, когда пришёл хотя бы один фрейм. Может прийти пачка фреймов. Поэтому в OnTesterPass надо принимать фреймы в цикле, а не по одному. Но если "после последнего раза - ни разу", то OnTesterPass не вызывается.

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

Это - нормальная здоровая логика.

Я несколько раз давал примеры приёма фреймов именно в OnTesterDeinit, а не только в OnTesterPass. И именно приём сложных фреймов разных типов


FrameFilter предназначен для сложных фреймов. OnTesterPass реагирует только на один фрейм из прохода. Поэтому рекомендовал бы использовать только по подному фрейму на проход.