Автоматизированный выбор ДЦ для эффективной работы экспертов

Автор: lexy Среда, Сентябрь 10th, 2014 Нет комментариев

Рубрика: Разное

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

  • Котировки. В разных ДЦ они слегка различаются из-за двух факторов — разные источники данных и разная степень фильтрации, сглаживающая котировки. Для некоторых экспертов это может стать существенным ударом. Могут возникать ситуации, что на одном ДЦ эксперт будет часто заключать сделки, а на втором — нет;
  • Проскальзывания. У разных брокеров они могут существенно различаться, что также может приводить к ухудшению характеристик эксперта из-за снижения математического ожидания прибыли;
  • Реквоты. У некоторых ДЦ они чаще, чем у других. Из-за этого на ДЦ с большим количеством реквотов эксперт будет упускать удачные точки для входа в рынок.

Таким образом, работоспособность некоторых экспертов начинает существенно зависеть от того ДЦ, на котором он запущен. Если бы не было выбора, то можно было бы смириться и с котировками, и с проскальзываниями, и с реквотами. Но если есть выбор, а он все больше и больше, то зачем это терпеть? Ведь можно сравнить множество ДЦ, собрать их технические характеристики, и, вооружившись такой информацией, отобрать лучшие ДЦ для своего эксперта.

Statistik

Конечно, можно запустить несколько терминалов от разных ДЦ, погонять месяц-другой и после этого определить полигоном для работы эксперта тот ДЦ, в котором прибыль максимальна. Но такое тестирование является малоинформативным. Хочется получить больше информации: среднее проскальзывание на сделку, количество реквотов, которое было при открытии на каждой конкретной сделке, время открытия каждой сделки и так далее. Чтобы не ковыряться в логах, был разработан проект под названием Statistik, базирующийся на следующем наборе правил:

  1. Эксперт делает анализ рынка, совершает транзакции, получает все интересующие нас данные о сделке и передает в общий модуль;
  2. В этом модуле находится вся информация о текущих и закрытых сделках, а также считается статистика по техническим характеристикам ДЦ;
  3. Должно быть максимум удобств для работы с большим количеством данных, чтобы просматривать только интересующую нас информацию, а не все, что может быть выведено и просчитано.

Проанализировав статистику (количество реквотов, время исполнения сделки, проскальзывания) и просмотрев все сделки, можно сделать вывод о том, с какими ДЦ лучше работать. Если статистика по всем ДЦ будет давать отрицательный результат, то следует пересмотреть некоторые параметры работы эксперта, например, время нахождения в рынке, частота сделок, и пересматривать их до тех пор, пока торговый робот не станет работать с прибылью. Если на каком-то этапе эксперт перестанет приносить прибыль на каком-то ДЦ, принося прибыль на других, то от тестирования на этом ДЦ отказываемся.

Теория

Организовать передачу данных от эксперта в приложение можно либо через файлы, либо через dll. Вариант с файлами проще в плане технической реализации, поскольку не требует привлечения серьезного системного программирования. Однако работать через файлы не очень удобно, ведь заранее неизвестно, где будут находиться клиентский терминал MetaTrader 4 для разных ДЦ, на каких валютах будет тестирование, что делать, если файлы потеряются и так далее. Если все хочется сделать динамически, красиво и с максимальной надежностью, то лучше реализовать обмен данными через dll.
Чтобы разные терминалы работали с одной и той же dll, ее нужно поместить в системную директорию windows\system32. Важно то, что эксперты с одного терминала грузят одну и ту же копию dll, потому что все они работают в рамках одного процесса, которым является терминал (terminal.exe в диспетчере задач), значит у них одно и то же адресное пространство, то есть они работают с одними и теми же переменными. У одного терминала с экспертами имеется своя копия dll на всех экспертов и одни и те же переменные, объявленные внутри dll, а у другого терминала — другая копия и уже другие переменные. Таким образом, один терминал не получит доступ к переменным другого терминала.
Мы хотим создать единое поле, в котором будут собираться данные от разных терминалов. Есть разные способы организовать синхронную работу нескольких процессов с одним полем данных. Можно реализовать через файлы, но опять встанет проблема прописывания пути, а если терминалов и экспертов много, то еще и быстродействия. Самое лучшее средство – это разделяемая оперативная память. Работа с ней требует повышенной внимательности и знаний особенностей используемой ОС (в нашем случае Windows), зато открывающиеся возможности безграничны. Для организации же последовательного доступа процессов к определенному блоку разделяемой памяти используется специальный механизм программных семафоров.
Итог теории: эксперты через dll пишут данные в разделяемую память, а приложение, назовем его Монитором, считывает их из этой памяти, отображает и проводит необходимые статистические расчеты. При первом обращении MetaTrader 4 к DLL, операционная система создает копию этой DLL для каждого терминала, поскольку каждый терминал является отдельным процессом. Схему работы можно увидеть на рисунке.

 

