MetaTrader для работы на фондовом рынке – легко!

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

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

После легкости разработки торговых роботов под MetaTrader 4 неприятно удивляешься от того, с какими проблемами придется столкнуться при разработке ботов для нашего родного фондового рынка. Самая популярная программа у российских брокеров – QUIK. В программе есть встроенный язык программирования – QPILE, позволяющий делать простенькие скрипты, но его возможностей явно недостаточно для разработки полноценных торговых роботов, о тестировании речи вообще нет. Поэтому придется искать какой-нибудь обходной путь.

Возможности QUIK

Для обмена информацией между QUIK и внешней программой используются текстовые файлы фиксированной структуры:

  • *.tri – файл с параметрами транзакций
  • *.tro – файл с результатами посылки транзакций в торговую систему
  • *.trr – файл, содержащий журнал обработки транзакций

Схема взаимодействия между программами выглядит следующим образом:

1. Внешняя программа формирует транзакцию с заданными параметрами и записывает ее в виде новой строки в tri-файл. Транзакции идентифицируются по дополнительному целочисленному параметру TRANS_ID, содержащему уникальный номер.

2. Система QUIK опрашивает с определенной периодичностью tri-файл с параметрами транзакций и передает в торговую систему ранее не обработанные транзакции. Если описание транзакции не соответствует принятому формату, то она отвергается.

3. Результат действий записывается в tro-файл в формате, приемлемом для чтения внешней программой. Каждая строка файла содержит информацию об обработке отдельной транзакции, различаемые по параметру TRANS_ID.

ЗАМЕЧАНИЕ: Перед первым чтением tri-файла QUIK обращается к tro-файлу и считывает обработанные заявки. Заявки, содержащиеся в tro-файле, считаются обработанными, и строки в tri-файле с тем же параметром TRANS_ID игнорируются. Если внешняя программа при каждом запуске начинает нумеровать заявки сначала, то перед ее запуском необходимо удалить tro-файл из рабочей директории.

Таким образом, торговая операция будет совершена, если мы запишем строку, соответствующую формату QUIK, в файл транзакций. Записать строку-приказ можно из какой-либо внешней программы. Самые важные поля в строке-приказе, перечислены в таблице 1.

Значение Описание
CLASSCODE Код класса, по которому выполняется транзакция, например, EQBR. Обязательный параметр
SECCODE Код инструмента, по которому выполняется транзакция, например, EESR
ACTION Вид транзакции, имеющий одно из следующих значений:
• «NEW_ORDER» — новая заявка,
• «NEW_STOP_ORDER» — новая стоп-заявка,
• «KILL_ORDER» — снять заявку,
• «KILL_STOP_ORDER» — снять стоп-заявку,
• «KILL_ALL_ORDERS» – снять все заявки из торговой системы,
• «KILL_ALL_STOP_ORDERS» – снять все стоп-заявки
ACCOUNT Номер счета Трейдера, обязательный параметр
CLIENT_CODE 20-ти символьное составное поле, может содержать код клиента и текстовый комментарий с тем же разделителем, что и при вводе заявки вручную.
TYPE Тип заявки, необязательный параметр. Значения: «L» – лимитированная, «M» – рыночная.
OPERATION Направление заявки, обязательный параметр. Значения: «S» – продать, «B» – купить.
QUANTITY Количество лотов в заявке, обязательный параметр
PRICE Цена заявки, за единицу инструмента. Обязательный параметр.
STOPPRICE Стоп-цена, за единицу инструмента. Используется только при «ACTION» = «NEW_STOP_ORDER»
STOP_ORDER_KIND Тип стоп-заявки.
• «SIMPLE_STOP_ORDER» – стоп-лимит,
• «WITH_LINKED_LIMIT_ORDER» – со связанной заявкой,
• И т.д.
EXPIRY_DATE Срок действия стоп-заявки. Возможные значения:
• «GTC» – до отмены.
• Дата в формате «ггггммдд», где «гггг» – год, «мм» – месяц, «дд» – день.
TRANS_ID Уникальный идентификационный номер заявки

Более подробно с форматом приказов в QUIK можно познакомиться, скачав приложенный файл. Для разработки «мозга» торгового робота существует множество решений, с некоторыми из них мы сейчас познакомимся.

Программы для разработки торгового робота

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

MetaStock

Программа MetaStock — самая старая программа для технического анализа, первая версия появилась в 1986 году. Внутренние средства для создания торговых роботов являются несовершенными в силу слабости языка программирования. Данные тестирования могут сильно отличаться от реальных в силу множества лазеек для «заглядывания» в будущее. Кроме того, MetaStock очень привередлив – не на каждом компьютере он будет стабильно работать. Ситуация, когда программа вылетает 1-2 раза в день, – типична. Еще одним минусом будет высокая стоимость лицензионной программы.

