Основы написания экспертов на языке NTL+

Введение

Эта статья предназначена для программистов, которые планируют написать свой первый эксперт на языке NTL+. В ней будет рассказано о ряде особенностей составления экспертов, знание которых избавит от многих ошибок и сократит время написания и отладки скрипта (понятие скрипта в языке NTL+ объединяет в себе три разновидности программ: эксперты, индикаторы и утилиты).


Создание эксперта.

Для создания нового эксперта перейдите в окно Navigator, кликните правой клавишей мыши на папке Advisors и выберите в контекстном меню функцию Create. Вам будет предложено ввести имя для нового эксперта. Для имени эксперта действуют стандартные правила написания имен файлов ОС Windows: имя не должно содержать следующие символы *|\:"<>?/ .


После создания файла нового эксперта вы увидите начальный шаблон с 3-мя функциями Initialize(), Run(), DeInitialize(). Каждая из этих функций запускается в определенный момент жизни эксперта. Программисту не надо вызывать их специально, так как это происходит автоматически.


Сразу после запуска эксперта выполняется функция Initialize(), предназначенная для начальной инициализации параметров. Отметим, что в функции Initialize() не следует выполнять торговые операции, так как на момент её запуска могут быть не определены значения торговых параметров (например, цены Bid и Ask, данные счета, информация по позициям и ордерам).


С приходом каждого тика вызывается функция Run(), в которой и должен находиться основной код скрипта. В этом коде может анализироваться текущая ситуация на рынке, приниматься решение о необходимости выполнения торговых операций или выполняться какие-либо математические расчеты. Обработка данных каждого тика не должна превышать 10 секунд, иначе программа автоматически остановит пользовательский эксперт.


При остановке эксперта вызывается функция DeInitialize(), которая выполняет некоторые заключительные действия перед остановкой скрипта. Во многих скриптах какие-либо действия при инициализации и деинициализации вообще не требуются – в этих случаях функции Initialize() и DeInitialize() можно оставить пустыми или вовсе удалить из скрипта (при этом терминал не будет их вызывать).


Составление алгоритма и написание кода эксперта.

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


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


От выбора правильных торговых критериев открытия/закрытия позиций, установки ордеров зависит успешность эксперта в целом, поэтому разработка стратегии имеет первостепенное значение при создании успешного эксперта. Торговые критерии могут создаваться на основе технических индикаторов, анализа ценовых уровней и других вычислений на основе ваших представлений об эффективной торговле.


Не забудьте предусмотреть возможность Вашего ручного вмешательства во время работы эксперта: что произойдет, если эксперт откроет позицию, а вы её закроете в терминале? Подумайте, не перейдет ли эксперт в какое-либо незапланированное состояние, что приведет к неправильной работе.


Для корректной работы Вам понадобится анализировать состояние открытых позиций и установленных ордеров на каждом тике. В этом Вам помогут свойства Deals.Total и Orders.Total, которые возвращают количество открытых позиций и установленных ордеров, а также методы Deals.Select() и Orders.Select() для выбора позиции или ордера.


Обратите также внимание на восстановление работы эксперта после перезапуска терминала: переходит ли он в то же состояние, в котором был до перезапуска? Учтите возможные ситуации, в которых между перезапусками часть позиций может закрыться по стоп-лоссу или тейк-профиту, а также ордера могут выполниться, что приведет к открытию новых позиций.


В эксперте нужно предусмотреть действия при наступлении стандартных ошибок и ситуаций: например, нет средств на открытие позиций, или попытка установки ордеров слишком близко к текущей цене.


Доступ к данным о состоянии счета можно осуществить через объект Account и его свойства. Например, свойство Account.Balance служит для получения баланса текущего счета, а свойство Account.MarginFree - для получения значения свободной маржи.


