Market Vectors / Financial One

Пишем робота “по шагам”: Шаг 3

6789

Robots ris 11.jpg [Евгений Ерошкин, частный инвестор]


F&O №11, 2011 Скачать коды к Шагу 3

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

Продолжение. Предыдущие материалы в F&О №8–9,10 за 2011 год.

Итак, наш робот уже многое может (смотри F&О №8-9,10 за 2011 год), но для воплощения торговой стратегии в жизнь ему не хватает умения работы с заявками. Определим порядок действий, которые должна воспроизводить механическая торговая система при появлении сигналов на покупку/продажу:

1. Выставляем заявку на покупку/продажу в зависимости от сигнала;

2. Ждем исполнения торгового приказа;

3. Если заявка исполнилась, сразу выставляем новый «стоп-ордер» и снимаем «старый» (если таковой имеется);

4. Если заявка не исполнилась за отведенный промежуток времени, снимаем заявку и ждем нового сигнала.

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

1. Функция выставления заявки;

2. Функция выставления «стоп-ордера»;

3. Функция покупки;

4. Функция продажи;

5. Функция снятия заявки;

6. Функция снятия «стоп-ордера»;

7. Функция контроля исполнения заявки;

8. Функция Stop-Loss.

Функции выставления заявок

Процесс отправки обычных и стоп-заявок схож. Отличие заключается лишь в том, что для стопа необходимо указывать две цены: стоп-цену (цена, при которой срабатывает стоп и выставляется обычный ордер) и цену, по которой будет размещен обычный приказ. Рассмотрим эти две функции вместе.

Аргументами для функции отправки обычных заявок являются: направление (покупка или продажа, “B”/”S”), цена, тип (рыночная (“M”) или лимитированная (“L”)), код инструмента и класса. Для функции стоп-заявок необходим дополнительный параметр – стоп-цена. Кроме того, она будет возвращать результат – номер стоп-заявки. Когда стоп сработает, он отправит ордер на покупку или продажу для закрытия текущей позиции по рыночной цене. ID транзакции – уникальный идентификационный номер – будем формировать из текущего времени в каждом цикле программы.

' Формируем

идентификатор TransID

SERVER_

TIME=GET_INFO_

PARAM("SERVERTIME")

TransID =0+(SUBSTR

(SERVER_TIME,0,2)&

SUBSTR(SERVER_

TIME,3,2)& SUBSTR

(SERVER_TIME,6,7))

Обмен данными между терминалом и программами на Qpile чаще всего происходит через ассоциативные массивы (MAP), в том числе и отправка заявок осуществляется посредством передачи данных в массиве. Поэтому функция отправки торговых приказов, по сути, просто заполняет необходимые элементы массива и передает последний в терминал. Когда биржа получает ордер, она должна идентифицировать клиента, который его выставляет. Для этого указываются уникальный код клиента и его счет (найти их можно в таблице «Ограничения по клиентским счетам»). После успешного принятия ордера торговой площадкой функция устанавливает флаг наличия активной заявки FlagOrder = 1 и запоминает ее номер в глобальной переменной OrderNumber.

Account="00000000000"

ClientCode ="00000000000"

NEW_GLOBAL

("FlagOrder",0) '

Глобальная переменная

– флаг наличия активной

заявки

NEW_GLOBAL

("OrderNumber",0) '

Глобальная переменная –

номер активной заявки

NEW_GLOBAL

