Блог им. morefinances

Qlua: работа с заявками (часть 2).

Сегодня:

Узнаем общее количество заявок
Функции getNumberOf и getItem
Как пройтись циклом по всем заявкам
Вывод активных заявок
Снять скриптом заявку
Снимаем все активные заявки скриптом
Снимаем только заявки, выставленные конкретным скриптом


В прошлый раз мы научились
выставлять скриптом заявки в терминале, теперь можем поработать с ними.
Выставим скриптом 5 заявок на покупку и продажу от лучших цен
BIDи OFFERстакана заявок с шагом в 0,01.

 

Напишем функцию, которая будет выдавать нам необходимые цены (лучшую цену спроса и предложения) со стакана:

Qlua: работа с заявками (часть 2).

И возвращать -1, если предложения или покупки в стакане не найдены (стакан закрыт, либо нет торгов).

Тогда основной алгоритм в main будет выглядеть:

Qlua: работа с заявками (часть 2).

Функцию выставления заявки 
newtransaction() мы прописывали ранее, она не изменится.

 

Запустим скрипт, увидим в нем свои заявки:

Qlua: работа с заявками (часть 2).

Теперь поработаем с ними.

 

Узнаем общее количество заявок

Количество строк в таблице заявок (т.е. сумму как активных заявок, так и снятых и исполненных) можно получить через функцию getNumberOf:

number = getNumberOf("orders")

message("Количество заявок: "..number)


Данная функция позволяет получать количество строк из различных таблиц терминала. Используется чаще всего вместе с функцией
getItem с помощью которой мы можем получать уже сами значения таблиц и смотреть в т.ч. лимиты по деньгам, лимиты по бумагам, информацию по сделкам и пр.  Подробное описание можно найти в файле QLUA.chm  (находится в папке с терминалом) при поисковом запросе getNumberOf:

Qlua: работа с заявками (часть 2).

Сейчас нас будут интересовать заявки.

Каждая строка таблицы заявок представляет собой массив данных с набором параметров. Нумерация строк идет с 0. Параметры таблицы каждой строки можно посмотреть в мануале QLUA раздел getNumberOf, далее Заявки (orders):

Qlua: работа с заявками (часть 2).

Следующий скрипт пройдется по таблице заявок и выведет по каждой номер, цену, объем и комментарий.

Qlua: работа с заявками (часть 2).
Результат

Qlua: работа с заявками (часть 2).

Внимательно изучая таблицу параметров можно заметить, что нигде не прописаны направление (покупка/продажа), а также статус по заявке (активная, снята, исполнено). Это разработчики решили спрятать во флаги (
flags), с которыми нам нужно будет работать побитово. Чтобы не было скучно, видимо.

Qlua: работа с заявками (часть 2).

Примеры
:

bit.band(tonumber(myorder["flags"]), 1) >  0 -- активная заявка

bit.band(tonumber(myorder["flags"]), 4) >  0 -- заявка на продажу

Вывод всех активных заявок:

Qlua: работа с заявками (часть 2).

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

Выведем активные заявки на покупку:

Qlua: работа с заявками (часть 2).


Результат:

Qlua: работа с заявками (часть 2).

Номер заявки в торговой системе (order_num) нам нужен, чтобы работать далее с ней. Например, снять заявку.

 

Снять скриптом заявку

Чтобы снять активную заявку нужно знать её номер (order_num не путать с idтранзакции!). Если мы его знаем и хотим запустить транзакцию на удаление нам достаточно передать в sendTransactionследующую таблицу:

Qlua: работа с заявками (часть 2).

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

Если мы уверены, что нужная нам заявка находится последней в таблице, то мы можем, получив по getNumberOfколичество строк таблицы заявок просто взять последнюю строку (с нумерацией getNumberOf() – 1) и по её номеру выставить транзакцию на снятие заявки.

Однако мы рассмотрим вариант, когда мы не знаем активна последняя заявка или нет и будет циклом перебирать в обратном порядке список заявок построчно, пока не дойдем до первой активной заявки. Её и снимем (она может попасться сразу, а может быть и в середине таблицы или даже в самом начале, если мы вручную или скриптом ранее снимали остальные заявки, либо какие-то заявки исполнились).

Сделаем функцию, которая будет снимать заявку по её номеру в терминале (order_num):

Qlua: работа с заявками (часть 2).