Практика

Эксперт

Формировать данные о происходящей сделке должен, разумеется, сам эксперт. Для передачи данных нужно сформировать интерфейс функций dll. Для реализуемой задачи хватит трех функций:

 bool NewExpert(string  isBrokerName, string isInstrument, int Digit);

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

bool NewDeal(string isInstrument, int Action, int magik,
double PriceOpen, int Slippage, int TimeForOpen, int Requotes);

Регистрация новой сделки происходит следующим образом. Поскольку терминал-процесс уже идентифицирован по имени брокера. Для идентификации новой сделки достаточно названия инструмента, по которому осуществляется сделка. Остальные параметры – это характеристика сделки.

Таблица1. Открытие сделки

Параметр

Значение

Action

0 – buy, 1 — sell

magik

мэджик

PriceOpen

Цена открытия

Slippage

Проскальзывание

TimeForOpen

Длительность открытия

Requotes

Количество полученных реквотов

bool CloseDeal(string isInstrument, int magik, double PriceClose,
               int Slippage, int TimeForClose, int Requotes);

Закрытие сделки идентифицируется по инструменту и мэджику. Передаваемые параметры:

Таблица2. Закрытие сделки

Параметр

Значение

PriceClose

Цена закрытия

Slippage

Проскальзывание

TimeForClose

Длительность закрытия

Requotes

Количество полученных реквотов

 

С учетом этого интерфейса, инициализация, функции открытия и закрытия сделок будут выглядеть примерно так:
Инициализация:

int init()
  {
   int Digit;
   if(IsDllsAllowed() == false)
     {
       Print("Вызов из библиотек (DLL) невозможен." +
             " Эксперт не может выполняться.");
       return(0);
     }
   if(!IsTradeAllowed())
     {
       Print("Торговля  не разрешена!");
       return(0);
     }
   Digit = MarketInfo(Symbol(), MODE_DIGITS);
   if((Digit > 0) && (Bid > 0))
     {
       if(!NewExpert(AccountServer(), Symbol(), Digit))
         {
           Print("Не удалось создать нового брокера");
           return (0);
         }
       Print("Брокер успешно создан ");
       return(0);
     }
   Print("Символа нет в MarketInfo!");
   return(0);
  }

При инициализации после проверки параметров терминала (разрешение торговли и подтверждение вызова DLL) происходит получение информации о разрядности инструмента и его текущей цене. Если оба параметра больше нуля, то инструмент адекватно представлен в терминале и с ним можно работать. Каждый брокер отличается своим именем, которое можно получить с помощью функции AccountServer(), по этому имени терминалы отличаются друг от друга в разделяемой памяти. Эксперты же различаются по названию инструмента, на котором они торгуют. Поэтому, если повесить разных экспертов на одной и той же валютной паре, они будут грузить одну и ту же копию DLL, что может привести к коллизии.

Функция открытия нового ордера:

int Deal(int act, double Lot)
  {
   int N = 0;
   int ticket;
   int err;
   double Price_open;
   double Real_price;
   datetime begin_deal;
   double Lots;
   int cmd;
   int magik;
   magik = GenericMagik() + 1;
   Lots = NormalizeDouble(Lot, 1);
// проверка маржи для открытия позиции
   AccountFreeMarginCheck(Symbol(), cmd, Lots);
   err = GetLastError();
   if(err > 0)
     {
       Print("No money for new position");
       return(0);
     }
   begin_deal=TimeCurrent();
   while(N < count)
     {
       if(act == 1)
         {
           Price_open = NormalizeDouble(Ask, Digits);
           cmd = OP_BUY;
         }
       if(act == 2)
         {
           Price_open = NormalizeDouble(Bid, Digits);
           cmd = OP_SELL;
         }
       ticket = OrderSend(Symbol(), cmd, Lots, Price_open,
                          slippage, 0, 0, 0, magik);
       if(ticket > 0)
         {
           if(OrderSelect(ticket, SELECT_BY_TICKET) == true)
             {
               Real_price = OrderOpenPrice();
               NewDeal(Symbol(), cmd,magik, Real_price ,
                       MathAbs(Real_price - Price_open),
                       (TimeCurrent() - begin_deal), N);
             }
           return(ticket);
         }
       N++;
       Sleep(5000);
       RefreshRates();
     }
   return(0);
  }

Ордер открывается при помощи функции Deal с двумя параметрами: действие (1 — buy, 2 — sell ) и лот. Каждая сделка по одному инструменту отличается от предыдущей меджиком — он инкрементируется. Сделка пытается открыться за count попыток. Это количество попыток наряду с длительностью открытия, ценой и проскальзыванием по сделке передается в разделяемую память, откуда считывается монитором.
Функция закрытия ордера:

bool CloseOrder(int magik)
  {
   int ticket, i;
   double Price_close;
   int count = 0;
   datetime begin_time;
   double Real_close;
   begin_time = TimeCurrent();
   for(i = OrdersTotal() - 1; i >= 0; i--)
     {
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
           if(OrderSymbol() == Symbol())
               if(OrderMagicNumber() == magik)
                 {
                   while(count < 10)
                     {
                       if(OrderType() == OP_BUY)
                           Price_close = NormalizeDouble(Bid, Digits);
                       if(OrderType() == OP_SELL)
                           Price_close = NormalizeDouble(Ask, Digits);
                       if(OrderClose(OrderTicket(), OrderLots(),
                                     Price_close, slippage))
                         {
                           Real_close = OrderClosePrice();
                           CloseDeal(Symbol(), magik, Real_close,
                                     MathAbs(Real_close - Price_close),
                                     (TimeCurrent() - begin_time), count);
                           return(true);
                         }
                       count++;
                       Sleep(5000);
                       RefreshRates();
                     }
                 }
     }
   return(false);
  }

Функция закрытия CloseOrder() имеет только один входной параметр — меджик. Ордер пытается закрыться несколько раз и это количество попыток будет передано вместе со временем исполнения транзакции, ценой закрытия и проскальзыванием в память, откуда данные будут считаны монитором.

Весь остальной код – это тестируемый эксперт. Таким образом, для того, чтобы использовать Statistik в своих экспертах, надо импортировать нужные функции dll, а также для инициализации и открытия/закрытия сделок пользоваться функциями Deal и CloseOrder. Желающие могут переписать и эти функции, но передавать данные о сделке все равно нужно в соответствии с тем интерфейсом,который предлагается в dll.
Пример реализации такого эксперта с подключеним и использованием DLL, без дублирования кода вышеперечисленных функций, приведен ниже.

// Подключаем dll для работы с монитором
#import "statistik.dll"
  bool NewExpert(string  isBrokerName, string isInstrument,
                 int Digit);   // Создаем брокера
  bool NewDeal(string isInstrument, int Action, int magik,
               double PriceOpen, int Slippage, int TimeForOpen,
               int Requotes);
  bool CloseDeal(string isInstrument, int magik, double PriceClose,
                 int Slippage, int TimeForClose,
                 int Requotes);
#import
//----
extern int Num_Deals = 3;
extern int TimeInMarket = 4;
// максимальное допустимое проскальзывание
int  slippage = 10;
// время для отдыха после сделки
int TimeForSleep = 10;
// период запроса
int time_for_action = 1;
// количество попыток открытия позиции
int count = 5;
// Функция нового бара
bool isNewBar()
  {
    static datetime BarTime;
    bool res = false;
    if(BarTime != Time[0])
      {
        BarTime = Time[0];
        res = true;
      }
   return(res);
  }