Omega Research

Программа Omega Research TradeStation 2000i — это функционально законченная исследовательская платформа с широким спектром возможностей. Программа строится на трех базовых компонентах:

а) Omega Research GlobalServer;

б) ProSuite Desktop;

в) EasyLanguage PowerEditor.

Язык для разработки ТС по виду похож на Visual Basic, но по своим возможностям стоит гораздо ниже. Тем не менее, в Omega можно создавать очень приличных по уровню сложности торговых роботов, а данные тестирования весьма близки к реальности. Недостатки – громоздкость платформы, сложность в установке, слабофункциональный язык, высокая стоимость.

Wealth Lab

Wealth-Lab Developer — это программа, обеспечивающая полноценную среду для создания и тестирования торговых систем для любых финансовых рынков.

По умолчанию в программе уже есть установленные торговые системы. Описываются они в ChartScripts. ChartScript может содержать правила и стратегии торговли (торговые инструкции) и инструкции для отображения индикаторов и графических объектов на диаграмме. Язык программирования очень близок к Pascal, на котором школьники и студенты знакомятся с программированием.

Слабости программы – нестабильность работы в режиме реального времени, что делает технический риск работы робота крайне высоким, а также стоимость.

MetaTrader 4

Рассмотрим теперь MetaTrader. Первое, что бросается в глаза – язык. СИ ориентированный MQL4 на голову выше языков программирования, используемых в других платформах. Программа бесплатная, и если для частного лица это философский вопрос, то для юридических лиц это важный фактор при выборе программы. Также программа куда проще в установке, меньше весит и бесперебойно работает на любой машине.

Недостаток только один – сами данные. В MetaStock, Omega и Wealth-Lab данные экспортируются напрямую из QUIK в режиме реального времени, а в MetaTrader – свой собственный источник данных. Расхождение цен между реальными данными и данными в MetaTrader невелико, поэтому нормальные непипсовочные стратегии будут отлично работать и на данных MT.

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

Функции для записи приказов в файл

Анализ полей для приказа-строки показывает, что некоторые из них будут повторяться для каждой транзакции, их вынесем в глобальные переменные. Нужно учесть, что при покупке дается плечо, а при продаже – нет. Поэтому максимальное количество акций для покупки и для продажи будет разное. Автор создавал робота для брокерской компании, поэтому предусмотрена возможность работы по нескольким клиентским счетам. Основные функции – открытие новой позиции (DEAL), установка стопа (Stop-Limit) и снятие ордеров (KillOrders) будут выглядеть следующим образом:

//ЗАЯВКА//
bool DEAL   (string TYPE,string ACTION,string OPERATION,string PRICE,string POSITION)
{
  string CLIENT_CODE;  
  int QUANTITY_BUY;  
  int QUANTITY_SELL;  
  int QUANTITY;    
   //Открытие файлов    
   HandleFileRequests=FileOpen(FileRequests,FILE_CSV|FILE_READ|FILE_WRITE,';');
   if(HandleFileRequests<1)  
   { Print("Файл для импорта транзакций не обнаружен, последняя ошибка ", GetLastError());    
     return(false);   }    
   //Запись в файлы  
   for(int i=0;i<COUNT_CLIENT;i++)  
   { CLIENT_CODE=CLIENT_CODES[i];      
     QUANTITY_BUY=CLIENT[i];      
     QUANTITY_SELL=CLIENT[i];      
     if (OPERATION=="B" && POSITION=="OPEN")         QUANTITY=QUANTITY_BUY;      
     if (OPERATION=="B" && POSITION=="CLOSE")        QUANTITY=QUANTITY_SELL;      
     if (OPERATION=="S" && POSITION=="OPEN")         QUANTITY=QUANTITY_SELL;      
     if (OPERATION=="S" && POSITION=="CLOSE")        QUANTITY=QUANTITY_BUY;      
     TRANS_ID++;          
     FileSeek(HandleFileRequests,0,SEEK_END);          
     FileWrite(HandleFileRequests, "TRANS_ID="+TRANS_ID, ACCOUNT,  "CLIENT_CODE="+CLIENT_CODE, 
           CLASSCODE, SECCODE, "TYPE="+TYPE, "ACTION="+ACTION, "OPERATION="+OPERATION, 
           "PRICE="+PRICE, "QUANTITY="+QUANTITY+";" );
   }  
   GlobalVariableSet(ID,TRANS_ID);  
   FileClose(HandleFileRequests);
}

