Тема: Пример: спредовый робот на QLua
Хотелось бы сделать несколько примеров простых роботов на LUA в QUIK, чтобы с одной стороны показать, как я вижу парадигму использования данного языка в QUIK, с другой - обменяться мнениями и послушать другие идеи, которые, надеюсь, непременно здесь будут опубликованы.
Материал будет выкладываться постепенно, так что заходите, пишите отзывы, критикуйте, предлагайте свои решения
В качестве первого примера возьму за основу [url=http://forum-archive.quik.ru/forum/lua/97085/]алгоритм спредового робота, предложенный на форуме сайте Arqa[/url]. Реализуемый моём примере алгоритм я несколько упрощу относительно описанного на форуме Arqa, будет надобность и интерес посетителей - дополню и расширю.
Алгоритм изложу так:
1. Мониторим один инструмент, по нему же открываем позицию. Красс и код инструмента задается константами SEC и CLASS.
2. В константе P_SPREAD задается пороговый процент спреда (в процентах). Например, 0.1
3. Следим за лучшими аск и бид по указанной бумаге.
4. Если спред расширяется до P_SPREAD или более и время сессии торговое, то становимся лучшим бидом в размере 1 лот. Если спред сужается ниже порогового - уходим.
5. Если второй под нами человек в стакане опускается, и нам есть куда опуститься, мы тоже опускаемся, оставаясь лучшими.
6. Если нас акцептовали, образовалась длинная позиция по нашему инструменту, то мы его тут же выставляем на продажу (1 лот), встав лучшими на офере. Если нас обгоняют на офере, мы тоже обгоняем. Если второй офер над нами подымается, мы тоже поднимаемся. Т.е. поддерживаем цену заявки такой, чтобы она была лучшей в стакане.
7. Продав имеющуюся бумагу, начинаем алгоритм по новой.
Общая идея реализации:
Заводим глобальную переменную CURRENT_STATE, где храним текущее состояние:
'0' - нашей котировки нет, ждем нужного спреда, при его возникновении выставляем заявку на покупку
‘OB’ – выставлена заявка на покупку, ждем ответа на транзакцию
'N' - активна заявка на покупку, позиция не открыта, удерживаем позицию лучшего спроса в стакане
'1' - открылась длинная позиция, необходимо выставитьзаявку на продажу
‘OS’ – выставлена заявка на продажу, ждем ответа на транзакцию
'L' - открылась длинная позиция, удерживаем позицию лучшего предложения
'MB' - снята активная заявка, необходимо перевыставить новую на покупку
'MS' - снята активная заявка, необходимо перевыставить новую на продажу
Обработчики, которые будут задействованы:
OnInit() - проверяем текущий спред, если он уже достаточен для открытия позиции - длинную открываем позицию.
OnQuote() - отслеживаем спред, поддерживаем лучшей спрос/предложение.
OnTransReply() - фиксируем результат выставления заявки на открытие или закрытие позиции, корректируем значения переменной состояния в зависимости от результата.
Текст кода робота буду формировать отдельными кусками с подробюным описанием. Куски эти будут дополнять друг друга, при этом постараюсь, чтобы в каждый момент времени весь скрипт из прочитанных кусков был исполнимым и корректным. Удобно это для того, чтобы в каждый момент времени его можно было запускать в терминале QUIK и смотреть на результат.
Начиная с этого места, читатель может открыть в блокноте (или любом другом текстовом редакторе) пустой файл с удобным именем и расширением .lua, и, по ходу изложения, наполнять свой файл все новыми и новыми кусками текста будущего робота, параллельно проводя эксперименты по запуску скрипта, анализу и осмыслению результатов (разумеется, только на демонстрационном счете!).
В конце есть ссылка на файл-архив с полным текстом.
Итак, для начала определим константы и глобальные переменные:
-- Константы --
MIN_P_SPREAD = 0.001 -- минимальный пороговый процент спреда
MIN_SPREAD_STEP = 5 -- минимальное количество шагов спреда, когда открываем позицию
SEC = "LKOH"
CLASS = "QJSIM"
PRICE_STEP = 0.1 -- шаг цены по инструменту
PRICE_SCALE = 1 -- точность задания цены инструмента
TRADE_ACC = "NL0011100000" -- торговый счет
CLIENT_CODE = "qtest" -- код клиента
-- Переменная состояния --
CURRENT_STATE = '0'
-- Глобальные переменные --
current_order_num = 0 -- номер текущей активной заявки
current_order_price = 0 -- цена в текущей активной заявке
uniq_trans_id = 0 -- уникальный номер последней отправленной транзакции
Для начала реализуем функцию SendOrder(), которая в зависимости от текущей позиции по инструменту, определяемому на основании значения переменной CURRENT_STATE, будет выставлять заявку либо на покупку, либо на продажу в размере 1 лота.
... ( to be continued ) ...
[url=https://quik2dde.ru/static-img/spread-robot1.zip]Скачать полный исходный текст[/url]