Проходим циклом по всем строкам таблицы заявок в обратном порядке и как только находим первую активную заявку снимаем её:

 Qlua: работа с заявками (часть 2).

Файл: https://github.com/morefinances/qlua/blob/main/delete_one_order.lua 

Снимаем все заявки скриптом

Чтобы снять разом все активные заявки нам достаточно в предыдущем примере убрать (или закомментить --) break в цикле, который обрывал работу после снятия первой найденной активной заявки. В этом случае цикл пройдется по всем строкам таблицы заявок и через новые транзакции снимет каждую активную заявку.

Qlua: работа с заявками (часть 2).
Снимая заявки в обратном порядке мы чуть ускоряем работу скрипта, т.к. преимущественно активные заявки находятся в конце списка таблицы заявок.

Выставим заявки по биржевому стакану скриптом с которого начинали статью. И теперь можем разом снять их:

Qlua: работа с заявками (часть 2).

Видим по комментариям, что снимались сперва те заявки, которые выставились последними. Всё автоматизировано.

 

Снимаем только заявки, выставленные конкретным скриптом.

Чтобы скрипт снял не все заявки, а только собственные, ранее выставленные, нам нужно обращаться к комментарию заявки (CLIENT_CODE) и сверять по нему (при условии, что другие скрипты делают собственные комментарии, отличные от варианта текущего алгоритма).

Qlua: работа с заявками (часть 2).

Здесь в string.sub(myorder["brokerref"], 8, 15) – первые 7 символов это торговый код и двойной слэш, поэтому делая срез с 8 по 15 получаем именно тот общий комментарий (code_order), который делал скрипт при выставлении заявки, но без слэша и номера id заявки.

Для проверки работы скрипта выставим вручную в терминале заявку, например, на продажу объемом в 10 лот.

Qlua: работа с заявками (часть 2).

Qlua: работа с заявками (часть 2).

После этого опять запустим скрипт выставления заявок по стакану.

Qlua: работа с заявками (часть 2).

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

Qlua: работа с заявками (часть 2).

Теперь снимем скриптом заявки, выставленные алгоритмом.

Qlua: работа с заявками (часть 2).

Видим, что заявка, выставленная вручную осталась активной, остальные снялись:

Qlua: работа с заявками (часть 2).

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

В следующей статье завершим работу с заявками.


Самостоятельная работа:

1) Напишите скрипт, закрывающий все активные заявки по таймеру, например в 18:30.
2) Измените предыдущий скрипт так, чтобы заявки по таймеру не закрывались, а перевыставлялись на исполнение по рынку.
3) Напишите скрипт, который делает покупку по рынку 1 лотом GAZP в 11:01 и продает в 11:55.
4*). Напишите скрипт, который выставляет тейк и стоп после исполнения заявки, при этом если по таймеру (например 2 часа) ни один уровень не достигнут, то позиция принудительно закрывается по рынку.

Теги: qlua для начинающих, кружок авиамоделизма.

Ранее:

Qlua: введение
Доля клиентов, использующих алгоритмическую торговлю
«Кружок авиамоделизма»
Разные торговые терминалы, почему Quik
Основной функционал qlua
smart-lab.ru/blog/917696.php

Настраиваем торговый терминал и редактор кода
Установка торгового терминала
Подготовка терминала
Вкладки в терминале
Сохранение и загрузка настроек
Таблица системных сообщений
Отключение окна сообщений
Редактор Notepad++
Настройка русского языка в редакторе
Выбор синтаксиса языка и кодировки
Цветовые настройки
Дублирующий просмотр
Запуск первого скрипта
smart-lab.ru/blog/918869.php

Основы qlua, часть 1:
message, конкатенация
фильтрация по сообщениям в терминале
PrintDbgStr, комментарии
типы данных, type
операции с числами
операции со строками
операции с таблицами
условные операторы
smart-lab.ru/blog/920031.php

Основы qlua, часть 2:
Циклы for … do … end, while do … end, repeat … until.
sleep, break, goto.
как пройти весь массив циклом, как пройти таблицу по ключам
локальные и глобальные переменные, функции
получение даты и времени
получение данных через getInfoParam
smart-lab.ru/blog/921366.php

Qlua: структура скрипта.
Структура типового скрипта qlua с примерами.
Обработка скриптом «обрыва связи» с сервером и возобновления работы.
Работа с файлами: запись, перезапись и чтение файла.
getScriptPath, getWorkingFolder
smart-lab.ru/blog/922044.php

