Учимся писать советник. Работа по расписанию. Часть 9

Если ваша торговая система не базируется на новостных скачках, то бывает очень полезно для финансового и ментального здоровья останавливать работу советника перед выходом важных новостей. А после устаканивания волатильности, через нескольких часов, заново его включать. Хорошо, если у вас под рукой доступ к рабочему терминалу. А если нет? Вот тут и пригодится автоматизация такой деятельности.

Одним из вариантов решения нашей задачи является составление файла с расписанием важных событий. Чтение этого файла нашим экспертом, и определение когда можно работать, а когда нет. В учебнике MQL4 приводится пример работы с текстовым файлом csv, его то мы и возьмем за основу, попутно избавившись от пары ошибок, которые авторы допустили непреднамеренно или с целью проверки нашей внимательности (о чем они сами предупреждают — не следует слепо верить никому, ошибки бывают всегда).

Итак, составим расписание важных событий на следующей неделе в следующем формате:
Дата и время события;инструмент;описание события

2016.04.01 14:00;USD;Индекс деловой активности ISM в производственном секторе	
2016.04.01 14:00;USD;Индекс постепенного разгона инфляции от ISM
2016.04.04 09:00;EUR;Индекс цен производителей (м/м)	
2016.04.04 09:00;EUR;Индекс цен производителей (г/г)
2016.04.05 04:30;AUD;Решение Резервного Банка Австралии по процентной ставке
2016.04.05 04:30;AUD;Сопроводительное заявление Резервного Банка Австралии
2016.04.06 07:00;EUR;Заседание ЕЦБ
2016.04.06 18:00;USD;Протокол заседания Комитета по открытым рынкам ФРС США
2016.04.07 11:30;EUR;Сведения о заседании ЕЦБ по монетарной политике

Запишем его в файл ht-news.csv и разместим в нужной директории \MQL4\Files\ht-news.csv, откуда наш советник сможет его прочитать.

Вначале зададим внешние переменные для настройки, комментарии объясняют их назначение:

extern string startNewsEvent="Ограничение работы по новостям";
input bool StopOnNewsEvent=true; //Включить ограничение
input string NewsEventFileName="ht-news.csv"; //Файл с расписанием
input uint LoadNewsEventTimerInDay=7;//Как часто в днях перезагружать файл
input uint StopPriorEventHours=2; //Остановить за Х часов до события
input uint StartAfterEventHours=3; //Запустить через Х часов после события
extern string stopNewsEvent="----------------";

Следующая структура поможет нам получить доступ к описанию обрабатываемого события:

struct NEWS_EVENT {
    datetime EventTime; //время наступления события
    string   Instrument;  //инструмент события 
    string   EventComment;  //комментарий события

};

Пользовательская функция чтения информации из файла

bool LoadNews()   
{
   int handle;                       // Файловый описатель
   string  instrument,                       // Название валюты события
           firstInstrument,secondInstrument, // 1я и 2я часть названия текущей пары 
           eventComment,                     // Текст описания события
           stringDateTime;                   // Строковое выражение даты и времени события
   datetime eventDateTime;                  // Дата и время события в формате datetime

   handle=FileOpen(NewsEventFileName,FILE_CSV|FILE_READ,";");// Открытие файла
   if(handle<0)                        // Неудача при открытии файла
     {
	  int lastError=GetLastError();
      if(lastError==4103)         // Если файла не существует, сообщим
         Alert("Нет файла с именем ",NewsEventFileName);
      else                             // При любой другой ошибке
         Alert("Ошибка при открытии файла ",NewsEventFileName," :",lastError);
      PlaySound("Bzrrr.wav");          // Громко ругнемся и вернем фалсе
      return false;                      
     }

int cnt=0;
   while(FileIsEnding(handle)==false)
     {                                
      stringDateTime =FileReadString(handle);// Дата и время события
      instrument=FileReadString(handle); //Инструмент
      eventComment  =FileReadString(handle);// Текст описания события, может не быть
      eventDateTime =StrToTime(stringDateTime);   // Преобразование типа данных
      firstInstrument=StringSubstr(Symbol(),0,3);// Извлекаем первые 3 символа
      secondInstrument=StringSubstr(Symbol(),3,3);// Извлекаем вторые 3 символа
     
      if(StringCompare(instrument,firstInstrument,false)!=0 && StringCompare(instrument,secondInstrument,false)!=0) 
        {  
        continue; //не наши инструменты
        }  
         cnt++;   
         
       ArrayResize(NewsEvent,cnt,1000);   //изменяем размер массива с запасом для ускорения
       ArrayResize(NewsEventTime,cnt,1000);
       
       NewsEvent[cnt-1].EventTime= eventDateTime;
       NewsEvent[cnt-1].Instrument=instrument;
       NewsEvent[cnt-1].EventComment=eventComment;
       
       NewsEventTime[cnt-1]=eventDateTime; //удобнее искать в одномерном массиве

     }

   FileClose( handle );                // Закрываем файл
   ArraySort(NewsEventTime,WHOLE_ARRAY,0,MODE_ASCEND); //сортируем массив для последующего поиска

   return true;              
}

