Обработка ошибок
Даже если Вы создадите идеального «эксперта», ошибок не избежать, уж очень много факторов которых Вы не можете контролировать (связь, провайдер, ДЦ, терминал и тд.). Ошибки при выполнении торговых операций (открытие, удаление или модификация ордеров) можно разделить на две группы.
Первая – это когда «советник» не верно оформляет «заказ» на торговую операцию. Такой ордер терминал не исполняет а возвращает нам код ошибки. Код ошибки это число, например ошибка номер 130 – неправильно выставлены стопы.
Вторая – это когда с нашей стороны ордер оформлен верно и терминал послал его на исполнение, возвращается ошибка обрив связи, брокер занят и тд.
Итак научим наш «советник» распознавать эти ошибки и реагировать на них.
При установке ордеров мы используем торговую функцию OrderSend, при успешном исходе она возвращает номер открытого ордера, а при неудачи (ошибке) -1.
При удалении (OrderDelete), если ордер удален получим TRUE, если нет FALSE (ошибка).
Что бы узнать код ошибки вызывается функция GetLastError(), которая возвращает номер последней ошибки.
После каждой торговой операции (открытие, модификация и удаление), проверяем на наличие ошибок, в нашем «советнике» таких блоков где нужно вставить код четыре, каждый раз после функции OrderSend и OrderDelete.
Если ошибка есть – вызываем функцию GetLastError. Получим номер ошибки, но этот номер нам нужен как зайцу стопсигнал, все эти номера все одно не упомнишь. Вызываем функцию inf и передаем ей номер ошибки.
inf(15, GetLastError()); // если дошли сюда значит есть ошибка... узнаем какая именно
В этой функции есть блок который распознает ошибку и уже на «человеческом» языке сообщит нам в чем проблема.
case 15: switch(Number) // Переход на номер ошибки { case 2: Graf_Text = "Общая ошибка."; break; case 4: Graf_Text = "Торговый сервер занят."; break; case 129: Graf_Text = "Неправильная цена. "; break; case 135: Graf_Text = "Цена изменилась."; break; case 136: Graf_Text = "Нет цен. Ждём новый тик.."; break; case 137: Graf_Text = "Брокер занят."; break; case 146: Graf_Text = "Подсистема торговли занята."; break; case 5 : Graf_Text = "Старая версия терминала."; break; case 64: Graf_Text = "Счет заблокирован."; break; case 133: Graf_Text = "Торговля запрещена"; break; case 134: Alert("Недостаточно денег для совершения операции."); return(0); // Выход из функции default: Graf_Text = StringConcatenate("Возникла ошибка ",Number); } break;
Здесь нет ничего сложного и Вы сами можете сделать так, чтобы «советник» обрабатывал те ошибки, которые Вы посчитаете наиболее важными.
То что мы знаем об ошибке – хорошо, еще лучше чтобы «эксперт» сам реагировал на конкретную ситуацию. Например, если есть ошибка 137 (Брокер занят), а «советник» будет продолжать посылать по 100 запросов в секунду, счет могут заблокировать. В этом и подобных случаях чтобы наш «эксперт» не был назойливым при подобных ошибках будем делать паузу (пережидать несколько секунд).
if(IsTesting() == false) Sleep(5000); // если это не тестирование - "засыпаем" на 5 секунд.
Sleep() – функция останавливает «эксперта» на заданное время.
IsTesting() – функция возвращает TRUE в режиме тестирования, иначе возвращает FALSE.
Если это тестирование то паузы не нужны.
Вносим изменения в блок обработки ошибок.
case 15: switch(Number) // Переход на номер ошибки { case 2: Graf_Text = "Общая ошибка."; break; case 4: Graf_Text = "Торговый сервер занят."; if(IsTesting() == false) Sleep(5000); // если это не тестирование - "засыпаем" на 5 секунд. break; case 129: Graf_Text = "Неправильная цена."; break; case 130: Graf_Text = "Неправильная дистанция."; break; case 135: Graf_Text = "Цена изменилась."; break; case 136: Graf_Text = "Нет цен. Ждём новый тик.."; if(IsTesting() == false) Sleep(1); // если это не тестирование - "засыпаем" на 1 миллисекунду. break; case 137: Graf_Text = "Брокер занят."; if(IsTesting() == false)Sleep(5000); // если это не тестирование - "засыпаем" на 5 секунд. break; case 146: Graf_Text = "Подсистема торговли занята."; if(IsTesting() == false) Sleep(500); // если это не тестирование - "засыпаем" на пол секунды. break; case 5 : Graf_Text = "Старая версия терминала."; break; case 64: Graf_Text = "Счет заблокирован."; break; case 133: Graf_Text = "Торговля запрещена"; break; case 134: Alert("Недостаточно денег для совершения операции."); return(0); // Выход из функции default: Graf_Text = StringConcatenate("Возникла ошибка ",Number); } break;
Теперь «советник» будет не только сообщать об ошибках но и реагировать на них.
Исходник: TradeOnNews-0.3
Все приказы на совершение торговых операций отправляются в виде структуры торгового запроса MqlTradeRequest с помощью функции OrderSend(). Результат выполнения этой функции помещается в структуру MqlTradeResult, поле retcode которой содержит код возврата торгового сервера.
10004 |
TRADE_RETCODE_REQUOTE |
Реквота |
10006 |
TRADE_RETCODE_REJECT |
Запрос отклонен |
10007 |
TRADE_RETCODE_CANCEL |
Запрос отменен трейдером |
10008 |
TRADE_RETCODE_PLACED |
Ордер размещен |
10009 |
TRADE_RETCODE_DONE |
Заявка выполнена |
10010 |
TRADE_RETCODE_DONE_PARTIAL |
Заявка выполнена частично |
10011 |
TRADE_RETCODE_ERROR |
Ошибка обработки запроса |
10012 |
TRADE_RETCODE_TIMEOUT |
Запрос отменен по истечению времени |
10013 |
TRADE_RETCODE_INVALID |
Неправильный запрос |
10014 |
TRADE_RETCODE_INVALID_VOLUME |
Неправильный объем в запросе |
10015 |
TRADE_RETCODE_INVALID_PRICE |
Неправильная цена в запросе |
10016 |
TRADE_RETCODE_INVALID_STOPS |
Неправильные стопы в запросе |
10017 |
TRADE_RETCODE_TRADE_DISABLED |
Торговля запрещена |
10018 |
TRADE_RETCODE_MARKET_CLOSED |
Рынок закрыт |
10019 |
TRADE_RETCODE_NO_MONEY |
Нет достаточных денежных средств для выполнения запроса |
10020 |
TRADE_RETCODE_PRICE_CHANGED |
Цены изменились |
10021 |
TRADE_RETCODE_PRICE_OFF |
Отсутствуют котировки для обработки запроса |
10022 |
TRADE_RETCODE_INVALID_EXPIRATION |
Неверная дата истечения ордера в запросе |
10023 |
TRADE_RETCODE_ORDER_CHANGED |
Состояние ордера изменилось |
10024 |
TRADE_RETCODE_TOO_MANY_REQUESTS |
Слишком частые запросы |
10025 |
TRADE_RETCODE_NO_CHANGES |
В запросе нет изменений |
10026 |
TRADE_RETCODE_SERVER_DISABLES_AT |
Автотрейдинг запрещен сервером |
10027 |
TRADE_RETCODE_CLIENT_DISABLES_AT |
Автотрейдинг запрещен клиентским терминалом |
10028 |
TRADE_RETCODE_LOCKED |
Запрос заблокирован для обработки |
10029 |
TRADE_RETCODE_FROZEN |
Ордер или позиция заморожены |
10030 |
TRADE_RETCODE_INVALID_FILL |
Указан неподдерживаемый тип исполнения ордера по остатку |
10031 |
TRADE_RETCODE_CONNECTION |
Нет соединения с торговым сервером |
10032 |
TRADE_RETCODE_ONLY_REAL |
Операция разрешена только для реальных счетов |
10033 |
TRADE_RETCODE_LIMIT_ORDERS |
Достигнут лимит на количество отложенных ордеров |
10034 |
TRADE_RETCODE_LIMIT_VOLUME |
Достигнут лимит на объем ордеров и позиций для данного символа |
10035 |
TRADE_RETCODE_INVALID_ORDER |
Неверный или запрещённый тип ордера |
10036 |
TRADE_RETCODE_POSITION_CLOSED |
Позиция с указанным POSITION_IDENTIFIER уже закрыта |
10038 |
TRADE_RETCODE_INVALID_CLOSE_VOLUME |
Закрываемый объем превышает текущий объем позиции |
10039 |
TRADE_RETCODE_CLOSE_ORDER_EXIST |
Для указанной позиции уже есть ордер на закрытие. Может возникнуть при работе в системе хеджинга:
|
10040 |
TRADE_RETCODE_LIMIT_POSITIONS |
Количество открытых позиций, которое можно одновременно иметь на счете, может быть ограничено настройками сервера. При достижении лимита в ответ на выставление ордера сервер вернет ошибку TRADE_RETCODE_LIMIT_POSITIONS. Ограничение работает по-разному в зависимости от типа учета позиций на счете:
|
10041 |
TRADE_RETCODE_REJECT_CANCEL |
Запрос на активацию отложенного ордера отклонен, а сам ордер отменен |
10042 |
TRADE_RETCODE_LONG_ONLY |
Запрос отклонен, так как на символе установлено правило «Разрешены только длинные позиции» (POSITION_TYPE_BUY) |
10043 |
TRADE_RETCODE_SHORT_ONLY |
Запрос отклонен, так как на символе установлено правило «Разрешены только короткие позиции» (POSITION_TYPE_SELL) |
10044 |
TRADE_RETCODE_CLOSE_ONLY |
Запрос отклонен, так как на символе установлено правило «Разрешено только закрывать существующие позиции« |
Предупреждения компилятора носят информационный характер и не являются сообщениями об ошибках.
21 |
Неполная запись даты в строке datetime |
22 |
Ошибочные числа в строке datetime для даты, требования: год 1970<=X<=3000 месяц 0<X<=12 день 0<X<= 31/30/28(29)…. |
23 |
Ошибочные числа в строке datetime для времени, требования: час 0<=X<24 минута 0<=X<60 |
24 |
Некорректный цвет в формате RGB: одна из компонент RGB меньше 0 или больше 255 |
25 |
Неизвестный символ эскейп последовательности. Известные: n r t \ » ’ X x |
26 |
Слишком большой объем локальных переменных (>512кб) функции, уменьшите их количество |
29 |
Перечисление уже определено (дублирование) – члены будут добавлены к первому определению |
30 |
Переопределение макроса |
31 |
Переменная объявлена, но нигде не используется |
32 |
Конструктор должен иметь тип void |
33 |
Деструктор должен иметь тип void |
34 |
Константа не вмещается в диапазон целых (X>_UI64_MAX || X<_I64_MIN) и будет преобразована в тип double |
35 |
Слишком длинный HEX больше 16 значащих символов (обрезаются старшие полубайты) |
36 |
Нет ни одного полубайта в HEX строке «0x» |
37 |
Нет ни одной функции — нечего будет выполнять |
38 |
Используется неинициализированная переменная |
41 |
Функция не имеет тела, но и не вызывается |
43 |
Возможны потери данных при преобразовании типа. Пример: int x=(double)z; |
44 |
Потеря точности(данных) при преобразовании константы. Пример: int x=M_PI |
45 |
Несовпадение знаков операндов в операциях сравнения. Пример: (char)c1>(uchar)c2 |
46 |
Проблемы с импортом функций – требуется объявление #import либо импорт функций уже закрыт |
47 |
Описание слишком большое – лишние символы не будут включены в исполняемый файл |
48 |
Количество индикаторных буферов объявлено меньше, чем требуется |
49 |
Не указан цвет для отрисовки графической серии в индикаторе |
50 |
Нет ни одной графической серии для отображения индикатора |
51 |
Не обнаружена функция-обработчик ‘OnStart» в скрипте |
52 |
Функция-обработчик ‘OnStart» определена с неверными параметрами |
53 |
Функция ‘OnStart’ может быть определена только в скрипте |
54 |
Функция ‘OnInit’ определена с неверными параметрами |
55 |
Функция ‘OnInit’ не используется в скриптах |
56 |
Функция ‘OnDeinit’ определена с неверными параметрами |
57 |
Функция ‘OnDeinit’ не используется в скриптах |
58 |
Определены две функции ‘OnCalculate’. Будет использована OnCalculate() на одном ценовом массиве |
59 |
Обнаружено переполнение при вычислении сложной целочисленной константы |
60 |
Возможно, переменная неинициализирована. |
61 |
Данное объявление делает недоступным обращение к локальной переменной, объявленной на указанной строке |
62 |
Данное объявление делает недоступным обращение к глобальной переменной, объявленной на указанной строке |
63 |
Не может быть использовано для статических массивов |
64 |
Данное объявление делает недоступным обращение к предопределенной переменной |
65 |
Значение выражения всегда true/false |
66 |
Использование переменной или выражения типа bool в математических операциях является небезопасным |
67 |
Результат применения оператора унарного минуса к беззнаковому типу ulong неопределен |
68 |
Версия, указанная в свойстве #property version, недопустима для размещения в разделе Маркет, правильный формат #property version «XXX.YYY» |
69 |
Отсутствует выражение для выполнения по условию |
70 |
Неверный возвращаемый тип функции или некорректные параметры при объявлении функции-обработчика события |
71 |
Требуется явное приведение структур к одному типу |
72 |
Данное объявление делает недоступным прямое обращение к члену класса, объявленному на указанной строке. Доступ будет возможен только с помощью операции разрешения контекста :: |
73 |
Константа в двоичной записи слишком велика, старшие разряды будут отброшены |
74 |
Параметр в методе наследуемого класса отличается модификатором const, дочерняя функция перегрузила функцию родителя |
75 |
Отрицательное или слишком большое значения смещения в битовой операции сдвига, результат выполнения неопределён |
76 |
Функция должна вернуть значение |
77 |
Функция типа void не должна возвращать значение |
78 |
Не все варианты выполнения возвращают значение |
79 |
Выражения на глобальном уровне не разрешены |
80 |
Возможна ошибка в последовательности выполнения операций, используйте скобки для явного указания порядка |
81 |
Найдено два вида вызова OnCalCulate(). Вызываться будет вариант с использованием таймсерий OHLC |
82 |
Структура не содержит членов, размер будет приравнен 1 байту |
83 |
Нет обработки результата выполнения функции |
84 |
Индикатор, включаемый как ресурс, скомпилирован в режиме отладки. Это снижает его производительность. Для повышения скорости работы его нужно перекомпилировать |
85 |
Слишком большой код символа в строке, должен быть в диапазоне от 0 до 65535 |
86 |
Нераспознанный служебный символ в строке |
87 |
Не указано свойство индикатора, задающее вывод в главное окно или в отдельное подокно. Будет применено свойство #property indicator_chart_window |
MetaEdtior 5, редактор mql5-программ, выдает сообщения об ошибках программы, обнаруженных встроенным компилятором на стадии компиляции. Список этих ошибок приведен ниже в таблице. Для компиляции исходного кода в исполняемый нажмите F7. Программы с ошибками не могут быть скомпилированы, пока ошибки, указанные компилятором, не будут устранены.
100 |
Ошибка чтения файла |
101 |
Ошибка открытия *.EX5 файла для записи |
103 |
Недостаточно свободной памяти для завершения компиляции |
104 |
Нераспознанная компилятором пустая синтаксическая единица |
105 |
Некорректное имя файла в #include |
106 |
Ошибка доступа к файлу в #include (возможно файл не существует) |
108 |
Неподходящее имя для #define |
109 |
Неизвестная команда препроцессора (допустимы #include,#define,#property,#import) |
110 |
Неизвестный для компилятора символ |
111 |
Функция не реализована (описание есть, тела нет) |
112 |
Пропущена двойная кавычка («) |
113 |
Пропущена открывающая угловая скобка (<) или двойная кавычка («) |
114 |
Пропущена одинарная кавычка (‘) |
115 |
Пропущена закрывающая угловая скобка «>» |
116 |
Не указан тип в объявлении |
117 |
Нет оператора возврата return или имеется не во всех ветках выполнения |
118 |
Ожидалась открывающая скобка параметров вызова |
119 |
Ошибка записи EX5 |
120 |
Некорректный доступ к элементу массива |
121 |
Функция не имеет тип void и оператор return должен вернуть значение |
122 |
Некорректное объявление деструктора |
123 |
Отсутствует двоеточие «:» |
124 |
Переменная уже объявлена |
125 |
Переменная с таким идентификатором уже объявлена |
126 |
Имя переменной слишком длинное (>250 символов) |
127 |
Структура с таким идентификатором уже определена |
128 |
Структура не определена |
129 |
Член структуры с таким именем уже определен |
130 |
Нет такого члена структуры |
131 |
Нарушена парность квадратных скобок |
132 |
Ожидается открывающая круглая скобка «(« |
133 |
Несбалансированные фигурные скобки ( отсутствует «}» ) |
134 |
Сложно для компиляции (слишком большое ветвление, внутренний стек уровней переполнен) |
135 |
Ошибка открытия файла на чтение |
136 |
Недостаточно памяти для загрузки исходного файла в память |
137 |
Ожидается переменная |
138 |
Ссылка не может быть инициализирована |
140 |
Ожидалось присваивание (возникает при объявлении) |
141 |
Ожидается открывающая фигурная скобка «{« |
142 |
Параметр может быть только динамическим массивом |
143 |
Использование типа «void» недопустимо |
144 |
Нет пары для «)» или «]», т.е. отсутствует «(» или «[« |
145 |
Нет пары для «(» или «[«, т.е. отсутствует «)» или «]» |
146 |
Некорректная размерность массива |
147 |
Слишком много параметров (>64) |
149 |
Этот токен тут не ожидается |
150 |
Недопустимое использование операции (неправильные операнды) |
151 |
Выражение типа void недопустимо |
152 |
Ожидается оператор |
153 |
Неправильное использование break |
154 |
Ожидается точка с запятой «;» |
155 |
Ожидается запятая «,» |
156 |
Тип должен быть определен как класс, а не как структура |
157 |
Ожидалось выражение |
158 |
В HEX встречается «не HEX символ» или слишком длинное число (количество цифр > 511) |
159 |
Строка-константа имеет более 65534 символов |
160 |
Определение функции здесь недопустимо |
161 |
Неожиданный конец программы |
162 |
Форвардная декларация для структур запрещена |
163 |
Функция с таким именем уже определена и имеет иной тип возвращаемого значения |
164 |
Функция с таким именем уже определена и имеет иной набор параметров |
165 |
Функция с таким именем уже определена и реализована |
166 |
Перегрузка функции для данного вызова не найдена |
167 |
Функция с возвращаемым значением типа void не может возвращать значение |
168 |
Функция не определена |
170 |
Ожидается значение |
171 |
В выражении case допустимы только целочисленные константы |
172 |
Значение для case в этом switch уже использовано |
173 |
Ожидается целочисленное значение |
174 |
В выражении #import ожидается имя файла |
175 |
Выражения на глобальном уровне не допустимы |
176 |
Пропущена круглая скобка «)» перед «;» |
177 |
Слева от знака равенства предполагается переменная |
178 |
Результат выражения не используется |
179 |
Объявление переменных в case недопустимо |
180 |
Неявное преобразование из строки в число |
181 |
Неявное преобразование числа в строку |
182 |
Неоднозначный вызов перегруженной функции (подходят несколько перегрузок) |
183 |
Недопустимый else без соответствующего if |
184 |
Недопустимый case или default без соответствующего switch |
185 |
Недопустимое использование эллипсиса |
186 |
Инициализирующая последовательность имеет большее количество элементов чем инициализируемая переменная |
187 |
Ожидается константа для case |
188 |
Требуется константное выражение |
189 |
Константная переменная не может быть изменена |
190 |
Ожидается закрывающая скобка или запятая (объявление члена массива) |
191 |
Идентификатор перечисления уже используется |
192 |
Перечисление не может иметь модификаторов доступа (const, extern, static) |
193 |
Член перечисления уже объявлен с другим значением |
194 |
Существует переменная, определенная с таким же именем |
195 |
Существует структура, определенная с таким же именем |
196 |
Ожидается имя члена перечисления |
197 |
Ожидается целочисленное выражение |
198 |
Деление на ноль в константном выражении |
199 |
Неверное количество параметров в функции |
200 |
Параметром по ссылке должна быть переменная |
201 |
Ожидается переменная такого же типа для передачи по ссылке |
202 |
Константная переменная не может быть передана по неконстантной ссылке |
203 |
Требуется целочисленная положительная константа |
204 |
Ошибка доступа к защищенному члену класса |
205 |
Импорт уже определен по другому пути |
208 |
Исполняемый файл не создан |
209 |
Для индикатора не найдена точка входа ‘OnCalculate’ |
210 |
Оператор continue может быть использован только внутри цикла |
211 |
Ошибка доступа к private(закрытому) члену класса |
213 |
Метод структуры или класса не объявлен |
214 |
Ошибка доступа к private(закрытому) методу класса |
216 |
Копирование структур с объектами недопустимо |
218 |
Выход индекса за границы массива |
219 |
Недопустима инициализация массивов в объявлении структуры или класса |
220 |
Конструктор класса не может иметь параметров |
221 |
Деструктор класса не может иметь параметров |
222 |
Метод класса или структуры с таким именем и параметрами уже объявлен |
223 |
Ожидается операнд |
224 |
Метод класса или структуры с таким именем есть, но с другими параметрами (объявление!=реализация) |
225 |
Импортируемая функция не описана |
226 |
Функция ZeroMemory() не применима для классов с защищенными членами или наследованием |
227 |
Неоднозначный вызов перегруженной функции (точное совпадение параметров для нескольких перегрузок) |
228 |
Ожидается имя переменной |
229 |
Ссылку нельзя объявить в этом месте |
230 |
Уже используется в качестве имени перечисления |
232 |
Ожидается класс или структура |
235 |
Нельзя вызывать delete для удаления массива |
236 |
Ожидается оператор ‘ while ‘ |
237 |
В delete должен быть указатель |
238 |
default для этого switch уже есть |
239 |
Синтаксическая ошибка |
240 |
Escape-последовательность может встретиться только в строках ( начинается с ‘’ ) |
241 |
Требуется массив – квадратная скобка ‘[‘ не относится к массиву либо в качестве параметра-массива подают не массив |
242 |
Не может быть инициализировано посредством инициализирующей последовательности |
243 |
Импорт не определен |
244 |
Ошибка оптимизатора на синтаксическом дереве |
245 |
Объявлено слишком много структур (упростите программу) |
246 |
Преобразование параметра недопустимо |
247 |
Некорректное использование оператора delete |
248 |
Нельзя объявить указатель на ссылку |
249 |
Нельзя объявить ссылку на ссылку |
250 |
Нельзя объявить указатель на указатель |
251 |
Недопустимо объявление структуры в списке параметров |
252 |
Недопустимая операция приведения типов |
253 |
Указатель можно объявить только для класса или структуры |
256 |
Необъявленный идентификатор |
257 |
Ошибка оптимизатора исполняемого кода |
258 |
Ошибка генерации исполняемого кода |
260 |
Недопустимое выражение для оператора switch |
261 |
Переполнение пула строковых констант, упростите программу |
262 |
Невозможно преобразовать к перечислению |
263 |
Нельзя использовать virtual для данных (членов класса или структуры) |
264 |
Нельзя вызвать защищенный метод класса |
265 |
Переопределяемая виртуальная функция возвращает другой тип |
266 |
Класс нельзя наследовать от структуры |
267 |
Структуру нельзя наследовать от класса |
268 |
Конструктор не может быть виртуальным (спецификатор virtual недопустим) |
269 |
Структура не может иметь виртуальных методов |
270 |
Функция должна иметь тело |
271 |
Перегрузка системных функций (функций терминала) запрещена |
272 |
Спецификатор const недопустим для функций, не являющихся членом класса или структуры |
274 |
Нельзя менять члены класса в константном методе |
276 |
Неподходящая инициализирующая последовательность |
277 |
Пропущено значение по умолчанию для параметра (специфика объявления параметров по умолчанию) |
278 |
Переопределение параметра по умолчанию (в объявлении и реализации разные значения) |
279 |
Нельзя вызвать неконстантный метод для константного объекта |
280 |
Для доступа к членам требуется объект (поставлена точка для не класса/структуры) |
281 |
Имя уже объявленной структуры нельзя использовать при объявлении |
284 |
Неразрешенное преобразование (при закрытом наследовании) |
285 |
Структуры и массивы не могут быть использованы в качестве input-переменных |
286 |
Спецификатор const недопустим для конструктора/деструктора |
287 |
Неправильное строковое выражение для типа datetime |
288 |
Неизвестное свойство (#property) |
289 |
Некорректное значение для свойства |
290 |
Некорректный индекс для свойства в #property |
291 |
Пропущен параметр вызова – < func(x,) > |
293 |
Объект должен быть передан по ссылке |
294 |
Массив должен быть передан по ссылке |
295 |
Функция была декларирована как экспортируемая |
296 |
Функция не была декларирована как экспортируемая |
297 |
Экспортировать импортируемую функцию нельзя |
298 |
Импортируемая функция не может иметь такого параметра (нельзя передавать указатель, класс или структуру, содержащую динамический массив, указатель, класс и т.д.) |
299 |
Должен быть класс |
300 |
Секция #import не закрыта |
302 |
Несоответствие типов |
303 |
extern-переменная уже инициализирована |
304 |
Не найдено ни одной экспортируемой функции или стандартной точки входа |
305 |
Явный вызов конструктора запрещен |
306 |
Метод был объявлен константным |
307 |
Метод не был объявлен константным |
308 |
Некорректный размер ресурсного файла |
309 |
Некорректное имя ресурса |
310 |
Ошибка открытия файла ресурса |
311 |
Ошибка чтения файла ресурса |
312 |
Неизвестный тип ресурса |
313 |
Некорректный путь к файлу ресурса |
314 |
Указанное имя ресурса уже используется |
315 |
Ожидались параметры макроса |
316 |
После имени макроса должен быть пробел |
317 |
Ошибка в описании параметров макроса |
318 |
Неверное число параметров при использовании макроса |
319 |
Превышение максимального количества(16) параметров для макроса |
320 |
Макрос слишком сложный, требуется упрощение |
321 |
Параметром EnumToString() может быть только перечисление |
322 |
Имя ресурса слишком длинное |
323 |
Неподдерживаемый формат изображения (допустим только BMP-формат с глубиной цвета 24 или 32 бита) |
324 |
Объявление массива внутри оператора запрещено |
325 |
Функцию можно определить только на глобальном уровне |
326 |
Данное объявление недопустимо для текущей области видимости (области определения) |
327 |
Инициализация статичных переменных значениями локальных недопустима |
328 |
Недопустимое объявление массива объектов, не имеющих конструктора по умолчанию |
329 |
Список инициализации разрешен только для конструкторов |
330 |
Отсутствует определение функции после списка инициализации |
331 |
Список инициализации пуст |
332 |
Инициализация массива в конструкторе запрещена |
333 |
В списке инициализации запрещено инициализировать члены родительского класса |
334 |
Ожидалось выражение целого типа |
335 |
Требуемый объем памяти для массива превышает максимально допустимое значение |
336 |
Требуемый объем памяти для структуры превышает максимально допустимое значение |
337 |
Требуемый объем памяти для переменных, объявленных на глобальном уровне, превышает максимально допустимое значение |
338 |
Требуемый объем памяти для локальных переменных превышает максимально допустимое значение |
339 |
Конструктор не определен |
340 |
Недопустимое имя для файла иконки |
341 |
Не удалось открыть файла иконки по указанному пути |
342 |
Файл иконки некорректен и не соответствует формату ICO |
343 |
Повторная инициализация члена в конструкторе класса/структуры с помощью списка инициализации |
344 |
Инициализация статических членов в списке инициализации конструктора не допускается |
345 |
Инициализация нестатического члена класса/структуры на глобальном уровне запрещена |
346 |
Имя метода класса/структуры совпадает с ранее объявленным именем члена |
347 |
Имя члена класса/структуры совпадает с ранее объявленным именем метода |
348 |
Виртуальная функция не может быть объявлена как static |
349 |
Модификатор const недопустим для статической функции |
350 |
Конструктор или деструктор не могут быть статическими |
351 |
Нельзя обращаться к нестатическому члену/методу класса или структуры из статической функции |
352 |
После ключевого слова operator ожидается перегружаемая операция (+,-,[],++,— и т.д.) |
353 |
Не все операции можно перегружать в MQL5 |
354 |
Определение не соответствует объявлению |
355 |
Указано неверное количество параметров для оператора |
356 |
Не обнаружено ни одной функции-обработчика события |
357 |
Методы не могут быть экспортируемыми |
358 |
Нельзя приводить указатель на константный объект к указателю на неконстантный объект |
359 |
Шаблоны классов пока не поддерживаются |
360 |
Перегрузка шаблонов функций пока не поддерживается |
361 |
Невозможно применить шаблон функции |
362 |
Неоднозначный параметр в шаблоне функции (подходят несколько типов параметра) |
363 |
Невозможно определить к какому типу параметра приводить аргумент шаблона функции |
364 |
Неверное количество параметров в шаблоне функции |
365 |
Шаблон функции не может быть виртуальным |
366 |
Шаблоны функций не могут быть экспортированы |
367 |
Нельзя импортировать шаблоны функций |
368 |
Структуры, содержащие объекты, недопустимы |
369 |
Массивы строк и структуры, содержащие объекты, недопустимы |
370 |
Статический член класса/структуры должен быть явно инициализирован |
371 |
Ограничение компилятора: строка не может содержать более 65 535 символов |
372 |
Несогласованные #ifdef/#endif |
373 |
Результатом выполнения функции не может быть объект класса, так как отсутствует конструктор копирования |
374 |
Нельзя использовать нестатические члены и/или методы при инициализации статической переменной |
375 |
OnTesterInit() нельзя использовать без объявления обработчика OnTesterDeinit() |
376 |
Имя локальной переменной совпадает с именем одного из параметров функции |
377 |
Нельзя использовать макросы __FUNCSIG__ и __FUNCTION__ вне тела функции |
378 |
Недопустимый возвращаемый тип. Например, такая ошибка будет выдана для функций, импортированных из DLL, которые возвращают структуру или указатель в качестве результата |
379 |
Ошибка при использовании шаблона |
380 |
Не используется |
381 |
Недопустимый синтаксис при объявлении чисто виртуальной функции, разрешено «=NULL» или «=0» |
382 |
Только виртуальные функции могут быть объявлены со спецификатором чисто виртуальной функции («=NULL» или «=0») |
383 |
Нельзя создать экземпляр абстрактного класса |
384 |
Для динамического приведения с помощью оператора dynamic_cast типом назначения должен быть указатель на пользовательский тип |
385 |
Ожидается тип «указатель на функцию» |
386 |
Указатели на методы не поддерживаются |
387 |
Ошибка – невозможно определить тип указателя на функцию |
388 |
Приведение типа недоступно из-за закрытого наследования |
389 |
Переменная с модификатором const должна быть проинициализирована при объявлении |
393 |
В интерфейсе могут быть объявлены только методы с публичным доступом |
394 |
Недопустимое вложение интерфейса в другой интерфейс |
395 |
Интерфейс может наследоваться только от другого интерфейса |
396 |
Ожидается интерфейс |
397 |
Интерфейсы поддерживают только публичное наследование |
398 |
Интерфейс не может содержать члены |
399 |
Нельзя создавать объекты интерфейса напрямую, только через наследование |
GetLastError() – функция, возвращающая код последней ошибки, которая хранится в предопределенной переменной _LastError. Значение этой переменной можно сбросить в ноль функцией ResetLastError().
ERR_SUCCESS |
0 |
Операция выполнена успешно |
ERR_INTERNAL_ERROR |
4001 |
Неожиданная внутренняя ошибка |
ERR_WRONG_INTERNAL_PARAMETER |
4002 |
Ошибочный параметр при внутреннем вызове функции клиентского терминала |
ERR_INVALID_PARAMETER |
4003 |
Ошибочный параметр при вызове системной функции |
ERR_NOT_ENOUGH_MEMORY |
4004 |
Недостаточно памяти для выполнения системной функции |
ERR_STRUCT_WITHOBJECTS_ORCLASS |
4005 |
Структура содержит объекты строк и/или динамических массивов и/или структуры с такими объектами и/или классы |
ERR_INVALID_ARRAY |
4006 |
Массив неподходящего типа, неподходящего размера или испорченный объект динамического массива |
ERR_ARRAY_RESIZE_ERROR |
4007 |
Недостаточно памяти для перераспределения массива либо попытка изменения размера статического массива |
ERR_STRING_RESIZE_ERROR |
4008 |
Недостаточно памяти для перераспределения строки |
ERR_NOTINITIALIZED_STRING |
4009 |
Неинициализированная строка |
ERR_INVALID_DATETIME |
4010 |
Неправильное значение даты и/или времени |
ERR_ARRAY_BAD_SIZE |
4011 |
Запрашиваемый размер массива превышает 2 гигабайта |
ERR_INVALID_POINTER |
4012 |
Ошибочный указатель |
ERR_INVALID_POINTER_TYPE |
4013 |
Ошибочный тип указателя |
ERR_FUNCTION_NOT_ALLOWED |
4014 |
Системная функция не разрешена для вызова |
ERR_RESOURCE_NAME_DUPLICATED |
4015 |
Совпадении имени динамического и статического ресурсов |
ERR_RESOURCE_NOT_FOUND |
4016 |
Ресурс с таким именем в EX5 не найден |
ERR_RESOURCE_UNSUPPOTED_TYPE |
4017 |
Неподдерживаемый тип ресурса или размер более 16 MB |
ERR_RESOURCE_NAME_IS_TOO_LONG |
4018 |
Имя ресурса превышает 63 символа |
ERR_MATH_OVERFLOW |
4019 |
При вычислении математической функции произошло переполнение |
Графики |
||
ERR_CHART_WRONG_ID |
4101 |
Ошибочный идентификатор графика |
ERR_CHART_NO_REPLY |
4102 |
График не отвечает |
ERR_CHART_NOT_FOUND |
4103 |
График не найден |
ERR_CHART_NO_EXPERT |
4104 |
У графика нет эксперта, который мог бы обработать событие |
ERR_CHART_CANNOT_OPEN |
4105 |
Ошибка открытия графика |
ERR_CHART_CANNOT_CHANGE |
4106 |
Ошибка при изменении для графика символа и периода |
ERR_CHART_WRONG_PARAMETER |
4107 |
Ошибочное значение параметра для функции по работе с графиком |
ERR_CHART_CANNOT_CREATE_TIMER |
4108 |
Ошибка при создании таймера |
ERR_CHART_WRONG_PROPERTY |
4109 |
Ошибочный идентификатор свойства графика |
ERR_CHART_SCREENSHOT_FAILED |
4110 |
Ошибка при создании скриншота |
ERR_CHART_NAVIGATE_FAILED |
4111 |
Ошибка навигации по графику |
ERR_CHART_TEMPLATE_FAILED |
4112 |
Ошибка при применении шаблона |
ERR_CHART_WINDOW_NOT_FOUND |
4113 |
Подокно, содержащее указанный индикатор, не найдено |
ERR_CHART_INDICATOR_CANNOT_ADD |
4114 |
Ошибка при добавлении индикатора на график |
ERR_CHART_INDICATOR_CANNOT_DEL |
4115 |
Ошибка при удалении индикатора с графика |
ERR_CHART_INDICATOR_NOT_FOUND |
4116 |
Индикатор не найден на указанном графике |
Графические объекты |
||
ERR_OBJECT_ERROR |
4201 |
Ошибка при работе с графическим объектом |
ERR_OBJECT_NOT_FOUND |
4202 |
Графический объект не найден |
ERR_OBJECT_WRONG_PROPERTY |
4203 |
Ошибочный идентификатор свойства графического объекта |
ERR_OBJECT_GETDATE_FAILED |
4204 |
Невозможно получить дату, соответствующую значению |
ERR_OBJECT_GETVALUE_FAILED |
4205 |
Невозможно получить значение, соответствующее дате |
MarketInfo |
||
ERR_MARKET_UNKNOWN_SYMBOL |
4301 |
Неизвестный символ |
ERR_MARKET_NOT_SELECTED |
4302 |
Символ не выбран в MarketWatch |
ERR_MARKET_WRONG_PROPERTY |
4303 |
Ошибочный идентификатор свойства символа |
ERR_MARKET_LASTTIME_UNKNOWN |
4304 |
Время последнего тика неизвестно (тиков не было) |
ERR_MARKET_SELECT_ERROR |
4305 |
Ошибка добавления или удаления символа в MarketWatch |
Доступ к истории |
||
ERR_HISTORY_NOT_FOUND |
4401 |
Запрашиваемая история не найдена |
ERR_HISTORY_WRONG_PROPERTY |
4402 |
Ошибочный идентификатор свойства истории |
ERR_HISTORY_TIMEOUT |
4403 |
Превышен таймаут при запросе истории |
ERR_HISTORY_BARS_LIMIT |
4404 |
Количество запрашиваемых баров ограничено настройками терминала |
ERR_HISTORY_LOAD_ERRORS |
4405 |
Множество ошибок при загрузке истории |
ERR_HISTORY_SMALL_BUFFER |
4407 |
Принимающий массив слишком мал чтобы вместить все запрошенные данные |
Global_Variables |
||
ERR_GLOBALVARIABLE_NOT_FOUND |
4501 |
Глобальная переменная клиентского терминала не найдена |
ERR_GLOBALVARIABLE_EXISTS |
4502 |
Глобальная переменная клиентского терминала с таким именем уже существует |
ERR_GLOBALVARIABLE_NOT_MODIFIED |
4503 |
Не было модификаций глобальных переменных |
ERR_GLOBALVARIABLE_CANNOTREAD |
4504 |
Не удалось открыть и прочитать файл со значениями глобальных переменных |
ERR_GLOBALVARIABLE_CANNOTWRITE |
4505 |
Не удалось записать файл со значениями глобальных переменных |
ERR_MAIL_SEND_FAILED |
4510 |
Не удалось отправить письмо |
ERR_PLAY_SOUND_FAILED |
4511 |
Не удалось воспроизвести звук |
ERR_MQL5_WRONG_PROPERTY |
4512 |
Ошибочный идентификатор свойства программы |
ERR_TERMINAL_WRONG_PROPERTY |
4513 |
Ошибочный идентификатор свойства терминала |
ERR_FTP_SEND_FAILED |
4514 |
Не удалось отправить файл по ftp |
ERR_NOTIFICATION_SEND_FAILED |
4515 |
Не удалось отправить уведомление |
ERR_NOTIFICATION_WRONG_PARAMETER |
4516 |
Неверный параметр для отправки уведомления – в функцию SendNotification() передали пустую строку или NULL |
ERR_NOTIFICATION_WRONG_SETTINGS |
4517 |
Неверные настройки уведомлений в терминале (не указан ID или не выставлено разрешение) |
ERR_NOTIFICATION_TOO_FREQUENT |
4518 |
Слишком частая отправка уведомлений |
ERR_FTP_NOSERVER |
4519 |
Не указан FTP сервер |
ERR_FTP_NOLOGIN |
4520 |
Не указан FTP логин |
ERR_FTP_FILE_ERROR |
4521 |
Не найден файл в директории MQL5Files для отправки на FTP сервер |
ERR_FTP_CONNECT_FAILED |
4522 |
Ошибка при подключении к FTP серверу |
ERR_FTP_CHANGEDIR |
4523 |
На FTP сервере не найдена директория для выгрузки файла |
ERR_FTP_CLOSED |
4524 |
Подключение к FTP серверу закрыто |
Буферы пользовательских индикаторов |
||
ERR_BUFFERS_NO_MEMORY |
4601 |
Недостаточно памяти для распределения индикаторных буферов |
ERR_BUFFERS_WRONG_INDEX |
4602 |
Ошибочный индекс своего индикаторного буфера |
Свойства пользовательских индикаторов |
||
ERR_CUSTOM_WRONG_PROPERTY |
4603 |
Ошибочный идентификатор свойства пользовательского индикатора |
Account |
||
ERR_ACCOUNT_WRONG_PROPERTY |
4701 |
Ошибочный идентификатор свойства счета |
ERR_TRADE_WRONG_PROPERTY |
4751 |
Ошибочный идентификатор свойства торговли |
ERR_TRADE_DISABLED |
4752 |
Торговля для эксперта запрещена |
ERR_TRADE_POSITION_NOT_FOUND |
4753 |
Позиция не найдена |
ERR_TRADE_ORDER_NOT_FOUND |
4754 |
Ордер не найден |
ERR_TRADE_DEAL_NOT_FOUND |
4755 |
Сделка не найдена |
ERR_TRADE_SEND_FAILED |
4756 |
Не удалось отправить торговый запрос |
ERR_TRADE_CALC_FAILED |
4758 |
Не удалось вычислить значение прибыли или маржи |
Индикаторы |
||
ERR_INDICATOR_UNKNOWN_SYMBOL |
4801 |
Неизвестный символ |
ERR_INDICATOR_CANNOT_CREATE |
4802 |
Индикатор не может быть создан |
ERR_INDICATOR_NO_MEMORY |
4803 |
Недостаточно памяти для добавления индикатора |
ERR_INDICATOR_CANNOT_APPLY |
4804 |
Индикатор не может быть применен к другому индикатору |
ERR_INDICATOR_CANNOT_ADD |
4805 |
Ошибка при добавлении индикатора |
ERR_INDICATOR_DATA_NOT_FOUND |
4806 |
Запрошенные данные не найдены |
ERR_INDICATOR_WRONG_HANDLE |
4807 |
Ошибочный хэндл индикатора |
ERR_INDICATOR_WRONG_PARAMETERS |
4808 |
Неправильное количество параметров при создании индикатора |
ERR_INDICATOR_PARAMETERS_MISSING |
4809 |
Отсутствуют параметры при создании индикатора |
ERR_INDICATOR_CUSTOM_NAME |
4810 |
Первым параметром в массиве должно быть имя пользовательского индикатора |
ERR_INDICATOR_PARAMETER_TYPE |
4811 |
Неправильный тип параметра в массиве при создании индикатора |
ERR_INDICATOR_WRONG_INDEX |
4812 |
Ошибочный индекс запрашиваемого индикаторного буфера |
Стакан цен |
||
ERR_BOOKS_CANNOT_ADD |
4901 |
Стакан цен не может быть добавлен |
ERR_BOOKS_CANNOT_DELETE |
4902 |
Стакан цен не может быть удален |
ERR_BOOKS_CANNOT_GET |
4903 |
Данные стакана цен не могут быть получены |
ERR_BOOKS_CANNOT_SUBSCRIBE |
4904 |
Ошибка при подписке на получение новых данных стакана цен |
Файловые операции |
||
ERR_TOO_MANY_FILES |
5001 |
Не может быть открыто одновременно более 64 файлов |
ERR_WRONG_FILENAME |
5002 |
Недопустимое имя файла |
ERR_TOO_LONG_FILENAME |
5003 |
Слишком длинное имя файла |
ERR_CANNOT_OPEN_FILE |
5004 |
Ошибка открытия файла |
ERR_FILE_CACHEBUFFER_ERROR |
5005 |
Недостаточно памяти для кеша чтения |
ERR_CANNOT_DELETE_FILE |
5006 |
Ошибка удаления файла |
ERR_INVALID_FILEHANDLE |
5007 |
Файл с таким хэндлом уже был закрыт, либо не открывался вообще |
ERR_WRONG_FILEHANDLE |
5008 |
Ошибочный хэндл файла |
ERR_FILE_NOTTOWRITE |
5009 |
Файл должен быть открыт для записи |
ERR_FILE_NOTTOREAD |
5010 |
Файл должен быть открыт для чтения |
ERR_FILE_NOTBIN |
5011 |
Файл должен быть открыт как бинарный |
ERR_FILE_NOTTXT |
5012 |
Файл должен быть открыт как текстовый |
ERR_FILE_NOTTXTORCSV |
5013 |
Файл должен быть открыт как текстовый или CSV |
ERR_FILE_NOTCSV |
5014 |
Файл должен быть открыт как CSV |
ERR_FILE_READERROR |
5015 |
Ошибка чтения файла |
ERR_FILE_BINSTRINGSIZE |
5016 |
Должен быть указан размер строки, так как файл открыт как бинарный |
ERR_INCOMPATIBLE_FILE |
5017 |
Для строковых массивов должен быть текстовый файл, для остальных – бинарный |
ERR_FILE_IS_DIRECTORY |
5018 |
Это не файл, а директория |
ERR_FILE_NOT_EXIST |
5019 |
Файл не существует |
ERR_FILE_CANNOT_REWRITE |
5020 |
Файл не может быть переписан |
ERR_WRONG_DIRECTORYNAME |
5021 |
Ошибочное имя директории |
ERR_DIRECTORY_NOT_EXIST |
5022 |
Директория не существует |
ERR_FILE_ISNOT_DIRECTORY |
5023 |
Это файл, а не директория |
ERR_CANNOT_DELETE_DIRECTORY |
5024 |
Директория не может быть удалена |
ERR_CANNOT_CLEAN_DIRECTORY |
5025 |
Не удалось очистить директорию (возможно, один или несколько файлов заблокированы и операция удаления не удалась) |
ERR_FILE_WRITEERROR |
5026 |
Не удалось записать ресурс в файл |
ERR_FILE_ENDOFFILE |
5027 |
Не удалось прочитать следующую порцию данных из CSV-файла (FileReadString, FileReadNumber, FileReadDatetime, FileReadBool), так как достигнут конец файла |
Преобразование строк |
||
ERR_NO_STRING_DATE |
5030 |
В строке нет даты |
ERR_WRONG_STRING_DATE |
5031 |
В строке ошибочная дата |
ERR_WRONG_STRING_TIME |
5032 |
В строке ошибочное время |
ERR_STRING_TIME_ERROR |
5033 |
Ошибка преобразования строки в дату |
ERR_STRING_OUT_OF_MEMORY |
5034 |
Недостаточно памяти для строки |
ERR_STRING_SMALL_LEN |
5035 |
Длина строки меньше, чем ожидалось |
ERR_STRING_TOO_BIGNUMBER |
5036 |
Слишком большое число, больше, чем ULONG_MAX |
ERR_WRONG_FORMATSTRING |
5037 |
Ошибочная форматная строка |
ERR_TOO_MANY_FORMATTERS |
5038 |
Форматных спецификаторов больше, чем параметров |
ERR_TOO_MANY_PARAMETERS |
5039 |
Параметров больше, чем форматных спецификаторов |
ERR_WRONG_STRING_PARAMETER |
5040 |
Испорченный параметр типа string |
ERR_STRINGPOS_OUTOFRANGE |
5041 |
Позиция за пределами строки |
ERR_STRING_ZEROADDED |
5042 |
К концу строки добавлен 0, бесполезная операция |
ERR_STRING_UNKNOWNTYPE |
5043 |
Неизвестный тип данных при конвертации в строку |
ERR_WRONG_STRING_OBJECT |
5044 |
Испорченный объект строки |
Работа с массивами |
||
ERR_INCOMPATIBLE_ARRAYS |
5050 |
Копирование несовместимых массивов. Строковый массив может быть скопирован только в строковый, а числовой массив – в числовой |
ERR_SMALL_ASSERIES_ARRAY |
5051 |
Приемный массив объявлен как AS_SERIES, и он недостаточного размера |
ERR_SMALL_ARRAY |
5052 |
Слишком маленький массив, стартовая позиция за пределами массива |
ERR_ZEROSIZE_ARRAY |
5053 |
Массив нулевой длины |
ERR_NUMBER_ARRAYS_ONLY |
5054 |
Должен быть числовой массив |
ERR_ONEDIM_ARRAYS_ONLY |
5055 |
Должен быть одномерный массив |
ERR_SERIES_ARRAY |
5056 |
Таймсерия не может быть использована |
ERR_DOUBLE_ARRAY_ONLY |
5057 |
Должен быть массив типа double |
ERR_FLOAT_ARRAY_ONLY |
5058 |
Должен быть массив типа float |
ERR_LONG_ARRAY_ONLY |
5059 |
Должен быть массив типа long |
ERR_INT_ARRAY_ONLY |
5060 |
Должен быть массив типа int |
ERR_SHORT_ARRAY_ONLY |
5061 |
Должен быть массив типа short |
ERR_CHAR_ARRAY_ONLY |
5062 |
Должен быть массив типа char |
ERR_STRING_ARRAY_ONLY |
5063 |
Должен быть массив типа string |
Работа с OpenCL |
||
ERR_OPENCL_NOT_SUPPORTED |
5100 |
Функции OpenCL на данном компьютере не поддерживаются |
ERR_OPENCL_INTERNAL |
5101 |
Внутренняя ошибка при выполнении OpenCL |
ERR_OPENCL_INVALID_HANDLE |
5102 |
Неправильный хэндл OpenCL |
ERR_OPENCL_CONTEXT_CREATE |
5103 |
Ошибка при создании контекста OpenCL |
ERR_OPENCL_QUEUE_CREATE |
5104 |
Ошибка создания очереди выполнения в OpenCL |
ERR_OPENCL_PROGRAM_CREATE |
5105 |
Ошибка при компиляции программы OpenCL |
ERR_OPENCL_TOO_LONG_KERNEL_NAME |
5106 |
Слишком длинное имя точки входа (кернел OpenCL) |
ERR_OPENCL_KERNEL_CREATE |
5107 |
Ошибка создания кернел — точки входа OpenCL |
ERR_OPENCL_SET_KERNEL_PARAMETER |
5108 |
Ошибка при установке параметров для кернел OpenCL (точки входа в программу OpenCL) |
ERR_OPENCL_EXECUTE |
5109 |
Ошибка выполнения программы OpenCL |
ERR_OPENCL_WRONG_BUFFER_SIZE |
5110 |
Неверный размер буфера OpenCL |
ERR_OPENCL_WRONG_BUFFER_OFFSET |
5111 |
Неверное смещение в буфере OpenCL |
ERR_OPENCL_BUFFER_CREATE |
5112 |
Ошибка создания буфера OpenCL |
ERR_OPENCL_TOO_MANY_OBJECTS |
5113 |
Превышено максимальное число OpenCL объектов |
ERR_OPENCL_SELECTDEVICE |
5114 |
Ошибка выбора OpenCL устройства |
Работа с WebRequest |
||
ERR_WEBREQUEST_INVALID_ADDRESS |
5200 |
URL не прошел проверку |
ERR_WEBREQUEST_CONNECT_FAILED |
5201 |
Не удалось подключиться к указанному URL |
ERR_WEBREQUEST_TIMEOUT |
5202 |
Превышен таймаут получения данных |
ERR_WEBREQUEST_REQUEST_FAILED |
5203 |
Ошибка в результате выполнения HTTP запроса |
Пользовательские символы |
||
ERR_NOT_CUSTOM_SYMBOL |
5300 |
Должен быть указан пользовательский символ |
ERR_CUSTOM_SYMBOL_WRONG_NAME |
5301 |
Некорректное имя пользовательского символа. В имени символа можно использовать только латинские буквы без знаков препинания, пробелов и спецсимволов (допускаются «.», «_», «&» и «#»). Не рекомендуется использовать символы <, >, :, «, /,, |, ?, *. |
ERR_CUSTOM_SYMBOL_NAME_LONG |
5302 |
Слишком длинное имя для пользовательского символа. Длина имени символа не должна превышать 32 знака с учётом завершающего 0 |
ERR_CUSTOM_SYMBOL_PATH_LONG |
5303 |
Слишком длинный путь для пользовательского символа. Длина пути не более 128 знаков с учётом «Custom\», имени символа, разделителей групп и завершающего 0 |
ERR_CUSTOM_SYMBOL_EXIST |
5304 |
Пользовательский символ с таким именем уже существует |
ERR_CUSTOM_SYMBOL_ERROR |
5305 |
Ошибка при создании, удалении или изменении пользовательского символа |
ERR_CUSTOM_SYMBOL_SELECTED |
5306 |
Попытка удалить пользовательский символ, выбранный в обзоре рынка (Market Watch) |
ERR_CUSTOM_SYMBOL_PROPERTY_WRONG |
5307 |
Неправильное свойство пользовательского символа |
ERR_CUSTOM_SYMBOL_PARAMETER_ERROR |
5308 |
Ошибочный параметр при установке свойства пользовательского символа |
ERR_CUSTOM_SYMBOL_PARAMETER_LONG |
5309 |
Слишком длинный строковый параметр при установке свойства пользовательского символа |
ERR_CUSTOM_TICKS_WRONG_ORDER |
5310 |
Не упорядоченный по времени массив тиков |
Пользовательские ошибки |
||
ERR_USER_ERROR_FIRST |
65536 |
С этого кода начинаются ошибки, задаваемые пользователем |
Metaquotes MQL5 — JSON — API
Development state: stable release version 2.0
Tested on macOS Mojave / Windows 10 in Parallels Desktop container.
Tested on Manjaro Linux / Windows 10 in VirtualBox
Working in production on Debian 10 / Wine 4.
Table of Contents
- About the Project
- Installation
- Documentation
- Usage
- Live data and streaming events
- Streaming MT5 indicator data
- Plot values to MT5 charts
- The JsonAPIIndicator
- Error handling
- License
About the Project
This project was developed to work as a server for the Backtrader Python trading framework. It is based on ZeroMQ sockets and uses JSON format to communicate. But now it has grown to the independent project. You can use it with any programming language that has ZeroMQ binding.
Backtrader Python client is located here: Python Backtrader — Metaquotes MQL5
Thanks to the participation of Gunther Schulz, the project moved to a new level.
New features:
- Support for multiple datastreams in parallel for any combination of symbols and timeframes independently of the timeframe and symbol of the attached chart
- Support for tick data
- Support for direct download as CSV files
- Automatic retry binding to sockets. When running under Wine in Linux, sockets will be blocked for 60 seconds if closed uncleanly. This can happen if the client is still connected while the EA gets reloaded.
- Skip re-initialization on chart timeframe change
- Support for spread data (ask/bid)
- Support for plotting to charts in MT5 by streaming values from the client
- Support for processing client data with MT5 indicators
In development:
- Devitation
- Stop limit orders
- Drawing of chart objects
Installation
- Install ZeroMQ for MQL5 https://github.com/dingmaotu/mql-zmq
- Put the following files from this repo to your MetaEditor Iinclude` directory
Include/Json.mqh
Include/controlerrors.mqh
Include/StringToEnumInt.mqh
- Put the
Indicators/JsonAPIIndicator.mq5
file from this repo to your MetaEditorIndicators
directory - Download and compile
experts/JsonAPI.mq5
script. - Check if Metatrader 5 automatic trading is allowed.
- Attach the
JsonAPI.mq5
script to a chart in Metatrader 5. - Allow DLL import in dialog window.
- Check if the ports are free to use. (default:
15555
,15556
,15557
,15558
,15559
,15560
,15562
)
Documentation
The script uses seven ZeroMQ sockets:
System socket
— Recives requests from client and replies ‘OK’.Data socket
— Pushes data to client depending on the request via System socket.Live socket
— Automatically pushes last candle when it closes.Streaming socket
— Automatically pushes last transaction info every time it happens.Indicator data socket
— automatically pushes indicator result values to the client.Chart Data Socket
— Recieves values to be plotted to a specific chart.Chart Indicator Socket
— Only for internal communication. Passes values to be plotted TO the supplied JsonAPIIndicator indicator
The idea is to send requests via System socket
and recieve results/errors via Data socket
. Event handlers should be created for Live socket
and Streaming socket
because the server sends data to theese sockets automatically. See examples in Live data and streaming events section.
System socket
request uses default JSON dictionary:
{
"action": null,
"actionType": null,
"symbol": null,
"chartTF": null,
"fromDate": null,
"toDate": null,
"id": null,
"magic": null,
"volume": null,
"price": null,
"stoploss": null,
"takeprofit": null,
"expiration": null,
"deviation": null,
"comment": null,
"chartId": None,
"indicatorChartId": None,
"chartIndicatorSubWindow": None,
"style": None,
}
Check out the available combinations of action
and actionType
:
action | actionType | Description |
---|---|---|
CONFIG | null | Set script configuration |
RESET | null | Reset subscribed symbols |
ACCOUNT | null | Get account settings |
BALANCE | null | Get current balance |
POSITIONS | null | Get current open positions |
ORDERS | null | Get current open orders |
INDICATOR | ATTACH | Attach an indicator and return ID |
INDICATOR | REQUEST | Get indicator data |
CHART | OPEN | Open a new chart window |
CHART | ADDINDICATOR | Attach JsonAPIIndicator indicator |
HISTORY | DATA | Get data history |
HISTORY | TRADES | Get trades history |
HISTORY | WRITE | Download history data as CSV |
TRADE | ORDER_TYPE_BUY | Buy market |
TRADE | ORDER_TYPE_SELL | Sell market |
TRADE | ORDER_TYPE_BUY_LIMIT | Buy limit |
TRADE | ORDER_TYPE_SELL_LIMIT | Sell limit |
TRADE | ORDER_TYPE_BUY_STOP | Buy stop |
TRADE | ORDER_TYPE_SELL_STOP | Sell stop |
TRADE | POSITION_MODIFY | Position modify |
TRADE | POSITION_PARTIAL | Position close partial |
TRADE | POSITION_CLOSE_ID | Position close by id |
TRADE | POSITION_CLOSE_SYMBOL | Positions close by symbol |
TRADE | ORDER_MODIFY | Order modify |
TRADE | ORDER_CANCEL | Order cancel |
Python 3 API class example:
import zmq class MTraderAPI: def __init__(self, host=None): self.HOST = host or 'localhost' self.SYS_PORT = 15555 # REP/REQ port self.DATA_PORT = 15556 # PUSH/PULL port self.LIVE_PORT = 15557 # PUSH/PULL port self.EVENTS_PORT = 15558 # PUSH/PULL port self.INDICATOR_DATA_PORT = 15559 # REP/REQ port self.CHART_DATA_PORT = 15560 # PUSH port # ZeroMQ timeout in seconds sys_timeout = 1 data_timeout = 10 # initialise ZMQ context context = zmq.Context() # connect to server sockets try: self.sys_socket = context.socket(zmq.REQ) # set port timeout self.sys_socket.RCVTIMEO = sys_timeout * 1000 self.sys_socket.connect('tcp://{}:{}'.format(self.HOST, self.SYS_PORT)) self.data_socket = context.socket(zmq.PULL) # set port timeout self.data_socket.RCVTIMEO = data_timeout * 1000 self.data_socket.connect('tcp://{}:{}'.format(self.HOST, self.DATA_PORT)) self.indicator_data_socket = context.socket(zmq.PULL) # set port timeout self.indicator_data_socket.RCVTIMEO = data_timeout * 1000 self.indicator_data_socket.connect( "tcp://{}:{}".format(self.HOST, self.INDICATOR_DATA_PORT) ) self.chart_data_socket = context.socket(zmq.PUSH) # set port timeout # TODO check if port is listening and error handling self.chart_data_socket.connect( "tcp://{}:{}".format(self.HOST, self.CHART_DATA_PORT) ) except zmq.ZMQError: raise zmq.ZMQBindError("Binding ports ERROR") def _send_request(self, data: dict) -> None: """Send request to server via ZeroMQ System socket""" try: self.sys_socket.send_json(data) msg = self.sys_socket.recv_string() # terminal received the request assert msg == 'OK', 'Something wrong on server side' except AssertionError as err: raise zmq.NotDone(err) except zmq.ZMQError: raise zmq.NotDone("Sending request ERROR") def _pull_reply(self): """Get reply from server via Data socket with timeout""" try: msg = self.data_socket.recv_json() except zmq.ZMQError: raise zmq.NotDone('Data socket timeout ERROR') return msg def _indicator_pull_reply(self): """Get reply from server via Data socket with timeout""" try: msg = self.indicator_data_socket.recv_json() except zmq.ZMQError: raise zmq.NotDone("Indicator Data socket timeout ERROR") if self.debug: print("ZMQ INDICATOR DATA REPLY: ", msg) return msg def live_socket(self, context=None): """Connect to socket in a ZMQ context""" try: context = context or zmq.Context.instance() socket = context.socket(zmq.PULL) socket.connect('tcp://{}:{}'.format(self.HOST, self.LIVE_PORT)) except zmq.ZMQError: raise zmq.ZMQBindError("Live port connection ERROR") return socket def streaming_socket(self, context=None): """Connect to socket in a ZMQ context""" try: context = context or zmq.Context.instance() socket = context.socket(zmq.PULL) socket.connect('tcp://{}:{}'.format(self.HOST, self.EVENTS_PORT)) except zmq.ZMQError: raise zmq.ZMQBindError("Data port connection ERROR") return socket def _push_chart_data(self, data: dict) -> None: """Send message for chart control to server via ZeroMQ chart data socket""" try: if self.debug: print("ZMQ PUSH CHART DATA: ", data, " -> ", data) self.chart_data_socket.send_json(data) except zmq.ZMQError: raise zmq.NotDone("Sending request ERROR") def construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary request = { "action": None, "actionType": None, "symbol": None, "chartTF": None, "fromDate": None, "toDate": None, "id": None, "magic": None, "volume": None, "price": None, "stoploss": None, "takeprofit": None, "expiration": None, "deviation": None, "comment": None, "chartId": None, "indicatorChartId": None, "chartIndicatorSubWindow": None, "style": None, } # update dict values if exist for key, value in kwargs.items(): if key in request: request[key] = value else: raise KeyError('Unknown key in **kwargs ERROR') # send dict to server self._send_request(request) # return server reply return self._pull_reply() def indicator_construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary request = { "action": None, "actionType": None, "id": None, "symbol": None, "chartTF": None, "fromDate": None, "toDate": None, "name": None, "params": None, "linecount": None, } # update dict values if exist for key, value in kwargs.items(): if key in request: request[key] = value else: raise KeyError("Unknown key in **kwargs ERROR") # send dict to server self._send_request(request) # return server reply return self._indicator_pull_reply() def chart_data_construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary message = { "action": None, "actionType": None, "chartId": None, "indicatorChartId": None, "data": None, } # update dict values if exist for key, value in kwargs.items(): if key in message: message[key] = value else: raise KeyError("Unknown key in **kwargs ERROR") # send dict to server self._push_chart_data(message)
Usage
All examples will be on Python 3. Lets create an instance of MetaTrader API class:
First of all we should configure the script symbol
and timeframe
. Live data stream will be configured to the same params. You can use any number of symbols
and timeframes
. The server subscribes to these sembols and will transmit them through the Live data
socket
print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="M5")) print(api.construct_and_send(action="CONFIG", symbol="AUDUSD", chartTF="M1")) ...
There is also tick
data. You can subscribe for tick
and candle
data at the same symbol
.
print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="TICK")) print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="M1"))
If you want to stop Live data
, you should reset server subscriptions.
rep = api.construct_and_send(action="RESET") print(rep)
Get information about the trading account.
rep = api.construct_and_send(action="ACCOUNT") print(rep)
Get historical data. fromDate
should be in timestamp format. The data will be loaded to the last candle if toDate
is None
. Notice, that the script sends the last unclosed candle too. You should delete it manually.
There are some issues:
- MetaTrader keeps historical data in cache. But when you make a request for the first time, MetaTrader downloads the data from a broker. This operation can exceed
Data socket
timeout. It depends on your broker. Second request will be handeled quickly. - It takes 6-7 seconds to process
50000
M1 candles. It was tested on Windows 10 in Parallels Desktop container with 4 cores and 4GB RAM. So if you need more data there are three ways to handle it. 1) IncreaseData socket
timeout. 2) You can load data partially usingfromDate
andtoDate
. 3) You can use more powerfull hardware.
rep = api.construct_and_send(action="HISTORY", actionType="DATA", symbol="EURUSD", chartTF="M5", fromDate=1555555555) print(rep)
History data reply example:
{'data': [[1560782340, 1.12271, 1.12288, 1.12269, 1.12277, 46.0],[1560782400, 1.12278, 1.12299, 1.12276, 1.12297, 43.0],[1560782460, 1.12296, 1.12302, 1.12293, 1.123, 23.0]]}
Buy market order.
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_BUY", symbol="EURUSD", "volume"=0.1, "stoploss"=1.1, "takeprofit"=1.3) print(rep)
Sell limit order. Remember to switch SL/TP depending on BUY/SELL, or you will get invalid stops
error.
- BUY: SL < price < TP
- SELL: SL > price > TP
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_SELL_LIMIT", symbol="EURUSD", "volume"=0.1, "price"=1.2, "stoploss"=1.3, "takeprofit"=1.1) print(rep)
All pending orders are set to Good till cancel
by default. If you want to set an expiration date, pass the date in timestamp format to expiration
param.
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_SELL_LIMIT", symbol="EURUSD", "volume"=0.1, "price"=1.2, "expiration"=1560782460) print(rep)
Live data and streaming events
Event handler example for Live socket
and Data socket
.
import zmq import threading api = MTraderAPI() def _t_livedata(): socket = api.live_socket() while True: try: last_candle = socket.recv_json() except zmq.ZMQError: raise zmq.NotDone("Live data ERROR") print(last_candle) def _t_streaming_events(): socket = api.streaming_socket() while True: try: trans = socket.recv_json() request, reply = trans.values() except zmq.ZMQError: raise zmq.NotDone("Streaming data ERROR") print(request) print(reply) t = threading.Thread(target=_t_livedata, daemon=True) t.start() t = threading.Thread(target=_t_streaming_events, daemon=True) t.start() while True: pass
There are only two variants of Live socket
data. When everything is ok, the script sends subscribed data on new even. You can divide streams by symbol and timeframe names:
{"status":"CONNECTED","symbol":"EURUSD","timeframe":"TICK","data":[1581611172734,1.08515,1.08521]}
{"status":"CONNECTED","symbol":"EURUSD","timeframe":"M1","data":[1581611100,1.08525,1.08525,1.08520,1.08520,10.00000]}
If the terminal has lost connection to the market:
{"status":"DISCONNECTED"}
When the terminal reconnects to the market, it sends the last closed candle again. So you should update your historical data. Make the action="HISTORY"
request with fromDate
equal to your last candle timestamp before disconnect.
OnTradeTransaction
function is called when a trade transaction event occurs. Streaming socket
sends TRADE_TRANSACTION_REQUEST
data every time it happens. Try to create and modify orders in the MQL5 terminal manually and check the expert logging tab for better understanding. Also see MQL5 docs.
TRADE_TRANSACTION_REQUEST
request data:
{
'action': 'TRADE_ACTION_DEAL',
'order': 501700843,
'symbol': 'EURUSD',
'volume': 0.1,
'price': 1.12181,
'stoplimit': 0.0,
'sl': 1.1,
'tp': 1.13,
'deviation': 10,
'type': 'ORDER_TYPE_BUY',
'type_filling': 'ORDER_FILLING_FOK',
'type_time': 'ORDER_TIME_GTC',
'expiration': 0,
'comment': None,
'position': 0,
'position_by': 0
}
TRADE_TRANSACTION_REQUEST
result data:
{
'retcode': 10009,
'result': 'TRADE_RETCODE_DONE',
'deal': 501700843,
'order': 501700843,
'volume': 0.1,
'price': 1.12181,
'comment': None,
'request_id': 8,
'retcode_external': 0
}
Streaming MT5 indicator data
Open a chart window and attach a MT5 indicator.
Parameters:
id
— a unique id string.symbol
— chart symbol to open and atatch the indicator to.chartTF
— timeframe to set the chart at.name
— the name of the MT5 indicator to attach.params
— the initialisation paramaters that the specified indicator expects.linecount
— the number of buffers the indicator returns. In the example below MACD is used and it return the values for «macd» and «signal».
print(api.indicator_construct_and_send(action='INDICATOR', actionType='ATTACH', id='4df306ea-e8e6-439b-8004-b86ba4bcc8c3', symbol='EURUSD', chartTF='M1', name='Examples/MACD', 'params'=['12', '26', '9', 'PRICE_CLOSE'], 'linecount'=2))
Stream the calculated result values of a previously attached indicator.
Parameters:
id
— id string of a previously attached indicator.fromDate
— timestamp for which a result value is requested.
print(api.indicator_construct_and_send(action='INDICATOR', actionType='REQUEST', id='4df306ea-e8e6-439b-8004-b86ba4bcc8c3', 'fromDate'=1591993860))
Example of the result:
{'error': False, 'id': '4df306ea-e8e6-439b-8004-b86ba4bcc8c3', 'data': ['0.00008204', '0.00001132']}
The data field holds a list with results of the calculated indicator buffers.
Plot values to MT5 charts
Open a new chart window to plot values to.
Parameters:
chartId
— a unique id string to reference the new chart window.fromDate
— timestamp for which a result value is requested.symbol
— chart symbol to open and atatch the indicator to.chartTF
— timeframe to set the chart at.
print(api.construct_and_send(action='CHART', actionType='OPEN', symbol='EURUSD', chartTF='M1', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b'))
A common scenario would be to stream vlaues calculated by the client indictor to be plotted in MT5. This is done by attaching the supplied MT5 indicator JsonAPIIndicator
and passing values to be plotted to it.
Initialize a plot line object by attaching a new instance of JsonAPIIndicator
, ready to recieve values to be plotted.
Parameters:
chartId
— id string of a previously opened chart.indicatorChartId
: a unique id string to reference the new plot line object.chartIndicatorSubWindow
: chart sub window to plot to (https://www.mql5.c.om/en/docs/chart_operations/chartindicatoradd)style
: style settings for the plot.shortname
andlinelabel
can be any string value.linewidth
expects an int. All other paramters require constants supported by MQL5.
Supported are the following style paramers (with the corresponding MQL5 constants in braces):color
(PLOT_LINE_COLOR),linetype
(PLOT_DRAW_TYPE),linestyle
(PLOT_LINE_STYLE).
print(api.construct_and_send(action='CHART', actionType='ADDINDICATOR', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, style={shortname='BT-BollingerBands', linelabel='Middle', color='clrYellow', linetype='DRAW_LINE', linestyle='STYLE_SOLID', linewidth=1))
Stream values to a plot line object (draw a line).
Parameters:
chartId
— id string of a previously opened chart.indicatorChartId
: id string of a previously initialized plot line object.data
: list of values to plot. The last value in a list (values[-1]
) corresponds to the most recent candle. If the size of the list of values passsed is >= 1, and the number of historic candles to plot isn
thenvalues[n-1]
is the most recent candle andvalues[0]
is the oldest candle.
# Plot line with historic data values=[1.1225948211353751, 1.1226243406054506, 1.1226266123404378] print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=values)) n=len(values) print(f'The value for the oldest candle: {values[0]} - The value for the most recent candle: {values[n-1]}') # Extend the plotted line with the most recent values as new candles are created print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=[1.122618120966847])) print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=[1.1226254106923093]))
The JsonAPIIndicator
The supplied indicator JsonAPIIndicator
does not do any calculations by itself. It simply plots
incoming data to a chart which can be passed by via JSON interface to the Chart Data Socket
. The indicator is controlled by the expert script JsonAPI.mq5
locally via port 15562
.
Error handling
First of all, when you send a command via System socket
, you should always receive back "OK"
message via System socket
. It means that your command was received and deserialized.
All data that come through Data socket
have an error
param. This param will have true
key if somethng goes wrong. Also, there will be description
and function
params. They will hold information about error and the name of the function with error.
This information also applies to the trade commannds. See MQL5 docs for possible server answers.
License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE
for more information.
Metaquotes MQL5 — JSON — API
Development state: stable release version 2.0
Tested on macOS Mojave / Windows 10 in Parallels Desktop container.
Tested on Manjaro Linux / Windows 10 in VirtualBox
Working in production on Debian 10 / Wine 4.
Table of Contents
- About the Project
- Installation
- Documentation
- Usage
- Live data and streaming events
- Streaming MT5 indicator data
- Plot values to MT5 charts
- The JsonAPIIndicator
- Error handling
- License
About the Project
This project was developed to work as a server for the Backtrader Python trading framework. It is based on ZeroMQ sockets and uses JSON format to communicate. But now it has grown to the independent project. You can use it with any programming language that has ZeroMQ binding.
Backtrader Python client is located here: Python Backtrader — Metaquotes MQL5
Thanks to the participation of Gunther Schulz, the project moved to a new level.
New features:
- Support for multiple datastreams in parallel for any combination of symbols and timeframes independently of the timeframe and symbol of the attached chart
- Support for tick data
- Support for direct download as CSV files
- Automatic retry binding to sockets. When running under Wine in Linux, sockets will be blocked for 60 seconds if closed uncleanly. This can happen if the client is still connected while the EA gets reloaded.
- Skip re-initialization on chart timeframe change
- Support for spread data (ask/bid)
- Support for plotting to charts in MT5 by streaming values from the client
- Support for processing client data with MT5 indicators
In development:
- Devitation
- Stop limit orders
- Drawing of chart objects
Installation
- Install ZeroMQ for MQL5 https://github.com/dingmaotu/mql-zmq
- Put the following files from this repo to your MetaEditor Iinclude` directory
Include/Json.mqh
Include/controlerrors.mqh
Include/StringToEnumInt.mqh
- Put the
Indicators/JsonAPIIndicator.mq5
file from this repo to your MetaEditorIndicators
directory - Download and compile
experts/JsonAPI.mq5
script. - Check if Metatrader 5 automatic trading is allowed.
- Attach the
JsonAPI.mq5
script to a chart in Metatrader 5. - Allow DLL import in dialog window.
- Check if the ports are free to use. (default:
15555
,15556
,15557
,15558
,15559
,15560
,15562
)
Documentation
The script uses seven ZeroMQ sockets:
System socket
— Recives requests from client and replies ‘OK’.Data socket
— Pushes data to client depending on the request via System socket.Live socket
— Automatically pushes last candle when it closes.Streaming socket
— Automatically pushes last transaction info every time it happens.Indicator data socket
— automatically pushes indicator result values to the client.Chart Data Socket
— Recieves values to be plotted to a specific chart.Chart Indicator Socket
— Only for internal communication. Passes values to be plotted TO the supplied JsonAPIIndicator indicator
The idea is to send requests via System socket
and recieve results/errors via Data socket
. Event handlers should be created for Live socket
and Streaming socket
because the server sends data to theese sockets automatically. See examples in Live data and streaming events section.
System socket
request uses default JSON dictionary:
{
"action": null,
"actionType": null,
"symbol": null,
"chartTF": null,
"fromDate": null,
"toDate": null,
"id": null,
"magic": null,
"volume": null,
"price": null,
"stoploss": null,
"takeprofit": null,
"expiration": null,
"deviation": null,
"comment": null,
"chartId": None,
"indicatorChartId": None,
"chartIndicatorSubWindow": None,
"style": None,
}
Check out the available combinations of action
and actionType
:
action | actionType | Description |
---|---|---|
CONFIG | null | Set script configuration |
RESET | null | Reset subscribed symbols |
ACCOUNT | null | Get account settings |
BALANCE | null | Get current balance |
POSITIONS | null | Get current open positions |
ORDERS | null | Get current open orders |
INDICATOR | ATTACH | Attach an indicator and return ID |
INDICATOR | REQUEST | Get indicator data |
CHART | OPEN | Open a new chart window |
CHART | ADDINDICATOR | Attach JsonAPIIndicator indicator |
HISTORY | DATA | Get data history |
HISTORY | TRADES | Get trades history |
HISTORY | WRITE | Download history data as CSV |
TRADE | ORDER_TYPE_BUY | Buy market |
TRADE | ORDER_TYPE_SELL | Sell market |
TRADE | ORDER_TYPE_BUY_LIMIT | Buy limit |
TRADE | ORDER_TYPE_SELL_LIMIT | Sell limit |
TRADE | ORDER_TYPE_BUY_STOP | Buy stop |
TRADE | ORDER_TYPE_SELL_STOP | Sell stop |
TRADE | POSITION_MODIFY | Position modify |
TRADE | POSITION_PARTIAL | Position close partial |
TRADE | POSITION_CLOSE_ID | Position close by id |
TRADE | POSITION_CLOSE_SYMBOL | Positions close by symbol |
TRADE | ORDER_MODIFY | Order modify |
TRADE | ORDER_CANCEL | Order cancel |
Python 3 API class example:
import zmq class MTraderAPI: def __init__(self, host=None): self.HOST = host or 'localhost' self.SYS_PORT = 15555 # REP/REQ port self.DATA_PORT = 15556 # PUSH/PULL port self.LIVE_PORT = 15557 # PUSH/PULL port self.EVENTS_PORT = 15558 # PUSH/PULL port self.INDICATOR_DATA_PORT = 15559 # REP/REQ port self.CHART_DATA_PORT = 15560 # PUSH port # ZeroMQ timeout in seconds sys_timeout = 1 data_timeout = 10 # initialise ZMQ context context = zmq.Context() # connect to server sockets try: self.sys_socket = context.socket(zmq.REQ) # set port timeout self.sys_socket.RCVTIMEO = sys_timeout * 1000 self.sys_socket.connect('tcp://{}:{}'.format(self.HOST, self.SYS_PORT)) self.data_socket = context.socket(zmq.PULL) # set port timeout self.data_socket.RCVTIMEO = data_timeout * 1000 self.data_socket.connect('tcp://{}:{}'.format(self.HOST, self.DATA_PORT)) self.indicator_data_socket = context.socket(zmq.PULL) # set port timeout self.indicator_data_socket.RCVTIMEO = data_timeout * 1000 self.indicator_data_socket.connect( "tcp://{}:{}".format(self.HOST, self.INDICATOR_DATA_PORT) ) self.chart_data_socket = context.socket(zmq.PUSH) # set port timeout # TODO check if port is listening and error handling self.chart_data_socket.connect( "tcp://{}:{}".format(self.HOST, self.CHART_DATA_PORT) ) except zmq.ZMQError: raise zmq.ZMQBindError("Binding ports ERROR") def _send_request(self, data: dict) -> None: """Send request to server via ZeroMQ System socket""" try: self.sys_socket.send_json(data) msg = self.sys_socket.recv_string() # terminal received the request assert msg == 'OK', 'Something wrong on server side' except AssertionError as err: raise zmq.NotDone(err) except zmq.ZMQError: raise zmq.NotDone("Sending request ERROR") def _pull_reply(self): """Get reply from server via Data socket with timeout""" try: msg = self.data_socket.recv_json() except zmq.ZMQError: raise zmq.NotDone('Data socket timeout ERROR') return msg def _indicator_pull_reply(self): """Get reply from server via Data socket with timeout""" try: msg = self.indicator_data_socket.recv_json() except zmq.ZMQError: raise zmq.NotDone("Indicator Data socket timeout ERROR") if self.debug: print("ZMQ INDICATOR DATA REPLY: ", msg) return msg def live_socket(self, context=None): """Connect to socket in a ZMQ context""" try: context = context or zmq.Context.instance() socket = context.socket(zmq.PULL) socket.connect('tcp://{}:{}'.format(self.HOST, self.LIVE_PORT)) except zmq.ZMQError: raise zmq.ZMQBindError("Live port connection ERROR") return socket def streaming_socket(self, context=None): """Connect to socket in a ZMQ context""" try: context = context or zmq.Context.instance() socket = context.socket(zmq.PULL) socket.connect('tcp://{}:{}'.format(self.HOST, self.EVENTS_PORT)) except zmq.ZMQError: raise zmq.ZMQBindError("Data port connection ERROR") return socket def _push_chart_data(self, data: dict) -> None: """Send message for chart control to server via ZeroMQ chart data socket""" try: if self.debug: print("ZMQ PUSH CHART DATA: ", data, " -> ", data) self.chart_data_socket.send_json(data) except zmq.ZMQError: raise zmq.NotDone("Sending request ERROR") def construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary request = { "action": None, "actionType": None, "symbol": None, "chartTF": None, "fromDate": None, "toDate": None, "id": None, "magic": None, "volume": None, "price": None, "stoploss": None, "takeprofit": None, "expiration": None, "deviation": None, "comment": None, "chartId": None, "indicatorChartId": None, "chartIndicatorSubWindow": None, "style": None, } # update dict values if exist for key, value in kwargs.items(): if key in request: request[key] = value else: raise KeyError('Unknown key in **kwargs ERROR') # send dict to server self._send_request(request) # return server reply return self._pull_reply() def indicator_construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary request = { "action": None, "actionType": None, "id": None, "symbol": None, "chartTF": None, "fromDate": None, "toDate": None, "name": None, "params": None, "linecount": None, } # update dict values if exist for key, value in kwargs.items(): if key in request: request[key] = value else: raise KeyError("Unknown key in **kwargs ERROR") # send dict to server self._send_request(request) # return server reply return self._indicator_pull_reply() def chart_data_construct_and_send(self, **kwargs) -> dict: """Construct a request dictionary from default and send it to server""" # default dictionary message = { "action": None, "actionType": None, "chartId": None, "indicatorChartId": None, "data": None, } # update dict values if exist for key, value in kwargs.items(): if key in message: message[key] = value else: raise KeyError("Unknown key in **kwargs ERROR") # send dict to server self._push_chart_data(message)
Usage
All examples will be on Python 3. Lets create an instance of MetaTrader API class:
First of all we should configure the script symbol
and timeframe
. Live data stream will be configured to the same params. You can use any number of symbols
and timeframes
. The server subscribes to these sembols and will transmit them through the Live data
socket
print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="M5")) print(api.construct_and_send(action="CONFIG", symbol="AUDUSD", chartTF="M1")) ...
There is also tick
data. You can subscribe for tick
and candle
data at the same symbol
.
print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="TICK")) print(api.construct_and_send(action="CONFIG", symbol="EURUSD", chartTF="M1"))
If you want to stop Live data
, you should reset server subscriptions.
rep = api.construct_and_send(action="RESET") print(rep)
Get information about the trading account.
rep = api.construct_and_send(action="ACCOUNT") print(rep)
Get historical data. fromDate
should be in timestamp format. The data will be loaded to the last candle if toDate
is None
. Notice, that the script sends the last unclosed candle too. You should delete it manually.
There are some issues:
- MetaTrader keeps historical data in cache. But when you make a request for the first time, MetaTrader downloads the data from a broker. This operation can exceed
Data socket
timeout. It depends on your broker. Second request will be handeled quickly. - It takes 6-7 seconds to process
50000
M1 candles. It was tested on Windows 10 in Parallels Desktop container with 4 cores and 4GB RAM. So if you need more data there are three ways to handle it. 1) IncreaseData socket
timeout. 2) You can load data partially usingfromDate
andtoDate
. 3) You can use more powerfull hardware.
rep = api.construct_and_send(action="HISTORY", actionType="DATA", symbol="EURUSD", chartTF="M5", fromDate=1555555555) print(rep)
History data reply example:
{'data': [[1560782340, 1.12271, 1.12288, 1.12269, 1.12277, 46.0],[1560782400, 1.12278, 1.12299, 1.12276, 1.12297, 43.0],[1560782460, 1.12296, 1.12302, 1.12293, 1.123, 23.0]]}
Buy market order.
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_BUY", symbol="EURUSD", "volume"=0.1, "stoploss"=1.1, "takeprofit"=1.3) print(rep)
Sell limit order. Remember to switch SL/TP depending on BUY/SELL, or you will get invalid stops
error.
- BUY: SL < price < TP
- SELL: SL > price > TP
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_SELL_LIMIT", symbol="EURUSD", "volume"=0.1, "price"=1.2, "stoploss"=1.3, "takeprofit"=1.1) print(rep)
All pending orders are set to Good till cancel
by default. If you want to set an expiration date, pass the date in timestamp format to expiration
param.
rep = api.construct_and_send(action="TRADE", actionType="ORDER_TYPE_SELL_LIMIT", symbol="EURUSD", "volume"=0.1, "price"=1.2, "expiration"=1560782460) print(rep)
Live data and streaming events
Event handler example for Live socket
and Data socket
.
import zmq import threading api = MTraderAPI() def _t_livedata(): socket = api.live_socket() while True: try: last_candle = socket.recv_json() except zmq.ZMQError: raise zmq.NotDone("Live data ERROR") print(last_candle) def _t_streaming_events(): socket = api.streaming_socket() while True: try: trans = socket.recv_json() request, reply = trans.values() except zmq.ZMQError: raise zmq.NotDone("Streaming data ERROR") print(request) print(reply) t = threading.Thread(target=_t_livedata, daemon=True) t.start() t = threading.Thread(target=_t_streaming_events, daemon=True) t.start() while True: pass
There are only two variants of Live socket
data. When everything is ok, the script sends subscribed data on new even. You can divide streams by symbol and timeframe names:
{"status":"CONNECTED","symbol":"EURUSD","timeframe":"TICK","data":[1581611172734,1.08515,1.08521]}
{"status":"CONNECTED","symbol":"EURUSD","timeframe":"M1","data":[1581611100,1.08525,1.08525,1.08520,1.08520,10.00000]}
If the terminal has lost connection to the market:
{"status":"DISCONNECTED"}
When the terminal reconnects to the market, it sends the last closed candle again. So you should update your historical data. Make the action="HISTORY"
request with fromDate
equal to your last candle timestamp before disconnect.
OnTradeTransaction
function is called when a trade transaction event occurs. Streaming socket
sends TRADE_TRANSACTION_REQUEST
data every time it happens. Try to create and modify orders in the MQL5 terminal manually and check the expert logging tab for better understanding. Also see MQL5 docs.
TRADE_TRANSACTION_REQUEST
request data:
{
'action': 'TRADE_ACTION_DEAL',
'order': 501700843,
'symbol': 'EURUSD',
'volume': 0.1,
'price': 1.12181,
'stoplimit': 0.0,
'sl': 1.1,
'tp': 1.13,
'deviation': 10,
'type': 'ORDER_TYPE_BUY',
'type_filling': 'ORDER_FILLING_FOK',
'type_time': 'ORDER_TIME_GTC',
'expiration': 0,
'comment': None,
'position': 0,
'position_by': 0
}
TRADE_TRANSACTION_REQUEST
result data:
{
'retcode': 10009,
'result': 'TRADE_RETCODE_DONE',
'deal': 501700843,
'order': 501700843,
'volume': 0.1,
'price': 1.12181,
'comment': None,
'request_id': 8,
'retcode_external': 0
}
Streaming MT5 indicator data
Open a chart window and attach a MT5 indicator.
Parameters:
id
— a unique id string.symbol
— chart symbol to open and atatch the indicator to.chartTF
— timeframe to set the chart at.name
— the name of the MT5 indicator to attach.params
— the initialisation paramaters that the specified indicator expects.linecount
— the number of buffers the indicator returns. In the example below MACD is used and it return the values for «macd» and «signal».
print(api.indicator_construct_and_send(action='INDICATOR', actionType='ATTACH', id='4df306ea-e8e6-439b-8004-b86ba4bcc8c3', symbol='EURUSD', chartTF='M1', name='Examples/MACD', 'params'=['12', '26', '9', 'PRICE_CLOSE'], 'linecount'=2))
Stream the calculated result values of a previously attached indicator.
Parameters:
id
— id string of a previously attached indicator.fromDate
— timestamp for which a result value is requested.
print(api.indicator_construct_and_send(action='INDICATOR', actionType='REQUEST', id='4df306ea-e8e6-439b-8004-b86ba4bcc8c3', 'fromDate'=1591993860))
Example of the result:
{'error': False, 'id': '4df306ea-e8e6-439b-8004-b86ba4bcc8c3', 'data': ['0.00008204', '0.00001132']}
The data field holds a list with results of the calculated indicator buffers.
Plot values to MT5 charts
Open a new chart window to plot values to.
Parameters:
chartId
— a unique id string to reference the new chart window.fromDate
— timestamp for which a result value is requested.symbol
— chart symbol to open and atatch the indicator to.chartTF
— timeframe to set the chart at.
print(api.construct_and_send(action='CHART', actionType='OPEN', symbol='EURUSD', chartTF='M1', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b'))
A common scenario would be to stream vlaues calculated by the client indictor to be plotted in MT5. This is done by attaching the supplied MT5 indicator JsonAPIIndicator
and passing values to be plotted to it.
Initialize a plot line object by attaching a new instance of JsonAPIIndicator
, ready to recieve values to be plotted.
Parameters:
chartId
— id string of a previously opened chart.indicatorChartId
: a unique id string to reference the new plot line object.chartIndicatorSubWindow
: chart sub window to plot to (https://www.mql5.c.om/en/docs/chart_operations/chartindicatoradd)style
: style settings for the plot.shortname
andlinelabel
can be any string value.linewidth
expects an int. All other paramters require constants supported by MQL5.
Supported are the following style paramers (with the corresponding MQL5 constants in braces):color
(PLOT_LINE_COLOR),linetype
(PLOT_DRAW_TYPE),linestyle
(PLOT_LINE_STYLE).
print(api.construct_and_send(action='CHART', actionType='ADDINDICATOR', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, style={shortname='BT-BollingerBands', linelabel='Middle', color='clrYellow', linetype='DRAW_LINE', linestyle='STYLE_SOLID', linewidth=1))
Stream values to a plot line object (draw a line).
Parameters:
chartId
— id string of a previously opened chart.indicatorChartId
: id string of a previously initialized plot line object.data
: list of values to plot. The last value in a list (values[-1]
) corresponds to the most recent candle. If the size of the list of values passsed is >= 1, and the number of historic candles to plot isn
thenvalues[n-1]
is the most recent candle andvalues[0]
is the oldest candle.
# Plot line with historic data values=[1.1225948211353751, 1.1226243406054506, 1.1226266123404378] print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=values)) n=len(values) print(f'The value for the oldest candle: {values[0]} - The value for the most recent candle: {values[n-1]}') # Extend the plotted line with the most recent values as new candles are created print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=[1.122618120966847])) print(api.chart_data_construct_and_send(action='PLOT', chartId='cbb82988-3193-4dda-9cea-c27faaf7835b', indicatorChartId='5f2c1ab5-6b36-498f-96ac-3982a4a3551a', chartIndicatorSubWindow=1, data=[1.1226254106923093]))
The JsonAPIIndicator
The supplied indicator JsonAPIIndicator
does not do any calculations by itself. It simply plots
incoming data to a chart which can be passed by via JSON interface to the Chart Data Socket
. The indicator is controlled by the expert script JsonAPI.mq5
locally via port 15562
.
Error handling
First of all, when you send a command via System socket
, you should always receive back "OK"
message via System socket
. It means that your command was received and deserialized.
All data that come through Data socket
have an error
param. This param will have true
key if somethng goes wrong. Also, there will be description
and function
params. They will hold information about error and the name of the function with error.
This information also applies to the trade commannds. See MQL5 docs for possible server answers.
License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE
for more information.