Qlua: получение данных из таблицы текущих торгов, создание таблиц в торговом терминале.
Получение биржевых данных через функцию getParamEx
Выгрузка списка параметров функции getParamEx через DDE из торгового терминала
Создание пользовательских таблиц в торговом терминале
smart-lab.ru/blog/923365.php

Qlua: работа с таблицами (продолжение). Пишем своего советника (начало).
Интегрируем таблицы в структуру скрипта qlua.
Удаляем таблицы через DestroyTable.
Останавливаем скрипт через IsWindowClosed.
Обработка события закрытия таблицы через коллбэк.
Работа с цветом SetColor, Highlight, SetSelectedRow.
Пишем простого советника.
smart-lab.ru/blog/924710.php

Qlua: дополняем скрипт советника таймингом:
Устанавливаем время старта работы скрипта,
Ставим тайминг на получение сигналов на вход,
Устанавливаем таймер на приостановку скрипта.
smart-lab.ru/blog/925421.php

Qlua советник: дополняем сигналами на закрытие позиции, таблицей для вывода данных и расчетом финансового результата по позициям.
Дополняем сигналами на закрытие позиции.
Создаем дополнительную таблицу для вывода данных.
Делаем расчет финансового результата.
smart-lab.ru/blog/926972.php

Qlua: завершаем апгрейд советника:
Пропуск «поздних» сигналов на старте.
Обработка советником обрыва связи.
Сохранение сигналов и логов в файл.
smart-lab.ru/blog/927748.php

Qlua: пишем скринер акций Московской биржи
smart-lab.ru/blog/928152.php

Qlua: получение данных биржевых свечей с сервера брокера, обработка данных, пишем скрипт выгрузки котировок
Функция CreateDataSource
Получение количества свечек данных
Пауза для подгрузки данных
Получение по инструменту OPEN, HIGH, LOW, CLOSE, VOLUME
Обработка времени и даты
Закрытие источника данных
Примеры: получение данных последних 10 свечей, выгрузка новой минутной свечки после её закрытия, текущее значение простой средней SMA10 по минуткам
Простой скрипт выгрузки котировок
smart-lab.ru/blog/929905.php

Qlua: получение данных с графиков терминала.
Идентификатор инструмента
Получаем количество свечей через getNumCandles
Получаем свечные данных через getCandlesByIndex
Читаем данные с индикатора SMA
Данные с верхней и нижней линии Price Channel
Графики с таблицы текущих торгов.
Сравнение получение данных через CreateDataSource и через getCandlesByIndex
smart-lab.ru/blog/931408.php

Qlua: работа с метками, пишем торгового советника на индикаторах.
Вывод текста на график
Вывод графических сигналов
Удаление меток с графика
Торговый советник на индикаторах
Удаление данных вечерней/утренней сессии с графика.
smart-lab.ru/blog/933582.php

Qlua: работа с лентой всех сделок.
Что такое таблица обезличенных сделок.
Настройка таблицы в терминале.
Что делать, если таблица открылась, но она пустая.
Вывод данных с таблицы по DDE.
Работа с таблицей обезличенных сделок через скрипт qlua с примерами.
Пишем советника, показывающего на графике крупных игроков.
smart-lab.ru/blog/935919.php

Qlua: работа с лентой всех сделок (часть 2).
Различия данных ленты всех сделок и биржевого стакана.
Большие покупки и продажи в ленте сделок и динамика цены.
Альтернативные варианты поиск крупных игроков по ленте сделок.
smart-lab.ru/blog/938053.php

Qlua: дополняем скринер акций статистикой, лидерами роста и падения.
Добавляем статистику по акциям роста и падения.
Составляем TOP лидеров роста и падения.
Быстрый поиск акций по тикеру в терминале.
smart-lab.ru/blog/938450.php

Qlua: работа с биржевым стаканом.
Работа с биржевым стаканом через getQuoteLevel2
Особенность нумерации в стакане заявок терминала квик
Работа через функцию обратного вызова OnQuote
Примеры работы со стаканом из скрипта
Сравнение реализации одного алгоритма через разные функции
smart-lab.ru/blog/940742.php

Qlua: работа с заявками (часть 1).
Зачем нужен демо терминал
Где открыть учебный счет
Выставление заявки в торговом терминале через скрипт
Делаем функцию выставления заявки по требуемым условиям
Карман заявок и tri-файлы
Параметры для заявок с примерами по разным рынкам
smart-lab.ru/blog/942481.php

  • обсудить на форуме:
  • Quik Lua