Поиск нужного времени осуществляем в массиве NewsEventTime, и если время найдено, то получим его описание их массива структуры NewsEvent

string GetEventInfo(datetime date)
{
for(int i=0;i<ArraySize(NewsEvent);i++)
  {
   if (NewsEvent[i].EventTime==date)
   {
   return (NewsEvent[i].Instrument+" "+NewsEvent[i].EventComment);
   }
  }
return "";
}

Вспомогательная функция для определения, попадает ли текущее время в промежуток простоя

//проверим, не нужно ли отключить советник по новости True -работаем False - отдыхаем
bool CheckEnableNewsWork()        
  {
  if (ArraySize(NewsEventTime)==0) return true; //по какой-то причине массив с расписанием оказался пустой, значит работаем
  
   //теперь нужно найти ближайшую дату в NewsEventTime перед которой нужно остановить работу за StopPriorEventHours часов
  datetime timeCurrent =TimeCurrent(); 
  
  datetime timeStopWork=timeCurrent+StopPriorEventHours*3600;

  //Если в NewsEventTime есть время, меньшее timeStopWork, то прекращаем работать
  int dateindex=ArrayBsearch(NewsEventTime,timeStopWork,WHOLE_ARRAY,0,MODE_ASCEND);

  datetime foundEventTime=NewsEventTime[dateindex];
  timeStopWork=foundEventTime-StopPriorEventHours*3600; //посчитаем время остановки от найденного времени
  datetime timeStartWork=foundEventTime+StartAfterEventHours*3600; //это время окончания отдыха
 
  //теперь проверим, находимся ли мы сейчас timeCurrent между timeStopWork и timeStartWork. Если да, то не работаем
   if (timeCurrent>=timeStopWork && timeCurrent<=timeStartWork)
   {
   DrawLabel("EnableNewsWork","Не работаем, новость: "+GetEventInfo(foundEventTime)+"",5,80,Red);
   return false;
   }
   else
   {
   DrawLabel("EnableNewsWork","Нормальная работа, новостей нет",5,80,Green);
   return true;
   }
              
}

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

//Проверяем наличие файла с новостями по таймеру
void OnTimer()
{
 if (StopOnNewsEvent)
 {
  LoadNews(); //читаем файл
 }
}

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

OnInit()
....
   
   if (StopOnNewsEvent) //Если задано, загрузим файл с новостями
    {
     bool tm=EventSetTimer(LoadNewsEventTimerInDay*86400); //запустим таймер для загрузки файла с расписанием
     if (!tm)  Alert("EventSetTimer error:",GetLastError());
     OnTimer();//Первый запуск сразу
    }

В каждом тике проверяем, можем ли мы открывать позиции. На трейлинг кстати это влиять не должно.

	
OnTick()	
....	
bool enableNewsWork=true; //можно работать по новостным событиям
 if (StopOnNewsEvent)
 {
    enableNewsWork=CheckEnableNewsWork(); //Если ограничение по новостям, проверим время
 }
 
   if (HaveMoney && enableNewsWork) Traiding(Pairs[0]); //проверка условий и открытие торговли по паре

Вот и все. К сожалению, на реальном счете я этот код пока не тестировал, так как писал в выходные, тики эмулировал таймером и текущее время, которое останавливается в выходные, менял вручную. Но на следующей неделе посмотрю уже в реале, в новой версии «Forex Grail 1.11» , куда я и встроил вышеприведенный код.

В дальнейшем, возможно, нужно сделать удобную утилиту для формирования файла ht-news.csv, например в той же программе Forex-Helper.

Предыдущая часть 8: Пишем Демо Версию.

Вы можете пропустить чтение записи и оставить комментарий. Размещение ссылок запрещено.

Оставить комментарий

Вы должны быть авторизованы, чтобы разместить комментарий.