
Автоматизированный выбор ДЦ для эффективной работы экспертов
Введение
Довольно часто возникают ситуации, когда эксперт успешно работает на одном ДЦ, при этом оставаясь на нуле или даже в минусе на другом. И причины этого могут быть неоднозначны. Все дело в настройках, которые могут варьироваться в разных ДЦ:
- Котировки. В разных ДЦ они слегка различаются из-за двух факторов - разные источники данных и разная степень фильтрации, сглаживающая котировки. Для некоторых экспертов это может стать существенным ударом. Могут возникать ситуации, что на одном ДЦ эксперт будет часто заключать сделки, а на втором - нет;
- Проскальзывания. У разных брокеров они могут существенно различаться, что также может приводить к ухудшению характеристик эксперта из-за снижения математического ожидания прибыли;
- Реквоты. У некоторых ДЦ они чаще, чем у других. Из-за этого на ДЦ с большим количеством реквотов эксперт будет упускать удачные точки для входа в рынок.
Statistik
Конечно, можно запустить несколько терминалов от разных ДЦ, погонять месяц-другой и после этого определить полигоном для работы эксперта тот ДЦ, в котором прибыль максимальна. Но такое тестирование является малоинформативным. Хочется получить больше информации: среднее проскальзывание на сделку, количество реквотов, которое было при открытии на каждой конкретной сделке, время открытия каждой сделки и так далее. Чтобы не ковыряться в логах, был разработан проект под названием Statistik, базирующийся на следующем наборе правил:
- Эксперт делает анализ рынка, совершает транзакции, получает все интересующие нас данные о сделке и передает в общий модуль;
- В этом модуле находится вся информация о текущих и закрытых сделках, а также считается статистика по техническим характеристикам ДЦ;
- Должно быть максимум удобств для работы с большим количеством данных, чтобы просматривать только интересующую нас информацию, а не все, что может быть выведено и просчитано.
Проанализировав статистику (количество реквотов, время исполнения сделки, проскальзывания) и просмотрев все сделки, можно сделать вывод о том, с какими ДЦ лучше работать. Если статистика по всем ДЦ будет давать отрицательный результат, то следует пересмотреть некоторые параметры работы эксперта, например, время нахождения в рынке, частота сделок, и пересматривать их до тех пор, пока торговый робот не станет работать с прибылью. Если на каком-то этапе эксперт перестанет приносить прибыль на каком-то ДЦ, принося прибыль на других, то от тестирования на этом ДЦ отказываемся.
Теория
Организовать передачу данных от эксперта в приложение можно либо через файлы, либо через 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.
Функции монитора – создать разделяемую память, считывать из нее данные и отображать в табличках, а также вести статистику по проскальзываниям. Помимо отображения сделок было еще реализовано несколько возможностей, которые должны сделать работу более удобной. Итоговый функционал монитора:
- Ведение журнала открытых сделок;
- Ведение журнала закрытых сделок;
- Статистика по проскальзываниям и реквотам;
- Настраиваемые таблицы;
- Сохранение сделок в 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 при своей работе создает вспомогательный файлы, поэтому лучше запустить приложение из какой-нибудь пустой папки. Программа может дорабатываться и модифицироваться, если к ней возникнет интерес разработчиков торговых роботов.
Следует отметить, что для автоторговли не все ДЦ предоставляют одинаковые условия:
- Брокер может запретить автоторговлю;
- Может запретить одновременно при выставлении ордера указывать SL или TP https://www.mql5.com/ru/forum/103341;
- Несимметричные уровни для SL и TP;
- Возможность взаимооткрытия ордеров может отсутствовать;
- Ограничение на количество одновременно открытых позиций на счету. При превышении разрешенного количества ордеров (открытых позиций + отложенных ордеров) функция OrderSend вернет код ошибки ERR_TRADE_TOO_MANY_ORDERS.
- Другие ограничения.
Поэтому нужно внимательно читать регламент дилингового центра, в котором Вы собираетесь открывать счет.
Проект Statistik показывает, какие комплексы можно создавать, если
к средствам языка MQL4 добавить мощь других языков и сред программирования.
Созданная программа будет полезна для экспертов, работающих
с разными ДЦ, поскольку позволит в удобном виде провести анализ
технических характеристик последних. Если у ДЦ большие проскальзывания,
сделки долго исполняются по времени, часто возникают реквоты,
то зачем нам такой ДЦ? Ведь есть множество альтернатив!





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Идея хороша, но на мой взгляд, не выполнима. Нам нужны данные по реальным счетам, ведь на демо реквотов не бывает и отработка моментальная. А вот подрисывать договора и открывать реальные счета в куче ДЦ только для тестирования ни кто не будет. Тем более, что реальный счёт от минифорекс счёта м то отлмчается. Но теория хороша....
А не подскажете что делать если картинка выглядит вот так?
поставить русский windows