int Run() { // инициализируем переменную volume - объем в единицах базовой валюты int volume = 10000; if(Account.MarginFree < volume/Account.Leverage) return -1; }

Обратите внимание на строку «return -1» - при выполнении этого оператора работа эксперта останавливается принудительно.


Работа с историей котировок.

Использование таймсерий позволяет получить историю котировок текущего символа для анализа ситуации на рынке, которая была некоторое время назад. Таймсерии представляют из себя группу массивов: Open[] - цены открытия бара, Close[] - цена закрытия бара, High[] - максимальная цена бара, Low[] - минимальная цена бара, Time[] - время открытия бара и Volume[] - тиковый объем бара (количество тиков за бар). Все таймсерии актуальны для графика символа, на котором запущен эксперт и для текущего таймфрейма. В таймсериях действует обратная индексация: самый последний (самый поздний по времени) элемент будет иметь индекс 0, а первый элемент – индекс равный Bars.Total(Chart.Symbol,Chart.Interval)-1.


При необходимости получать данные для произвольного символа Вам понадобится использовать объект Bars. Его методы Open(), High(), Low(), Close(), Volume(), Time() аналогичны соответствующим таймсериям с тем отличием, что необходимо указать символ, размер бара (интервал, таймфрейм) и номер бара, для которого требуется получить значения. Перед запуском скрипта нужно подписаться на все символы, с которыми работает скрипт. Для этого откройте окно MarketWatch, нажмите правой кнопкой мыши на пустом поле, выберите из контекстного меню команду Subscribe, отметьте необходимые символы и нажмите "OK".


В экспертах может понадобиться определять, когда открывается новый бар или завершается формирование предыдущего бара. Для этого можно воспользоваться глобальным массивом Volume. При каждом тике значение элемента Volume[0] увеличивается на единицу, а после первого тика нового бара становится равным 1. Таким образом, для определения момента открытия бара подойдет следующая конструкция:


int Run() { if(Volume[0]==1) { // Некий код, выполняемый при открытии нового бара. } }

Так же просто можно завершать работу Run() при помощи оператора return для всех значений Volume[0] кроме единицы:


int Run() { if(Volume[0]>1) return (0); // Некий код, выполняемый при открытии нового бара. }

Другим альтернативным методом является анализ времени открытия бара - если это время двух последних тиков совпадает, то выходим из скрипта при помощи оператора return(0). При формировании нового бара мы получим различные значения для Time[0] на текущем и предыдущем тиками - именно это событие и означает открытие нового бара.


datetime lasttime=0; int Run() { if(lasttime == Time[0]) return(0); // Некий код, выполняемый при открытии нового бара. lasttime = Time[0]; }

Тестирование эксперта

Тестировщик стратегий Advisor Tester предназначен для оценки эффективности работы и проверки функционирования эксперта. Тестировщик запускается функцией главного меню View -> Advisor Tester. В верхней части окна тестировщика расположены вкладки для следующих разделов:


  • Parameters - параметры работы тестировщика
  • Results - табличное представление информации по позициям
  • Equity Graph - отображение изменения баланса и эквити
  • Journal - файл журнала

Parameters

На вкладке Parameters возможно указать следующие параметры, влияющие на процесс тестирования:


  • Выпадающий список Advisor - выбор советника, который будет тестироваться.
  • Кнопка Properties - вызов параметров эксперта для редактирования. Если в эксперте нет параметров объявленных с ключевым словом extern, то кнопка будет неактивной.
  • Symbol - cимвол для тестирования*.
  • Interval - интервал (таймфрейм) для тестирования.
  • Spread - выбор значения спреда. Значение Current spread соответствует текущему значению спреда. В поле Spread можно ввести любое произвольное неотрицательное значение.
  • Method - метод тестирования. Можно выбрать одно из следующих значений: Control Points или Open Price Only. При выборе Control points автоматически генерируются по 4 тика для каждого бара (в указанной далее последовательности). Для баров с ценой открытия ниже цены закрытия, тики соответствуют ценам Open, Low, High, Close; для баров с ценой открытия выше цены закрытия - Open, High, Low, Close.
    img
    Для метода Open Prices Only все торговые операции выполняются только по ценам открытия. При этом элементы таймсерий с нулевым индексом будут равны между собой Open[0] = High[0] = Low[0] = Close[0], а значения элементов таймсерий для ненулевых индексов совпадут с соответствующими значениями для метода Control Points.
  • Флажок Limit Dates служит для включения ограничения диапазона дат для тестирования.
  • Поля ввода дат From и To служат для задания диапазона дат для тестирования. Значения по умолчанию соответствуют диапазону загруженной истории по указанным символу и интервалу.
  • Initial Deposit - начальный депозит на момент начала тестирования.
  • Флажок Enable visual mode служит для вывода графика, на котором отмечаются моменты открытия и закрытия позиций, а также момент установки ордера для последней открытой позиции.
  • Флажок Enable expert logs служит для вывода печати из функции System.Print на вкладку Journal.
  • Кнопка Start/Stop запускает и останавливает работу тестировщика.

Включение флажков Enable visual mode и Enable expert logs влияет на скорость выполнения тестирования, поэтому рекомендуется включать их только при необходимости.


* На данный момент не предусмотрено тестирование мультивалютных экспертов. Если вы тестируйте советник, который работает с позициями на нескольких символах и диапазон загруженной истории котировок этих символов не совпадает, то значения цен bid и ask, таймсерий и значений, возвращаемых методами объекта Bars , могут быть нулевыми.


Results

На вкладке Results выводится информация по всем позициям, открытым и закрытым в процессе тестирования. Сверху расположена таблица с закрытыми позициями. В ней отображается следующая информация:


  • Номер # - порядковый номер закрытой позиции. Первая закрытая позиция получает #1, вторая #2 и т.д.
  • Deal ID - идентификатор закрытой позиции.
  • Symbol - символ, на котором открывалась позиция.
  • Volume1 - объем позиции в единицах базовой валюты
  • Volume2 - объем позиции в единицах валюты котировки
  • Open rate - цена открытия
  • Open time - время открытия
  • Stop loss - уровень стоп-лосса (не отображается, если не задан)
  • Take profit - уровень тейк-профита (не отображается, если не задан)
  • Last swap - своп по текущей позиции
  • Rate close - цена закрытия
  • Time close - время закрытия
  • Profit - прибыль по позиции
  • Balance - баланс после закрытия позиции*.
  • Equity - эквити после закрытия позиции*.

* Данные столбцы выводятся в расширенном режиме Show extended columns. Этот режим включается через контекстное меню таблицы.


В нижней таблице отображаются позиции, которые не были закрыты на момент окончания тестирования. Наименования столбцов таблицы совпадают с соответствующими столбцами таблицы Closed Positions, за исключением отсутствующих столбцов закрытия позиций.


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


Equity graph

Отображение изменения размера баланса и эквити в зависимости от номера закрытой позиции. Двойной клик мышью на графике показывает соответствующую позицию в таблице закрытых позиций Closed positions.


Journal

Отображение текстового вывода из функции печати System.Print, используемой в эксперте. Если флажок Enable expert logs на вкладке Parameters отключен, то в журнале будут отображаться только команды о старте и остановке эксперта.


Отладка скрипта

Отладка скрипта редко обходится без использования функции печати System.Print, которая выводит информацию на вкладку Journal окна Toolbox (либо на вкладку Journal окна тестировщика). Однако полезно знать, что при запуске эксперта выводимая информация также дублируется в лог файл в папке «Имя_пользователя\Documents\ NeTTradeX Advisors\logs». Лог файлы можно открыть текстовым редактором, умеющим работать с файлами в формате txt. В лог файле фиксируется время возникновения события, код завершения (0-удачное завершение, 1-ошибка) и текст сообщения.


Добавление обработки значения свойства System.LastError дает возможность анализировать ситуацию, когда ваш эксперт работает некорректно. Это свойство сохраняет номер последней ошибки, связанной с торговыми операциями. У этого свойства есть важная особенность: каждая последующая торговая операция изменяет это свойство в соответствии с результатом своей работы. Таким образом, если у вас есть скрипт, который отправляет запрос на проведение сделки с ошибочным параметром и затем устанавливает ордер уже с корректными параметрами, то в System.LastError запишется нулевое значение (нет ошибки). Следовательно, получать значение свойства System.LastError нужно ДО следующей торговой операции (в нашем случае установки ордера), именно тогда в ней будет храниться код ошибки возникшей в процессе совершения сделки. Для получения текстового описания ошибки служит метод System.ErrorDescription(), который возвращает строку с текстовым описанием проблемы, а принимаемое значение есть числовой код ошибки, получаемый при помощи System.LastError.


При отладке может оказаться полезным свойство IsStopped объекта System. Оно имеет значение true, если выполнение программы, связанное с приходом последнего тика, заняло более 7 секунд. С помощью этого свойства программист информируется, что скрипт скоро (через 3 секунды) принудительно остановится. Тем самым, скрипт получает время для выполнения каких-либо программных действий по корректному завершению работы скрипта.


Резюме

В заключение хотелось бы отметить, что создание эксперта можно условно разделить на две большие стадии: разработка алгоритма и написание его кода. От того, насколько тщательно была проработана первая стадия, зависит легкость и скорость реализации второй. В статье были приведены некоторые важные вопросы составления алгоритма, а также практические решения, дающие возможность упростить Ваше первое знакомство с языком NTL+ и его возможностями.


IFCMARKETS. CORP. не является компанией, регулиремой ЦБ РФ, и не предоставляет финансовые услуги на территории РФ. Переведенная страница не ориентирована для граждан РФ.