Как выполняются скрипты в терминале QUIK #
В прошлой статье мы разобрали как создать свой первый скрипт, запустили его. Давайте вспомним код из него:
function main()
message("Запущен мой скрипт");
end
Код написан всего в несколько строчек. Оставим на потом разбор самих функций, используемых в скрипте, а сейчас рассмотрим именно порядок исполнения функций в коде. Это нужно именно для понимания того, что код не всегда будет исполняться по порядку, в котором мы его создаем, например со второй строки. Это зависит от используемых функций в коде. В нашем примере мы использовали одну функцию — main. Скрипт, написанный на LUA в терминале КВИК, может включать одновременно ряд функций, обрабатывающих различные события (например, изменение котировок, новая сделка и пр.).
Последовательность исполнения скрипта на языке LUA в КВИКе представим так: #
Нажимая «Запустить» в разделе «Сервисы -> Lua скрипты«, начинает свою работу скрипт. Сначала обрабатывается основа скрипта без всех функций (на картинке обозначено как — BODY) и вызова обработчика Init(). Дальше после того, как выполнится функция Init(), образовывается отдельный новый поток в терминале КВИК и именно в нем запускается функция main(). Пока функция main исполняется, скрипт можно считать запущенным. При завершении исполнения функция main, выполнение скрипта также останавливается, т.е. и вызов из него обработчиков событий.
И главное, функции обработки событий, выполняются в основном потоке терминала QUIK, в отличие от функции main(), из этого следует, что они должны работать мало, иначе будут видны «подтормаживания» в работе КВИКа.
Представим наш скрипт Укрупненно в виде такой схемы #
Схематично показан наш скрипт. Состоит из четырех компонентов. В красном блоке расположена главная функция main. И как писали выше, что функция может находиться не в начале скрипта. Пара желтых блоков — это функции, которые создает сам пользователь. Нижний синий блок — это функция обратного вызова. И немного поговорим о данной функции.
Функция обратного вызова может запускаться в любое время. Исполняется функция, при появлении нового события, коих может быть большое количество и для каждого своя функция.
Если откроем справочник QLUA.chm из папки с КВИКом, то можем узнать, что за события используются в КВИКЕ и что за функции с ними связаны. Находим в заглавии — Функции обратного вызова.
И узнаем, что функция Main — это функция обратного вызова.
Цитата из инструкции:
«Функция, реализующая основной поток выполнения в скрипте. Для ее выполнения терминал QUIK создает отдельный поток. Скрипт считается работающим, пока работает функция main(). При завершении работы функции main() скрипт переходит в состояние «остановлен». Если скрипт находится в состоянии «остановлен», то не происходит вызовов функций обработки событий терминала QUIK, содержащихся в этом скрипте.»
Главный момент — это то, что Main исполняется в своем новом потоке и не мешает процессам основного функционала терминала КВИК.
Допустим, сам КВИК сейчас занят подгрузкой исторических данных для открытых графиков инструментов, пока это происходит, цена в моменте меняется, т.к. торги идут, появляется нужная нам цена для входа. В скрипте указали алгоритм, что при появлении нужной цены надо тут же открыть позицию на покупку, скрипт готов к покупке, но не может это сделать, он ждет пока QUIK подгрузит все исторические данные. И пока это происходит (вроде бы несколько секунд), но нужная цена уже изменилась, а наш скрипт только начал работу. Это и есть выполнение скрипта в одном потоке с выполнением терминала КВИК. Постараемся исключить этот момент, применив main, тем самым сделаем свой отдельно работающий поток, тем самым добиваемся немедленной покупки, даже если сам терминал в это время загружен каким-то процессом.
Перейдем к следующему блоку в нашей схеме — OnInit (функция обратного вызова), в схеме показана синим. В справочнике по LUA про эту функцию написано следующее:
«Функция вызывается терминалом QUIK перед вызовом функции main(). В качестве параметра принимает значение полного пути к запускаемому скрипту.»
Основное для нас — функция OnInit исполняется до начала выполнения функции main. Следовательно по порядку — сначала сработает функция OnInit, а после ее выполнения, начнет отрабатывать функция Main. А т.к. вызывается OnInit до вызова main, то выполнение функции OnInit осуществляется в общем потоке QUIK, т.к. main еще не была вызвана, следовательно отдельного поток еще нет.
Рассмотрим функции, создаваемые нами, т.е. пользователями. #
Программист может создать в своем скрипте сколь угодно много собственных функций, которые будут исполняться по отдельному событию, так как они не являются функциями обратного вызова, а следовательно их нужно вызывать. На схеме указано, в main и OnInit вызов функции, следовательно из данных функций вызываются пользовательские функции. Пользовательские функции исполняются в том потоке, в котором их вызвали. В потоке платформы QUIK запускается функция myFirstFunc. Функция mySecondFunc запустится уже в другом своем потоке, т.к. вызвана с помощью функции main.
А теперь разберем все на живом примере. #
На первый взгляд может показаться все сложно и непонятно, но давайте разберемся!
Сначала объявляем таблицу t и в поле 0 устанавливаем время, в течении которого работает терминал QUIK. Для нас будет точка старта выполнения кода. В другие графы запишем разницу между временем в необходимый момент и стартовой точкой, в итоге узнаем сколько времени прошло в любой момент кода. Со следующей строки запишем время старта скрипта, потом сделаем паузу в 100 мс. Дальше в нужных точках кода указываем, где расположено исполнение и время в данный момент, этим мы определим последовательность выполнения кода. В завершении, перед остановкой функции main, покажем информацию, где покажем все указанные точки.
Можете скачать файл и запустить в Квике у себя. Должно получиться данное сообщение.
Смотрим на метки по времени. 1я метка «Запуск» и время 0, скрипт только запустился и прошло 0 мс. 2я метка «Отметили myFirstFunc» и время 0,101, это означает — Квик получил информацию, что есть функция myFirstFunc спустя 101мс после старта скрипта, но только лишь узнал про функцию, при этом основа функции не исполнилась. А чем был занять скрипт эти 100мс? Собственно ничем 🙂 Просто ожидал. Получил команду sleep(100) в строка номер 2. Обращаем ваше внимание, что функция main тоже отмечена, в это время, но не исполняется пока и новый поток для нее не создан. Так же поступили и другие метки участвующих функций.
Смотрим на цвет курсора. Сначала цвет был синим, что показывает процесс исполнения кода в потоке самой платформы QUIK, а после исполнения функции OnInit() поток в QUIK начинает выполнять функционал самого терминала, при этом создан новый поток — окрашен в желтый цвет. После завершения функции main, новый поток исчезает и сам скрипт останавливается.
В статье попытались понять последовательность выполнения процессов в запущенных нами скриптах, написанных на языке LUA в торговом терминале QUIK.