//+------------------------------------------------------------------+
//| Генерация magik                                                  |
//+------------------------------------------------------------------+
int GenericMagik()
  {
   int deals;
//----
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
           if(OrderSymbol() == Symbol())
               if(OrderMagicNumber() != 0)
                   deals++;
     }
   return (deals);
  }
//+------------------------------------------------------------------+
//| формирование сигналов на открытие/закрытие позиции               |
//+------------------------------------------------------------------+
int GetAction(int &action, double &lot, int &magik)
   {
    int cnt, total;
    if(OrdersTotal() <= Num_Deals)
      {
        if(Close[1] > Close[2])
          {
            action = 1;
            lot = 1;
            return(0);
          }
        if(Close[2] < Close[1])
          {
            action = 2;
            lot = 1;
            return(0);
          }
      }
    total = OrdersTotal();
    for(cnt = total - 1; cnt >= 0; cnt--)
      {
        if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
            if(OrderSymbol() == Symbol())
                if((TimeCurrent() - OrderOpenTime()) > TimeInMarket*60)
                  {
                    action = 3;
                    magik = OrderMagicNumber();
                    return(0);
                  }
      }
   }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   int action = 0;
   double lot = 1;
   int magik = 0;
   while(!IsStopped())
     {
       Sleep(time_for_action*1000);
       RefreshRates();
       if(isNewBar())
         {
           GetAction(action, lot, magik);
           if(((action == 1) || (action == 2)))
             {
               if(IsTradeAllowed())
                   Deal(action, lot);
               Sleep(TimeForSleep*1000);
             }
           if(action == 3)
             {
               if(IsTradeAllowed())
                   if(!CloseOrder(magik))
                     {
                       Print("ТРЕБУЕТСЯ РУЧНОЕ ЗАКРЫТИЕ СДЕЛКИ");
                       Sleep(TimeForSleep*1000);
                     }
             }
           action = 0;
           lot = 0;
           magik = 0;
         }
     }
   Print("Возникла серьезная ошибка и эксперт остановил свою работу");
   return(0);
  }
//+------------------------------------------------------------------+

Исполнительный блок эксперта — это бесконечный цикл в функции старт. С заданной частотой time_for_action эксперт обращается к аналитической функции GetAction() , которая по ссылке возвращает действие, которое необходимо выполнить эксперту, лот, с которым надо открыть сделку, а также меджик, в случае, если сделку необходимо закрыть.

Аналитический блок в данном эксперте является примитивным — buy, если предыдущий бар больше предпредыдущего, и sell, в противном случае. Сделки закрываются по времени. Для тестирования своих экспертов достаточно переписать этот блок в соответствии с тем алгоритмом, который в них заложен. Исполнительную часть можно оставить без изменений.

DLL

DLL можно реализовать в разных средах и на разных языках. Необходимая для нашей работы dll была создана в Visual C++. Сделки будут представлять собой структуры вида

struct DealRec
  {
    int Index;
    int Magik;
    int Cur;
    int Broker;
    double PriceOpen;
    double PriceClose;
    int SlipOpen;
    int SlipClose;
    int Action;  // 0 = BUY 1 = SELL
    int TimeForOpen;
    int TimeForClose;
    int ReqOpen;
    int ReqClose;
    int Profit;
    bool Checked; // признак того, что сделка закрыта
  };

 

и заполняться в два этапа – на открытии и на закрытии. То есть часть данных (цена открытия, проскальзывания на открытии и так далее) передаются на открытии сделки, а другая часть (цена закрытия, время закрытия сделки и так далее) передается на закрытии сделки. Прототипы вызова функций в dll

__declspec(dllexport) bool __stdcall NewExpert (char *isBrokerName,
                                                char *isInstrument,
                                                int Digit);
__declspec(dllexport) bool __stdcall NewDeal (char *isInstrument,
                                              int Action,
                                              int magik,
                                              double PriceOpen,
                                              int Slippage,
                                              int TimeForOpen,
                                              int Requotes);
__declspec(dllexport) bool __stdcall CloseDeal (char *isInstrument,
                                                int magik,
                                                double PriceClose,
                                                int Slippage,
                                                int TimeForClose,
                                                int Requotes);

