MetaTrader для работы на фондовом рынке - легко!
Введение
После легкости разработки торговых роботов под 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 LabWealth-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.
Рассмотрим достоинства и недостатки данной модели:
Достоинства:
- Можно реализовать любые торговые системы благодаря возможностям MQL4
- Работает без сбоев
Недостатки:
- Данные в MT могут слегка отличаться от реальных
- Данные из MT могут не идти из-за технические проблем серверов
- Требуется контроль синхронизации между сделками в MT и реальными сделками
- Требуется изменение лотов примерно раз в 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 является работа с глобальными переменными, благодаря которым можно без нарушения процессов (чистка файла, остановка экспорта транзакций) остановить, либо продолжить торговлю.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Говорили мы тебе, заберём все твои денежки, мурчик, а ты не слушал и не делал что следует, вот теперь проклятие работает... Тем не менее была достоверная инфа с форумов что "Отскок уже близко" 😉
Ничего) Когда-нибудь я сам буду знать "достаточно" :)
дважды) жду откат до 14:00)
Или лось будет больше, если не откатит или ниже спустится)
ВТБ выше 0.04 смысла нет брать. Смотрите более большие ТФ чтоб ориентироваться по среднему ходу цены.
А от 0.04 можно начинать портфель их собирать.
ВТБ выше 0.04 смысла нет брать. Смотрите более большие ТФ чтоб ориентироваться по среднему ходу цены.
А от 0.04 можно начинать портфель их собирать.
Фьючерсы пока по средней цене) Дальше видно будет куда что брать и какой портфель) Я близок))
Фьючерсы пока по средней цене) Дальше видно будет куда что брать и какой портфель) Я близок))
Ни когда не вникал в это.
Сделал по вашему примеру
Робот пишет строку
TRANS_ID=10464;ACCOUNT=SPBFUT17Iwi;CLIENT_CODE=SPBFUT17Iwi;TYPE=L;CLASSCODE=SPBFUT;SECCODE=SiZ4;ACTION=NEW_ORDER;OPERATION=S;PRICE=91473;QUANTITY=1;
Но когда Квик его считывает постоянно выскакивает окно
Но если сделать следующее.
Взять, скопировать данную строку, удалить старый файл который создал МТ5 терминал и создать текстовый файл заменив ему расширение .tri
далее вставить в него нашу строку и загрузить этот файл терминалом квик, вуаля, все работает, сделка установилась.
Какие бы я не делал махинации с чисткой файла .tro что бы не было в нем айдишников и т.д. стоит загрузить файл созданный терминалом мт5, выскакивает окно, делаем файл руками, квик его подхватывает, до того момента пока МТ5 в него не сделает запись, как только делается запись, снова это окно.
Что сделать не подскажите, может какая кодировка, может какие то атрибуты файла чтения нужно сменить.