★13
26 комментариев
Учитывая потенциальную возможность встретить отрицательные цены, лучше не использовать -1 для обозначения отсутствия цен.
Например: в календарных спредах легко найти отрицательную цену.
avatar
Jame Bonds, спасибо!) В стакане акций, к счастью, пока нет таких) Но на фьючах уже была история. Скрипт отработает нормально отрицательные цены — он просто не будет выставлять по ним заявку.
avatar
Что посоветуете использовать вместо комментария, для идентификации заявок, если брокер не дает туда писать, вернее перезатирает его?
Номер транзакции тоже ненадежен в этом плане.
avatar
Surmounter, не встречал, чтобы брокер перезатирал. вы точно не путаете с попыткой написать комментарий при ручном выставлении? Номер заявок можно складывать в массив внутри скрипта, тогда не нужно проходить по таблице заявок, вы всегда будете знать номера и последовательность выставления именно своих (текущего скрипта) заявок.
avatar

alfacentavra, открытие брокер, пишет мне в коммент всегда код клиента.
Да, приходится хранить все заявки.

avatar
Surmounter, Хм. Открытие вполне нормально работал. 1. Убедитесь, что в CLIENT_CODE при выставлении заявки вы даете строковый комментарий (переведите через tostring). 2. Напишите в поддержку брокера, если они реально со своей стороны вводят какие-то ограничения, то в частном порядке вполне могут и снять. Код клиента пишется всегда по умолчанию, да. Комментарий идет далее после //
avatar
Surmounter, Храните номера всех отправленных транзакций, заявки и сделки будут содержать этот номер, что позволяет их легко идентифицировать.

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

avatar
Surmounter, Не может такого быть, механизм транзакций является ключевым для написания роботов. Возможно вы путаете номер транзакции и номер заявки.
Станислав Потемкин, еще как может, было пару раз в этом году на вечерней сессии. Перепутать тут сложно, я про TRANS_ID
avatar
Surmounter, Никогда с таким не сталкивался. Если у вашего брокера такое случается это очень серьезный повод от него уйти, потому что алго-торговля с такими проблемами работать не будет.

Еще добавлю, что для получения лучшего спроса и предложения по инструменту не надо подписываться на очень «тяжелый» поток данных Level_II_Quotes. Эти данные есть в таблице текущих торгов, получаемые очень быстро и просто. И если уж рассматривается метод getQuoteLevel2, то важно уточнять, что без подписки он будет работать если стакан уже открыт самим пользователем. Что вероятно и будет сделано, но, например, вероятна ситуация, когда нет открытых окон в терминале. Все заказывается скриптами.

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

Но как учебный пример в учебной ситуации — годится. Хотя, конечно, лучше сразу предусматривать в коде нештатные ситуации. Избегать sleep, т.к. это плохой подход в клиент серверном взаимодействии. В конечном итоге, пишется же инструмент для работы с деньгами, т.е. он должен быть надежным даже когда время ожидания ответа от сервера брокера достигает десятков минут.

avatar
nicknh, спасибо за комментарии. что за метод снимает все активные заявки из скрипта, напишите пожалуйста.

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

alfacentavra, При указании действия транзакции указать

«KILL_ALL_FUTURES_ORDERS»

 

Для фондовой секции, действительно, это пока не работает. Для срочного рынка вполне себе работает, хотя, это важно, по одному инструменту. Т.е. можно снять все ордера по инструменту Si. Но т.к. большинство скриптов, по какой-то причине, пишется на один инструмент, то думаю, что это вполне годится.

 

Что касается sleep, то в отдельном потоке исполнения скрипта, в бесконечном цикле в main, надо указать что-то большее чем 0. Если используются таблицы qlua как интерфейс, то больше чем 50. Но речь была про ожидание после подачи транзакции. Как я написал, Вы не знаете сколько будет идти ответ транзакции. Т.о. у вас нет ответа на вопрос — когда после подачи транзакции уже можно искать ордер в таблице ордеров. Большинство решает это через колбек. Пришел — можно искать. Что вполне годится, если понимать минусы колбеков Квика.

avatar
nicknh, ясно, спасибо.