//СТОП-ЛИМИТ//    
bool Stop   ( string ACTION, string OPERATION, string STOPPRICE, string PRICE )
{  
   string CLIENT_CODE;  
   int QUANTITY_BUY;  
   int QUANTITY_SELL;  
   int QUANTITY;    
   //Открытие файлов    
   HandleFileRequests=FileOpen(FileRequests,FILE_CSV|FILE_READ|FILE_WRITE,';');  
   if(HandleFileRequests<1)  
   { Print("Файл для импорта транзакций не обнаружен, последняя ошибка ", GetLastError());      
     return(false);   }
   //Запись в файлы  
   for(int i=0;i<COUNT_CLIENT;i++)  
   {      
      CLIENT_CODE=CLIENT_CODES[i];
      QUANTITY_BUY=CLIENT[i];
      QUANTITY_SELL=CLIENT[i];
      if (OPERATION=="S")  QUANTITY=QUANTITY_BUY;  
      if (OPERATION=="B")  QUANTITY=QUANTITY_SELL;
      TRANS_ID++;        
      FileSeek(HandleFileRequests,0,SEEK_END);  
      FileWrite(HandleFileRequests, "TRANS_ID="+TRANS_ID,  ACCOUNT, "CLIENT_CODE="+CLIENT_CODE,
            CLASSCODE, SECCODE, "ACTION="+ACTION, "OPERATION="+OPERATION, "QUANTITY="+QUANTITY,
            "PRICE="+PRICE, "STOPPRICE="+STOPPRICE,"EXPIRY_DATE=GTC;" );
   }
   GlobalVariableSet(ID,TRANS_ID);  
   FileClose(HandleFileRequests);}

//Снять все ордера//    
bool KillOrders   ( string ACTION )
{   string CLIENT_CODE;      
   //Открытие файлов  
   HandleFileRequests=FileOpen(FileRequests,FILE_CSV|FILE_READ|FILE_WRITE,';');
   if(HandleFileRequests<1)  
   {      Print("Файл для импорта транзакций не обнаружен, последняя ошибка ", GetLastError());      
          return(false);   }        
 //Запись в файлы  
   for(int i=0;i<COUNT_CLIENT;i++)  
   {      
      CLIENT_CODE=CLIENT_CODES[i];
      TRANS_ID++;        
      FileSeek(HandleFileRequests,0,SEEK_END);        
      FileWrite(HandleFileRequests,  "TRANS_ID="+TRANS_ID, CLASSCODE, SECCODE, "ACTION="+ACTION,
                        "CLIENT_CODE="+CLIENT_CODE+";" );
   }
   GlobalVariableSet(ID,TRANS_ID);   FileClose(HandleFileRequests);
}

TRANS_ID вынесена в отдельную глобальную переменную, потому что при выключении терминала переменная должна быть сохранена, в противном случае значение счетчика транзакций сбросится, и новые ордера не будут выполняться, поскольку их TRANS_ID будут совпадать с уже выполненными, которые будут храниться в файле Trans.tro.

В переменной FileRequests хранится имя файла, в который записываются строки-приказы.

Результатом выполнения каждой функции будет создание строк в файле trans.tri, которые затем обработаются QUIKом и превратятся в реальные сделки.

Простейший торговый робот

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

В качестве генератора сигналов входа, для примера, используем сглаженные цены – экспоненциальные скользящие средние (EMA) с длинным (EMA Long) и с коротким (EMA Short) периодами. Правила работы торгового робота заключаются в следующем:

а) вход в длинную позицию (покупка актива) осуществляется, когда EMA Short> EMA Long;

б) вход в короткую позицию (продажа актива) осуществляется, когда EMA Short< EMA Long;

в) если есть открытая позиция, то все сигналы игнорируются;

г) после открытия позиции устанавливается защитный ордер (Стоп-Лосс);

д) если тенденция разворачивается в сторону открытой позиции, то защитный ордер начинает двигаться за ценой (Trailing Stop);

е) сигналы в начале сессии и в конце – игнорируются;

Алгоритмически перенос стоп-заявки двусоставной. Сначала снимаются предыдущие заявки, а потом выставляются новые. В результате функция трейлинга будет иметь следующий вид:

//Трейлинг-стоп
bool Trailing()
  {
   string Stop_Price;
   string Price;  
   int N=OrdersTotal();
   for(int i = N - 1; i >= 0 ; i--)
      {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)        break;
      if( OrderSymbol()!=Symbol()) continue;
         if(OrderType() == OP_BUY)            
            if(TrailingStop > 0)
               if((Bid-OrderOpenPrice()) > (Point*TrailingStop))
                  if((OrderStopLoss()+TrailingStop*Point) < (Bid-Point*TrailingStop))
                     {
                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,
                                                       OrderTakeProfit(),0,GreenYellow);
                     //Запись трейлинга в файл
                     KillOrders("KILL_ALL_STOP_ORDERS");
                     Stop_Price=DoubleToStr(Bid-Point*TrailingStop,2);                    
                     Price=DoubleToStr(Bid-Point*TrailingStop-Bid*0.0006,2);
                     Stop("NEW_STOP_ORDER","S",Stop_Price,Price);                    
                     return(0);
                     }

            if(OrderType() == OP_SELL)                                                                      
               if(TrailingStop > 0)
                  if(OrderOpenPrice()-Ask>Point*TrailingStop)
                     if(OrderStopLoss()-TrailingStop*Point>Ask+Point*TrailingStop)
                        {
                        OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,
                                                                  OrderTakeProfit(),0,Red);
                        //Запись трейлинга в файл
                        KillOrders("KILL_ALL_STOP_ORDERS");
                        Stop_Price=DoubleToStr(Ask+Point*TrailingStop,2);                    
                        Price=DoubleToStr(Ask+Point*TrailingStop+Ask*0.0006,2);
                        Stop("NEW_STOP_ORDER","B",Stop_Price,Price);                                                  
                        return(0);              
                        }
      }
  }

 

Опыт реальной эксплуатации

Полученная модель робота представлена на рисунке 1.

Рассмотрим достоинства и недостатки данной модели:

Достоинства:

1) Можно реализовать любые торговые системы благодаря возможностям MQL4

2) Работает без сбоев

Недостатки:

1) Данные в MT могут слегка отличаться от реальных

2) Данные из MT могут не идти из-за технические проблем серверов

3) Требуется контроль синхронизации между сделками в MT и реальными сделками

4) Требуется изменение лотов примерно раз в 2 недели, поскольку постоянно меняются цены на акции и капитал

 

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

При работе с большим количеством счетов возникают дополнительные проблемы – постоянное добавление новых клиентов требует перекомпиляции экспертов, при этом открытые позиции и их параметры «забываются». Проблема забывания решается с помощью семафоров. Но проблема добавления/удаления клиентов, изменение объемов средств для каждого клиента (вводы-выводы денег, изменение цен акций, добавление новых роботов) в рамках MetaTrader решить проблематично.

Комплексный модуль управления счетами

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

 

В новой схеме добавляется база данных, в которой хранится информация о ценах на акции, денежных средствах клиентов, доля капитала для каждого робота и прочая полезная информация. Роботы на mql4 немного переделываются – теперь строчки-приказы формируются не в них, а в программе RoboTrader (авторская разработка). Структура команды от роботов к модулю управления счетами может быть разной, например (для функции Deal):

 //ЗАЯВКА
 bool DEAL(string TYPE,string ACTION,string OPERATION,string PRICE,string POSITION   )
 {    
  //Открытие файлов    
   HandleFileRequests=FileOpen(FileRequests,FILE_CSV|FILE_READ|FILE_WRITE,';');  
   if(HandleFileRequests<1)  
   {   Print("Файл для импорта транзакций не обнаружен, последняя ошибка ", GetLastError());      
       return(false);   }    
  //Запись в файлы          
  FileSeek(HandleFileRequests,0,SEEK_END);      
  FileWrite(HandleFileRequests,"WITH STOP");      
  FileWrite(HandleFileRequests,RobotName);      
  FileWrite(HandleFileRequests,Paper);                
  FileWrite(HandleFileRequests,ACCOUNT,CLASSCODE,SECCODE,"TYPE="+TYPE,"ACTION="+ACTION,
                                                "OPERATION="+OPERATION,"PRICE="+PRICE+";");                                
  FileClose(HandleFileRequests);
  }

 

 

 

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

Выводы

Задача, которая перед нами стояла – автоторговля на фондовом рынке, решена. Приложенный файл робота можно использовать как шаблон при создании торговых роботов для ММВБ (для работы с фьючерсами РТС придется немного переделать).

Использование MetaTrader позволяет создавать торговых роботов любой сложности для работы на фондовом рынке. Кроме того, опыт реальной эксплуатации показал, что работа связки MT + QUIK является стабильнее остальных.

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

Прикрепленные файлы:
 quikref.zip (3.1 Mb)
 Stock Robot.mq4 (14.8 Kb)
Источник: mql4.com

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

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

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