отличаются от прототипов в языке MQL4 только передачей строк. Все желающие могут посмотреть исходники dll, которые могут помочь при создании других проектов. Для перекомпиляции проекта нужно открыть файл statistik.dsw прогаммой Visual C++. Весь код dll содержится в файлах statistik.cpp и statictik.h, остальные — вспомогательные. Все указанные файлы содержатся в прикрепленом архиве Statistik.zip.

Монитор

Оптимальный инструмент для быстрого написания приложений с таблицами и графическим интерфейсом – решения от Borland. Это Delphi и C++Builder.

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

  1. Ведение журнала открытых сделок;
  2. Ведение журнала закрытых сделок;
  3. Статистика по проскальзываниям и реквотам;
  4. Настраиваемые таблицы;
  5. Сохранение сделок в html-файл.

 

Реализацию можно увидеть в прикрепленном архиве Statistik Monitor.zip. Для перекомпиляции проекта нужна программа C++Builder. Расширение файла проекта — *.bpr. Основной код — в main.cpp.

Тестирование

Для тестирования был создан эксперт с простейшими условиями для входа и закрытием сделки по времени, реализация которого приведена выше. Сам эксперт вместе с dll и monitor.exe содержится в архиве монитор+dll+эксперт.zip. При запуске нажимаем на кнопку СТАРТ – создаем разделяемую память. DLL должна находиться в папке system32. После этого запускаем несколько терминалов и прикрепляем эксперта к графикам валют, на которых он будет торговать. После множества сделок накапливается необходимая статистика. Данные собираются в мониторе на вкладе Журнал сделок, который периодически надо сбрасывать в файл, хранящийся в виде html странички.

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

Заключение

Поддержка dll в языке MQL4 позволяет делать разнообразные прикладные программы, которые дают возможность не только принимать решения о торговле, но и собирать статистику. Последняя может пригодиться в торговле, а также в выборе ДЦ. Созданное приложение должно помочь разработчикам в этом нелегком поиске. Для того, чтобы анализировать брокеров, нужно подключить statistik.dll к эксперту, по образцу, показанному в статье. Необходимые для работы файлы прикреплены в монитор+dll+эксперт.zip. Для работы нужно скопировать statistik.dll в папку system32, запустить Statistik.exe из любого места и открыть терминалы с экспертами, которые загружают dll, начинают торговать и передавать свои данные в разделяемую память. Statistik.exe при своей работе создает вспомогательный файлы, поэтому лучше запустить приложение из какой-нибудь пустой папки. Программа может дорабатываться и модифицироваться, если к ней возникнет интерес разработчиков торговых роботов.

Следует отметить, что для автоторговли не все ДЦ предоставляют одинаковые условия:

  1. Брокер может запретить автоторговлю;
  2. Может запретить одновременно при выставлении ордера указывать SL или TP http://forum.mql4.com/ru/6615;
  3. Несимметричные уровни для SL и TP http://www.metaquotes.ru/forum/7293/;
  4. Возможность взаимооткрытия ордеров может отсутствовать;
  5. Ограничение на количество одновременно открытых позиций на счету. При превышении разрешенного количества ордеров (открытых позиций + отложенных ордеров) функция OrderSend вернет код ошибки ERR_TRADE_TOO_MANY_ORDERS.
  6. Другие ограничения.

Поэтому нужно внимательно читать регламент дилингового центра, в котором Вы собираетесь открывать счет.
Проект Statistik показывает, какие комплексы можно создавать, если к средствам языка MQL4 добавить мощь других языков и сред программирования. Созданная программа будет полезна для экспертов, работающих с разными ДЦ, поскольку позволит в удобном виде провести анализ технических характеристик последних. Если у ДЦ большие проскальзывания, сделки долго исполняются по времени, часто возникают реквоты, то зачем нам такой ДЦ? Ведь есть множество альтернатив!

Прикрепленные файлы:
 Statistik Monitor.zip (219.4 Kb)
 Statistik.zip (24.3 Kb)
 монитор+dll+эксперт.zip (524.7 Kb)
Источник: mql4.com

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

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

Похожие посты