Да, по поводу работы с заявками в предыдущей статье писал, что пока мы просто закладываем ожидание на обработку. OnTransReply будет в следующей статье.
avatar
nicknh, спасибо… можно подробнее про «избегать sleep», как я понимаю что бы его избежать надо цепляться к какому-либо событию, что не всегда возможно…
avatar

Сергей Иванов, Нет. Необходимо изменить подход к работе. Отправляя транзакцию, Вы создаете запрос на сервер — сделай то-то, пришли ответ.

В идеальном мире это занимает 100-200 млс. А в реальном — может достигать 10 минут. Т.к. Вы не можете каждый раз задавать время ожидания в коде, то и подход должен быть — создай задачу, начинай выполнять ее и жди пока не придет ответ. И таких задач может быть много. Например, поставить сразу 100 ордеров по совершенно разным инструментам. Поэтому подаем сразу 100 транзакций (но в реальности не более 30 за секунду) и ждем ответа по ним.

 

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

avatar
nicknh, если вы про KILL_ALL_ORDERS, то это работает только для кармана транзакций и tri-файлов. В прошлой статье об этом писал.
Разработчики на форуме также говорят об этом: 

forum.quik.ru/messages/forum10/message69267/topic3348/#message69267

avatar
alfacentavra, спасибо за урок…
Вопрос немного не по теме, а есть ли у Вас опыт работа с различными типами заявок типа Стоп-лимит (Stop limit), Тейк профит… рекомендации по ним?
В частности интересует механизм реализации Тейк профит: у моего брокера нет алгоритмических заявок, а я бы хотел каждый день автоматом выставлять заявку на продажу по цене к примеру 101. Выхода два: 1) ставить скриптом, 2) использовать Take profit. Вопрос такой — если была заявка на покупку по рыночной цене которая с 99 пробьет цену до 105, то в какой очередности обработаются — прямая заявка по 101, прямая заявка по 102, заявка Take profit по 101…
avatar
Сергей Иванов, каждый день выставлять вы вполне можете скриптом, всё для этого уже пройдено.
Если хотите работать вручную, то при выставлении стоп-заявок (стоп-лимит/тейк-профит/стоп-лимит и тейк-профит) нужно понимать, что это только условия на выставления заявки. Когда эти условия срабатывают (цена по инструменту достигает необходимого уровня с учетом заданного отступа и спрэда) только тогда на сервер брокера уходит заявка на покупку/продажу. В вашем примере если цена резко пробила уровни 99-102, но после сразу ушла обратно на 99, например, то при тейке 101 сделка может и не пройти.
Скрипт может все эти события отработать, в т.ч. в него можно заложить перевыставление тейка, если цена ушла ниже. Т.е. скрипт это сделает сам, а в терминале это нужно будет перевыставлять руками повторно.
avatar
alfacentavra, извиняюсь только добрался до компьютера..
С выставлением заявки скриптом смущает то, что как я понимаю терминал должен работать — 24/7. Если терминал отключить, то скрипт остановится ?  Можно как то эту проблему «терминал 24/7» решить по иному?
avatar
Сергей Иванов, решается арендой виртуального сервера, где устанавливаете и запускаете терминал. Если сервис хороший там, как правило, редко бывают сбои. А так — и электричество могут отключить, и биржа может приостановить работу, и интернет пугают, что отключат. В этой сфере много инфраструктурных рисков.
avatar
Сергей Иванов, лимитные заявки исполнятся сразу, по заявке тейк-профит брокер сформирует лимитную заявку согласно параметрам, вероятность исполнения зависит от этих самых параметров.
Станислав Потемкин, спасибо конечно. Можете подсказать по примеру выше? 
"… если была заявка на покупку по рыночной цене которая с 99 пробьет цену до 105, то в какой очередности обработаются — прямая заявка по 101, прямая заявка по 102, заявка Take profit по 101 (отступления от Max — 0, Защитный спред — 0)?
avatar
Сергей Иванов, Если я правильно понимаю условия и вы стоите в стакане по 101 и 102 и еще тейком на 101, а кто-то другой кидает заявку по рынку собирая все ордера до 105, то будет следующее:
1. Исполняется заявка по 101
2. Исполняется тэйк-заявка по 101 и брокер формирует лимитную заявку, через полсекунды она появится в стакане.
3. Исполняется заявка по 102
4. В стакане появляется заявка по тейк-профиту по 101, ее исполнение зависит от встречных заявок.


теги блога alfacentavra

....все тэги



UPDONW
Новый дизайн