(“TransID",1) '

Идентификатор

транзакции

Order_TIMER="30" '

Длительность периода

ожидания ответа

торговой площадки

Коды функций выставления заявок на языке Qpile приведены в справке.

SP 11.jpg

Покупка и продажа

Функции покупки и продажи по своей логике идентичны, но имеют противоположное значение, поэтому также рассмотрим их вместе. В качестве аргументов будем использовать код инструмента, его класс и количество контрактов (Qty), которое необходимо купить или продать. Эти функции сами рассчитывают цену заявки исходя из лучшей цены спроса/предложения и максимального проскальзывания (Slip). Последнее указывается в единицах минимального шага цены инструмента. Коды функций покупки и продажи на языке Qpile приведены в справке.

SP 11-1.jpg

Функции снятия и контроля исполнения заявок

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

Когда ордер принят торговой системой, остается ждать его исполнения. Для этого достаточно остановить работу программы до наступления этого момента. Но на исполнение приказа может потребоваться некоторое время, и, если ждать исполнения внутри одного цикла программы, оно может превысить период одного цикла (особенно, если последний составляет несколько секунд). Чтобы избежать этого, исполнение ордера будем проверять в последующих циклах. Факт совершения сделки определим по остатку в текущей активной заявке: если он равен «0», заявка полностью удовлетворена. Если приказ не исполнен за отведенное количество циклов (Cycles), то снимаем его. В приведенном примере количество циклов ожидания равно 20. То есть при периоде расчета 1 секунда максимальное время ожидания составит 20 секунд.

NEW_GLOBAL ("Count",0)

' Счетчик циклов

NEW_GLOBAL

("FlagStopOrder",0) ' Флаг

стоп-ордера

NEW_GLOBAL

("PriceStopOrder",0) '

Цена последней заявки –

базовая цена для расчета

стоп-ордера

Cycles =20 ' Количество

циклов ожидания

исполнения заявки

Код функций контроля исполнения заявок приведен в справке.

SP 11-2.jpg

Функция Stop-Loss

Данная функция будет выставлять новый стоп-ордер и снимать предыдущий. Аргументами для нее выступят код класса и код инструмента. В начале работы она определяет баланс по текущему инструменту: если он равен «0», просто снимаем все активные стоп-заявки (если они есть). Если баланс отличен от «0», то в зависимости от занимаемой позиции (короткая или длинная) выставляем новый стоп-ордер, а затем снимаем предыдущий активный стоп. Перед отправкой нового стоп-приказа функция рассчитывает цену стопа (StopPrice) исходя из цены последней заявки (PriceStopOrder) и величины стоп-лосса (wStopLoss). Переменная wStopLoss устанавливается в процентном выражении (в представленном варианте - 30%) от ширины основного канала Width (будет рассмотрена в следующей части).

Width = 0.8 ' Ширина

канала в %

wStopLoss = Width*0.3 '

Ширина стоп-лосса - 30%

от канала

Код функций выставления стоп-заявок представлен в справке.

SP 11-4.jpg

Мы описали необходимые функции для работы с заявками. Все активные действия будут автоматически фиксироваться в LOG-файле, с помощью которого можно контролировать работу программы. Обращения к функциям BUY и SELL будут происходить из основной программы при наличии сигналов на покупку/продажу. Обращения к ORDER_DONE и STOP_LOSS также осуществляются из тела программы при наличии соответствующих флагов: FlagOrder и FlagStopOrder.

SP 11-3.jpg

Новый взгляд

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

1. При появлении сигнала на покупку/продажу идет обращение к функциям BUY/SELL;

2. BUY/SELL рассчитывают цену заявки и выставляют ее через функцию SEND_ORDER;

3. SEND_ORDER отправляет приказ в торговую систему и в случае его принятия биржей устанавливает флаг наличия активной заявки (FlagOrder=1), номер активной заявки (OrderNumber), после чего осуществляется переход на следующий цикл;

4. Если заявка активна (FlagOrder=1), вызывается функция ORDER_DONE, которая проверяет остаток (Rest) исполненных контрактов в текущей заявке;

5. Если остаток (Rest) больше 0, счетчик циклов (Count) увеличивается на единицу, и затем осуществляется переход на следующий цикл;

6. Если количество циклов ожидания (Count) превысило заданное максимальное число (Cycles), снимается заявка (функция KILL_ORDER), обнуляется флаг ее активности (FlagOrder=0), сбрасывается счетчик прошедших циклов (Count=0), после чего ожидается очередной сигнал торговой системы на покупку или продажу;

7. Если остаток (Rest) равен 0 (заявка исполнилась), то обнуляется флаг ее активности (FlagOrder=0), сбрасывается счетчик прошедших циклов (Count=0), устанавливается флаг стоп-ордера (FlagStopOrder=1), задается цена последней заявки (PriceStopOrder) и осуществляется переход на следующий цикл;

8. На следующем цикле при FlagStopOrder=1 идет обращение к функции STOP_LOSS, которая получает текущий баланс по инструменту;

9. При балансе равном нулю снимается стоп (функция KILL_STOP_ORDER), если имеется активный;

10. Если баланс отличен от нуля, выставляем защитный стоп-ордер (функция SEND_STOP_ORDER) и снимаем предыдущий (функция KILL_STOP_ORDER), если таковой имеется;

11. Снимаем флаг стоп-ордера (FlagStopOrder=0);

12. Ожидаем следующего сигнала.

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

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

Скачать коды к Шагу 3

Продолжение - Шаг 4.

SP 11-5.jpg

Понятия:

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

Стоп-заявка – приказ о покупке/продаже, размещенный выше/ниже уровня текущих цен, который реализуется при достижении определенной ценовой отметки. Чаще всего используется для ограничения потерь.

Ассоциативный массив (MAP) – абстрактный тип данных,который позволяет хранитьпары вида «ключ-значение».Используется в языке Qpile.

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





Вернуться в список новостей

Комментарии (0)
Оставить комментарий
Отправить
Новые статьи