За последние годы рынок форекс стал одним из самых популярных финансовых рынков для торговли. Из-за круглосуточной работы, высокого кредитного плеча и низкого уровня маржи тысячи простых людей стали активными трейдерами.
MetaTrader 4 (MT4) — это одна из самых популярных торговых платформ для торговли на форекс. MetaTrader, разработанный MetaQuotes Software Corporation, предлагается сотнями форекс-брокеров по всему миру, в том числе такими громкими именами, как GAIN Capital, FXCM, Alpari и Interbank FX.
Популярность MetaTrader обусловлена тем, что эта торговая платформа полностью бесплатная и включает в себя множество полезных инструментов технического анализа. Но, вероятно, главной причиной успеха MetaTrader является мощный язык программирования MQL.
MQL позволил трейдерам программировать собственные пользовательские индикаторы и стратегии автоматической торговли, не платя ни копейки за программное обеспечение. Подобные торговые пакеты для акций и фьючерсов могут стоить более 1000 долларов. Появилось всемирное сообщество трейдеров и программистов, которые предлагают сотни бесплатных и коммерческих советников и индикаторов, а также услуги и советы по программированию.
Сходство MQL с такими языками, как C, позволяет опытным программистам относительно легко изучить его синтаксис, а сам язык достаточно хорошо документирован. Но обучение эффективному программированию торговых стратегий на MQL — это процесс постоянных проб и ошибок.
MQL является языком относительно низкого уровня, поэтому программисту необходимо создавать собственные процедуры для обработки торговых функций. Например, написание кода чего-то такого простого, как трейлинг-стоп, может быть пугающим для начинающего MQL-программиста.
При программировании надежной стратегии автоматической торговли необходимо учитывать множество факторов, и сам MetaTrader имеет много особенностей, о которых должен знать каждый программист.
На официальном веб-сайте MQL4 по адресу http://www.mql4.com есть бесплатная книга по программированию на MQL, которая может служить полезным и дополнительным ресурсом. На сайте также размещено множество статей, в которых рассматриваются базовые и продвинутые концепции программирования на MQL, библиотека кода, а также форум, где вы можете обратиться за помощью по вопросам программирования.
Что из себя представляет торговый советник?
Торговый советник — это программа автоматической торговли, написанная на MQL. Советники (сокращенно EA — Expert Advisors) могут размещать, изменять и закрывать ордера в соответствии с алгоритмом торговой системы. Советники обычно используют технические индикаторы для генерации торговых сигналов. Эти индикаторы могут быть теми, которые поставляются с MetaTrader, или они могут быть пользовательскими.
Индикатор — это инструмент технического анализа, который вычисляет ценовые данные, чтобы интерпретировать рыночную активность. Индикатор рисует линии или объекты на графике. Индикаторы не могут размещать, изменять или закрывать ордера. Примеры индикаторов: скользящая средняя и стохастик.
Скрипт — это упрощенный советник, который выполняет одну задачу, такую как установка отложенного ордера или закрытие всех ордеров на графике. Несколько полезных скриптов включены в MetaTrader.
Форматы файлов
Файлы с расширением .mq4 являются файлами исходного кода. Это файлы, которые мы редактируем в MetaEditor. Когда файл .mq4 компилируется, создается файл .ex4.
Файлы с расширением .ex4 являются исполняемыми файлами. Это файлы, которые мы запускаем в MetaTrader. Эти файлы не могут быть открыты в MetaEditor. Если у вас есть только файл .ex4 для советника или индикатора, значок рядом с именем файла в окне навигатора MetaTrader будет затемнен.
Файлы с расширением .mqh являются включаемыми файлами. Эти файлы содержат созданные пользователем функции, на которые есть ссылки в файле .mq4. Во время компиляции компилятор «включает» содержимое файла .mqh в файл .ex4.
Расширение .mqt используется для файлов шаблонов. Шаблоны используются для создания новых файлов с помощью MetaEditor. Вы можете также создавать свои собственные шаблоны.
Индикаторы, эксперты, библиотеки и скрипты имеют общее расширение .mq4. Единственный способ отличить их друг от друга — либо по месту сохранения, либо открыв файл и изучив его исходный код.
Расположение файлов
Все файлы MetaEditor хранятся в папке экспертов. Папка \experts находится в каталоге установки MetaTrader, который находится в C:\Program Files\. Папка \experts содержит исходный код и исполняемые файлы для экспертов.
Внутри папки \experts есть множество папок, содержащих другие типы исходного кода и исполняемых файлов. Вот список мест сохранения для всех типов файлов:
- \experts\indicators — здесь хранятся исходный код и исполняемые файлы ваших индикаторов.
- \experts\include — здесь находятся исходные коды включаемых файлов с расширением .mqh.
- \experts\libraries — здесь хранятся библиотеки функций и библиотеки DLL.
- \experts\scripts — здесь хранятся исходный код и исполняемые файлы скриптов.
- \experts\templates — здесь хранятся шаблоны для файлов с исходным кодом.
В папке экспертов есть еще несколько папок, о которых вы также должны знать:
- \experts\logs — журналы активности ваших экспертов хранятся здесь. Они будут полезны для отладки ваших советников.
- \experts\presets — здесь хранятся настройки советника, которые сохраняются или загружаются из диалога свойств MetaTrader.
- \experts\files — все файлы, используемые для ввода или вывода, должны храниться здесь.
MetaEditor
MetaEditor — интегрированная среда разработки (IDE) для MQL, которая поставляется в комплекте с MetaTrader. Он включает в себя полезные справочные материалы, инструменты поиска и автозаполнения, которые значительно упрощают написание кода на MQL.
Окно редактора позволяет открывать сразу несколько файлов. Вы можете свернуть, развернуть и перейти между несколькими открытыми окнами. Окно навигатора предлагает полезные функции просмотра файлов и справочные функции. В окне панели инструментов отображается содержание справки, ошибки компиляции, результаты поиска файлов и онлайн-доступ к статьям и файлам на MQL4.com.
Одна из самых полезных функций редактирования — Помощник. Просто введите первые несколько символов функции MQL, оператора или другого элемента языка, и появится раскрывающийся список. Нажмите Enter, чтобы принять выделенное предложение и автоматически завершить ввод части кода.
Вкладка «Файлы» в окне «Навигатор» — это простой файловый браузер, который позволяет открывать и редактировать любые файлы MQL в папке \experts. На вкладке «Словарь» имеется встроенная ссылка на MQL, а на вкладке «Поиск» — функция поиска.
Встроенная справка по MQL сэкономит вам много времени при написании кода. Если вам нужна помощь в запоминании синтаксиса определенного элемента языка, выберите или поместите текстовый курсор на элемент в окне редактора. Нажмите F1 на клавиатуре, и раздел справки появится в панели инструментов.
Панель инструментов в MetaEditor содержит стандартное дополнение к файлам и функциям редактирования. Кнопка «Скомпилировать» компилирует текущий файл в редакторе. Если есть какие-либо ошибки компиляции, они также будут показаны. Кнопка «Терминал» открывает торговый терминал для тестирования советников.
Синтаксис
Если вы знакомы с программированием на таких языках, как C ++, PHP или на одном из многих языков, синтаксис которых является производным от C, вам будет удобно программировать на MQL.
В MQL каждый оператор заканчивается точкой с запятой. Это называется выражением. Выражение может занимать несколько строк, но в конце должна стоять точка с запятой.
double LastHigh = High[1]; string MultiLine = StringConcatenate("Выражение в несколько строк ", "И еще выражение.");
Если вы новичок в программировании или привыкли к программированию на языке, в котором выражения не заканчиваются точкой с запятой, вам необходимо убедиться, что вы ставите точку с запятой в конце каждого оператора.
Однако есть несколько исключений из этого правила: составным операторам не нужна точка с запятой. Составной оператор — это блок кода, который содержит несколько выражений в фигурных скобках {}. Примеры составных операторов включают операторы управления потоком (if, switch), операторы цикла (for, while) и объявления функций.
if(Compound == true) { Print("Часть кода"); }
Обратите внимание, что после начального оператора if нет точки с запятой, а также нет точки с запятой после закрывающей скобки. Однако после функции Print() стоит точка с запятой. Внутри фигурных скобок может быть одно или несколько выражений. Каждое из них должно заканчиваться точкой с запятой.
Комментарии
Комментарии полезны для документирования вашего кода, а также для временного удаления кода во время тестирования и отладки. Вы можете закомментировать одну строку двумя косыми чертами:
// Это комментарий
Многострочный комментарий начинается с / * и заканчивается * /. Многострочный комментарий может занимать любое количество строк.
/ * Это блок комментариев Все здесь закомментировано * /
Идентификаторы
Идентификаторы — это имена, которые присваиваются переменным или функциям. Идентификатор может состоять из любой комбинацией цифр, букв или символа подчеркивания (_). Идентификаторы могут быть длиной до 31 символа.
Убедитесь, что ваш идентификатор не является зарезервированным словом в MQL. Вот пример идентификатора переменной и идентификатора пользовательской функции:
double StopLoss; int Order_Count()
Идентификаторы в MQL чувствительны к регистру. Это означает, что StopLoss и Stoploss — это разные идентификаторы.
Переменные
Переменная является основной единицей хранения любого языка программирования. Переменные содержат данные, необходимые для работы вашей программы. В них могут сохраняться цены, настройки и значения индикаторов.
Переменные должны быть объявлены до их использования. Чтобы объявить переменную, вы указываете ее тип данных, идентификатор и, опционально, значение по умолчанию. Если вы объявите переменную более одного раза или не объявите ее, вы получите ошибку компиляции.
Тип данных указывает тип информации, которую содержит переменная, будь то число, текстовая строка, дата или цвет. Вот типы данных в MQL:
- int — целое число, например 0, 3 или -5. Любое число, присвоенное целочисленной переменной, округляется до следующего целого числа.
- double — дробное число, такое как 1,5765, 0,03 или -2,376. Используйте их для ценовых данных или в математических выражениях, связанных с делением.
- string — текстовая строка. Строки должны быть заключены в двойные кавычки.
- логическое значение true/false. Может также быть представлен как 1 (true) или 0 (false).
- datetime — значение времени и даты, например 2009.01.01 00:00. Переменная datetime представлена как количество секунд, прошедших с 1 января 1970 года.
- color — константа, представляющая цвет, такой как Red или DarkSlateBlue. Они обычно используются для изменения цвета индикатора или какого-либо объекта на графике.
Вот пример объявления переменной. Это целочисленная переменная с идентификатором MyVariable и значением по умолчанию 1:
int MyVariable = 1;
Как только переменная была объявлена, вы можете изменить ее значение. Вот пример, где мы присваиваем число 5 нашей переменной MyVariable:
MyVariable = 5;
Вы также можете присвоить значение одной переменной через другую переменную:
int YourVariable = 2; MyVariable = YourVariable; // MyVariable равен 2
Присвоенная переменная должна быть того же типа данных. Например, если переменная типа Double назначена переменной типа Int, Double будет округлена до ближайшего целого числа. Это может привести к нежелательному результату.
Константы
Как следует из названия, константа — это значение данных, которое никогда не меняется. Например, число 5 является целочисленной константой, буква «A» является символьной константой, а 2009.01.01 — константой даты и времени на 1 января 2009 года.
В MQL есть множество стандартных констант. К примеру, данные о ценах, периоды графика, цвета и торговые операции. Например, PERIOD_H1 является константой для таймфрейма графика H1, OP_BUY относится к рыночному ордеру на покупку, а Red — это цветовая константа для красного цвета.
Вы даже можете создавать свои собственные константы, используя директиву препроцессора #define.
Функции
Функции являются строительными блоками современных языков программирования. Функция — это блок кода, предназначенный для выполнения определенной задачи, например, размещения ордера или расчета стоп-лосса. MQL имеет десятки встроенных функций.
Функции предназначены для многократного использования. Изучение того, как создавать функции для общих торговых задач, важно для продуктивного программирования.
Давайте начнем с простой функции PipPoint(), которая вычисляет количество десятичных знаков в текущей паре и автоматически настраивается для 3-х и 5-ти значных брокеров. Для пар с йеной (2 или 3 цифры) функция возвращает 0,01. Для всех остальных пар (4 и 5 цифр) функция возвращает 0,0001.
double UsePoint; UsePoint = PipPoint();
Мы объявляем переменную типа double с именем UsePoint. Затем мы вызываем функцию PipPoint() и присваиваем результат UsePoint. Теперь мы можем использовать значение, хранящееся в UsePoint, например, для расчета стоп-лосса.
Вот код для функции PipPoint():
double PipPoint() { if(Digits == 2 || Digits == 3) double UsePoint = 0.01; else if(Digits == 4 || Digits == 5) UsePoint = 0.0001; return(UsePoint); }
Первая строка — это объявление нашей функции. Как и переменные, объявления функций имеют тип данных и идентификатор. Функции используют такие же типы данных, что и переменные. Тип данных зависит от типа данных, которые возвращает функция. Поскольку эта функция возвращает дробное число, мы используем тип данных double.
Тело функции содержится в скобках {}. У нас есть оператор if-else, который выводит количество цифр после десятичного знака и присваивает соответствующее значение переменной UsePoint. После этого у нас следует оператор return, который возвращает значение UsePoint вызывающей функции.
Существует специальный тип данных для функций, которые не возвращают значение. Тип данных void используется для функций, которые выполняют определенную задачу, но не должны возвращать никакое значение. Пустые функции не требуют оператора возврата в теле функции.
Давайте рассмотрим простую функцию для размещения ордера на покупку. Эта функция имеет аргументы, которые необходимо передать в функцию. Функция будет выставлять рыночный ордер на покупку на текущий символ с указанным размером лота, стоп-лоссом и тейк-профитом.
int OpenBuyOrder(double LotSize, double StopLoss, double TakeProfit) { int Ticket = OrderSend(Symbol(),OP_BUY,LotSize,Ask,StopLoss,TakeProfit); return(Ticket); }
Эта функция имеет три аргумента: LotSize, StopLoss и TakeProfit. Аргументы — это переменные, которые используются внутри тела функции. Их значение присваивается вызывающей функцией. Вот как мы будем вызывать эту функцию в коде:
OpenBuyOrder(2, 1.5550, 1.6050);
Это позволит нам разместить ордер на покупку 2 лотов со стоп-лоссом 1,5550 и тейк-профитом 1,6050. Вот еще один пример использования переменных. Предположим, что переменным UseLotSize, BuyStopLoss и BuyTakeProfit присвоены соответствующие значения:
int GetTicket = OpenBuyOrder(UseLotSize,BuyStopLoss,BuyTakeProfit);
В этом примере мы присваиваем возвращаемое значение OpenBuyOrder() переменной GetTicket, в которой указан номер заявки только что размещенного нами ордера. Присвоение вывода функции переменной необязательно. Это необходимо только в том случае, если вы планируете проводить дальнейшую обработку с использованием номера тикета размещенного ордера.
Аргументы могут иметь значения по умолчанию, что означает, что если параметр явно не передан функции, аргумент примет значение по умолчанию. Значения аргументов по умолчанию всегда будут размещены в конце списка аргументов. Вот пример функции с несколькими значениями по умолчанию:
int DefaultValFunc(int Ticket, double Price, int Number = 0, string Comment = NULL)
Эта функция имеет два аргумента со значениями по умолчанию, Number и Comment, со значениями по умолчанию 0 и NULL соответственно. Если мы хотим использовать значения по умолчанию для Number и Comment, мы просто пропускаем эти аргументы при вызове функции:
DefaultValFunc(TicketNum,UsePrice);
Обратите внимание, что мы указали только первые два аргумента. Number и Comment используют значения по умолчанию 0 и NULL. Если мы хотим указать значение для Number, но не для Comment, мы просто опускаем последний аргумент:
DefaultValFunc(TicketNum,UsePrice,UseNumber);
Опять же, комментарий использует значение по умолчанию NULL. Но, если мы хотим указать значение для комментария, независимо от того, хотим ли мы использовать значение по умолчанию для числа, мы должны также указать значение для числа:
DefaultValFunc(TicketNum,UsePrice,0,"Комментарий");
В этом примере мы использовали 0 в качестве значения для Number, которое совпадает со значением по умолчанию, и строковую константу в качестве значения для Comment. Когда вы имеете дело с несколькими аргументами, которые имеют значения по умолчанию, вы можете опустить аргументы, только если хотите использовать значения по умолчанию для оставшихся аргументов.
Область видимости
Область видимости переменной определяет, для каких функций она доступна и как долго она остается в памяти. В MQL область действия может быть локальной или глобальной. Локальная переменная также может быть статической.
Локальная переменная — это переменная, объявленная внутри функции. Локальные переменные доступны только внутри функции, в которой они объявлены. Переменная инициализируется при каждом запуске функции. После выхода из функции переменная и ее данные удаляются из памяти.
Исключением является статическая локальная переменная. Статические переменные остаются в памяти даже после выхода из функции. Когда функция запускается снова, переменная не инициализируется повторно, а вместо этого сохраняет свое предыдущее значение.
Статическая переменная объявляется путем ввода static перед объявлением переменной. Вот пример объявления статической переменной:
static int MyStaticVar;
Если статическая переменная должна быть доступна более чем одной функции, используйте вместо нее глобальную переменную. В этом случае вам не нужно объявлять переменную как статическую.
Глобальная переменная — это переменная, которая доступна всем функциям в программе. Пока программа работает, значение глобальной переменной сохраняется. Глобальные переменные объявляются вне функции, обычно в верхней части файла исходного кода.
Создание нового советника
Мастер советников в MetaEditor — это самый быстрый способ начать создавать советник. Вы можете запустить мастер, выбрав New в меню File, нажав кнопку New на панели инструментов или нажав Ctrl + N на клавиатуре.
Диалог представляет вам несколько вариантов. Вы можете создавать индикаторы, скрипты, библиотеки и включать файлы с помощью мастера. Вы также можете выбрать шаблон для создания файла. Полученный файл будет сохранен в соответствующем каталоге, в зависимости от его типа. Убедитесь, что выбран эксперт, и нажмите Далее.
Вам будет предложено ввести имя, автора и ссылку, а также некоторые дополнительные параметры. Поле Имя будет именем файла вашей программы. Советник будет сохранен в папке \experts под этим именем.
Содержимое поля «Автор» будет отображаться рядом с именем советника в тестере стратегий и в виде всплывающей подсказки при наведении указателя мыши на имя советника в окне навигатора. Поле «Ссылка» — это URL-адрес вашего веб-сайта, но он не появится нигде за пределами файла исходного кода.
Вы также можете ввести свои торговые параметры здесь. Пока добавьте один или два параметра, но не беспокойтесь о их настройке. Лучше просто добавить их вручную в исходный код позже. Нажмите кнопку Готово, и откроется шаблон советника с уже добавленной информацией.
Шаблон советника по умолчанию довольно минимален, но он содержит базовую структуру советника.
Директивы препроцессора
Первым, что появляется в любом MQL-файле, являются директивы препроцессора. Они предваряются знаком #. Шаблон советника по умолчанию имеет два параметра: #property copyright, то есть имя автора, которое вы ввели в мастере советника, и #property link, то есть ссылка, которую вы ввели в мастере.
Существуют и другие директивы #property, но почти все они связаны с индикаторами и скриптами. Единственная директива #property, которую вы должны включить в свой советник, это #property copyright, которая идентифицирует советника как ваше творение.
Второй тип директивы препроцессора, который вы, вероятно, будете использовать, — это директива #include. Как упоминалось ранее, включаемый файл состоит из функций и исходного кода, которые будут включены в ваш проект при его компиляции. Синтаксис для директивы include:
#include <filename.mqh>
Файл stdlib.mqh в нашем примере на странице 19 является стандартным включаемым файлом, который поставляется с MetaTrader. Он включает в себя несколько разных функций, которые программисты могут найти полезными. Как и все включаемые файлы, он находится в папке \experts\include.
Директива #define используется для объявления констант для использования в нашей программе. Например, вместо ввода длинной текстовой строки каждый раз, когда вам нужно ее использовать, вы можете определить константу и ввести вместо этого:
#define MYCONSTANT "Это константа"
В этом примере мы можем использовать постоянный идентификатор MYCONSTANT вместо текстовой строки в нашем коде.
Для постоянных идентификаторов принято использовать только заглавные буквы.
Иногда функция, которую вам нужно использовать, уже скомпилирована в другом файле, таком как другой советник, файл библиотеки (.ex4) или файл Windows DLL (.dll). Вы можете импортировать функции непосредственно в проект, используя директивы #import.
Библиотеки похожи на включаемые файлы, но вместо включения исходного кода в наш проект, мы выполним другой файл и вызовем функцию из него.
Вот синтаксис для директивы #import:
#import "library.ex4" double MyImportedFunction(); #import
В этом примере библиотечный файл, из которого мы импортируем функцию, — это library.ex4. Мы импортируем одну функцию типа double, которая называется MyImportedFunction(). Идентификатор функции должен совпадать с именем функции в файле исходной библиотеки. Обратите внимание на точку с запятой в конце объявления функции.
Параметры и внешние переменные
Следующий раздел в файле исходного кода нашего советника — это внешние переменные. Это настраиваемые параметры для нашей торговой системы. Сюда входят настройки вашей торговли (стоп-лосс, тейк-профит, размер лота) и настройки индикатора. Когда вы открываете диалоговое окно свойств эксперта для советника, вы просматриваете внешние переменные.
Мы указываем внешнюю переменную, добавляя extern перед переменной. Это указывает на то, что переменная будет отображаться в диалоговом окне «Свойства эксперта» и будет доступна для просмотра и настройки пользователем.
Убедитесь, что идентификатор вашей внешней переменной описывает, что он на самом деле делает. («StopLoss» лучше, чем «стоп» или «SL», например).
У вас есть 31 символ для описания вашей переменной, поэтому используйте их максимально эффективно. Значение по умолчанию для вашей переменной также будет значением по умолчанию для этого параметра, поэтому выберите логическое значение по умолчанию.
Глобальные переменные
Мы объявляем любые глобальные переменные в начале нашего файла исходного кода, обычно после внешних переменных. Расположение не имеет значения, если как глобальные, так и внешние переменные находятся вне и перед любыми функциями.
Глобальная переменная — это переменная, которая доступна любой функции в программе. Пока программа работает, глобальная переменная и ее значение остаются в памяти, и на них можно ссылаться.
Технически внешние переменные также являются глобальными, но глобальные переменные, которые мы обсуждаем в этом разделе, являются внутренними. Это означает, что они не могут быть просмотрены или изменены пользователем.
Специальные функции
MQL имеет 3 встроенные функции для управления выполнением программы: init(), deinit() и start(). Функция init() состоит из кода, который запускается один раз при первом запуске советника. Функция init() является необязательной и может быть опущена, если вы ее не используете.
Функция deinit() состоит из кода, который запускается один раз, когда советник останавливается.
Функция start() содержит основной программный код и требуется в вашем советнике. Каждый раз, когда запускается функция запуска, ваши торговые условия проверяются, а ордера размещаются или закрываются в зависимости от того, как эти условия оцениваются.
Функция start() запускается на каждом тике. Тик — это движение цены или изменение цены Bid или Ask для валютной пары. На активных рынках может быть несколько тиков в секунду. На медленных рынках минуты могут проходить без единого тика.
// директивы препроцессора #property copyright "Александр Паркер" #property link "https://traderblog.net/" #include <stdlib.mqh> #define MYCONSTANT "Это константа" // Внешние параметры extern int Parameter1 = 1; extern double Parameter2 = 0.01; // Глобальные переменные int GlobalVariable1; // Функция init int init() { // Код начала программмы return(0); } // Функция deinit int deinit() { // Код завершения программы return(0); } // Функция start int start() { // Код программы return(0); } // Другие функции int MyCustomFunction() { // Код функции return(0); }