Блог им. morefinances

Qlua: основы, часть 2

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

 

Циклы for … do… end
while do … end
repeat … until
sleep
Как пройти весь массив циклом
Как пройти таблицу по ключам и значением
break
goto
Локальные и глобальные переменные
Функции
Получение даты и времени
Получение данных через getInfoParam


Цикл for … end

for index = start, end, step do 
-- start – начало отсчета, 
-- end – конец отсчета, step - шаг

  -- тело цикла

end



Пример:

for i = 1, 10 do -- пройтись от 1 до 10 c шагом 1 (по умолчанию)<br />
  message("i="..i)  -- вывод i<br />
end

Можно задать шаг:

for i = 1, 10, 2 do -- пройтись с 1 до 10 с шагом 2

  message("i="..i)

end

Цикл while do...end

while (условие) do

  -- тело цикла

end


Выполняет тело цикла, пока соблюдается условие. Если условие на старте не соблюдается, то цикл не запустится.

Пример:

a = 1

while a < 9 do

   a = a + 1

   message(tostring(a))

end

 

Цикл repeat … until

repeat

-- тело цикла

until(условие)


Выполняет условие цикла минимум один раз, если условие соблюдается запускается повторное выполнение тело цикла.

a = 1

repeat

  a = a + 1

  message("a="..a)

until(aa > 5) -- будет выполняться пока а не станет больше 5


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

repeat

  …

until a > 5

Однако в текущей версии терминала этот скрипт просто подвесит квик, т.к. программа не обнаружит скобок с условиями и уйдёт в вечный цикл. Также как и отдельные функции lua работы со строками и таблицами сейчас перестали поддерживаться (видимо оказались слишком мало востребованными), а какие-то модифицировались (вместо message для вывода сообщений ранее использовалась функция MsgBox, например, хотя в оригинале самого языка это print). По этой причине отдельные скрипты, написанные 5 и более лет назад, полезно изучать, но приходится, порой, адаптировать под текущий синтаксис и условия реализации языка в терминале.

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

for i = 9, 0, -1 do -- пройтись с 9 до 0 с шагом -1

  message("i="..i)

  sleep(10)

end

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


Пройти массив циклом

Бывает полезным пройтись по всем значениям массива. Это делается следующим образом:

t = {0, 10, 25, 30, 48, 52}

for i = 1, #t do

  message("t["..i.."] = "..t[i])

end

 

for i = #t, 1, -1 do -- пройти по массиву в обратном порядке

  message("t["..i.."] = "..t[i])

end

 

Пройти таблицу по ключам и значением

Также в язык заложена возможность пройти таблицу по ключам 

table_lots = {['SBER'] = 10, ['VKCO'] = 1, ['POLY'] = 1, ['VTBR'] = 10000}

-- альтернативная запись: table_lots = {SBER = 10, VKCO = 1, POLY = 1, VTBR = 10000}

for key, value in pairs(table_lots) do

    message('ticker :'..key.." lot="..value)

end

Однако, если запустить этот скрипт несколько раз подряд, то можно обнаружить, что pairs рандомно формирует порядок вывода.

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

break

В отдельные моменты бывает полезным прервать цикл, чтобы не дожидаться его завершения. Это делается через break:

for i = 1, 10 do

   if i == 5 then break end – на i=5 цикл прервётся

   message(""..i)

end

Аналогичным образом break работает и в циклах while do … end и в repeat … until.

 

goto

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

for i = 1, 10 do

   if i == 3 then goto NXT end    -- цикл пропустит 3

   message("i="..i)

:: NXT ::

end

 

for i = 1, 10 do

   if i%2 == 0 then goto NXT end   -- цикл пропустит все четные итерации

   message("i="..i)

:: NXT ::

end

 

Локальные и глобальные переменные


Несколько слов про переменные в целом: переменные – это любые наборы букв, цифр и нижнего подчеркивания (при этом переменная не может начинаться с цифры). Помним про регистр (Abc, ABC и abc – разные переменные). Также в качестве имен переменных нельзя использовать зарезервированные слова (функции и константы qlua).

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

Пример объявления локальной переменной:

local a = 5

глобальной:

a = 5

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

 

Функции

Это один из важнейших инструментов в qlua. Большая часть кода скриптов так или иначе завязана на пользовательские функции, функции библиотек и функции терминала, в т.ч. так называемые функции обратного вызова, которые срабатывают когда произошли какие-то изменения (в стакане, таблице, в соединении с сервером и пр.). Функции в lua могут быть записаны в переменные, переданы как параметры в другие функции и возвращены как результат выполнения функций.

Синтаксис функции:

function name_fun(param) -- param – один или несколько (разделяются запятой) входных параметров, их можно пропустить

   -- код функции

end


Если необходимо, чтобы функция что-то вернула, то используется return

function name_fun(param)

-- код функции

    return (значение)

end

 

Пример:

function hello()

   message("Hello!")

end


function square(numb)

    return numb^0.5

end

 
hello()

m = 25

b = square(m)

message("Квадратный корень из "..m.." = "..b)

 

Можно использовать с циклами:

function square(numb)

    return numb^0.5

end


for i=5, 25, 5 do

   b = square(i)

   message("Квадратный корень из "..i.." = "..b)

end
И с различными условиями:

function square(numb)

    return numb^0.5

end


for i=1, 625 do

  b = square(i)

  c, d = math.modf(b) -- выделяем целую и дробную часть

  if d ==0 then message("Квадратный корень из "..i.." = "..b) end -- если дробная часть =0 вывод на экран

end

Функция также может вернуть несколько значений (как в последнем примере возвращает целую и дробную часть числа math.modf), для этого нужно задать соответствующие переменные через запятую в return функции.

function mynumb(numb)

   return numb^2, numb^3

end

 

z = 2

x, y = mynumb(z)

message("Квадрат числа "..z.." равен "..x.." куб равен"..y)

К этому моменту мы прошли основу языка, с помощью которого можно решать типичные задачки по программированию или делать простые вычисления в терминале (для желающих погрузиться в большие детали, порекомендую классику по языку – книгу Роберту Иерузалимски «Программирование на языке Lua»: https://qlua.ru/help/lua-book/lua_3rd_rus.pdfс поправкой на то, что не всё из lua реализовано в терминале или это сделано с небольшими синтактическими изменениями).

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


Дата и время.

Получить системную дату и время можно с помощью функции os.sysdate()

Функция возвращает таблицу, из которой можно получить через ключи следующие значения:


ключ                    значение

mcs                     Микросекунды

ms                       Миллисекунды

sec                      Секунды

min                     Минуты

hour                    Часы

day                      День

week_day           Номер дня недели

month                 Месяц

year                     Год

 

b = os.sysdate()

message("Текущий год "..b['year']..", месяц "..b[' month ']..", день: "..b['day'])


Ключи можно указывать как в квадратных скобках, так и через точку, т
.е. запись b['month'] и b.month будут равнозначны.

Порой бывает полезным работать с переменными в виде ЧЧММСС, где ЧЧ – это часы, ММ – минуты, СС – секунды, чтобы компактнее ставить в скрипте различные ограничения по времени или чтобы использовать в названиях сохраняемых файлов и видеть точную время записи данных.

В этом случае будет полезным использовать дополнительные вставки с «0», на случай, если какая-то из составных частей меньше 10 (иначе вместо 140608 получится при слиянии данных 1468).

Пример:

tm = os.sysdate()

time_txt=""

if tm.hour < 10 then

  time_txt="0"..tm.hour

else

  time_txt=tm.hour

end

 

if tm.min < 10 then

  time_txt=time_txt.."0"..tm.min

else

  time_txt=time_txt..tm.min

end

 

if tm.sec < 10 then

  time_txt=time_txt.."0"..tm.sec

else

  time_txt=time_txt..tm.sec

end

message("Час: "..tm['hour'].." минуты: "..tm['min'].." секунды: "..tm['sec'])
message(time_txt)

На выходе получим:

Qlua: основы, часть 2
 

Аналогично можно обрабатывать даты, добавляя нули в те значения, что меньше 10.


getInfoParam 

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

 

VERSION                        Версия программы

TRADEDATE                    Дата торгов

SERVERTIME                   Время сервера

LASTRECORDTIME           Время последней записи

NUMRECORDS                 Число записей

LASTRECORD                  Последняя запись

LATERECORD                   Отставшая запись

CONNECTION                  Соединение

IPADDRESS                     IP-адрес сервера

IPPORT                            Порт сервера

IPCOMMENT                     Описание соединения

SERVER                           Описание сервера

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

USER                               Пользователь

USERID                            ID пользователя

ORG                                 Организация

MEMORY                           Занято памяти

LOCALTIME                       Текущее время

CONNECTIONTIME             Время на связи

MESSAGESSENT                Передано сообщений

ALLSENT                           Передано всего байт

BYTESSENT                       Передано полезных байт

BYTESPERSECSENT            Передано за секунду

MESSAGESRECV                Принято сообщений

BYTESRECV                       Принято полезных байт

ALLRECV                           Принято всего байт

BYTESPERSECRECV            Принято за секунду

AVGSENT                          Средняя скорость передачи

AVGRECV                          Средняя скорость приема

LASTPINGTIME                  Время последней проверки связи

LASTPINGDURATION          Задержка данных при обмене ссервером

AVGPINGDURATION           Средняя задержка данных

MAXPINGTIME                   Время максимальной задержки

MAXPINGDURATION           Максимальная задержка данных

 

Примеры:

vers = getInfoParam('VERSION')

org = getInfoParam('ORG')

ip = getInfoParam('IPADDRESS')

user = getInfoParam('USER')

message('Версия терминала: '..vers)

message('Компания: '..org)

message('IP адрес: '..ip)

message('Пользователь: '..user)


getInfoParamпозволяет в т.ч. получить время (через параметр SERVERTIME), но это будет время доставки последнего пакета данных с сервера и оно может расходиться с временем, полученным с помощью os.sysdate (будет запаздывать тем больше, чем дольше подвисает терминал).

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

 

Упражнения для закрепления (для желающих):

1. Выведите, используя циклы, в терминале таблицу умножения от 1 до 9.

2. Сделайте таблицу параметров getInfoParam и пройдите по данной функции циклом с выводом результатов каждого запроса.

3*. Напишите алгоритм, который выводит текущее время словами (например: четырнадцать часов тридцать пять минут)

 

 

Оглавление:

Введение

Настраиваем торговый терминал и редактор кода 

Основы qlua, часть 1    

 

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

★26
15 комментариев
Мож, проще Иерусалимского почитать — Lua и мануал от ARQA?
В инете все есть в свободном доступе.
avatar
3Qu, на Иерузалимски ссылка есть по тексту, но после неё только общая логика языка будет понятна, роботов для квика не напишешь. А мануал разработчиков терминала составлен так, что после прочтения у начинающих больше вопросов, чем понимания как это использовать.
avatar
Я думаю кто решился писать на луа уже знает, что такое циклы
avatar
StockChart.ru, вопрос именно синтаксиса. плюс, как это в примере с repeat until я указал в сети могут встречаться примеры старых версий, которые только подвесят терминал или просто не будут работать.
avatar
Как по мне разработка роботов на QLua не лучший вариант. Нормально только если есть готовая стратегия, и ее надо реализовать, и вы совсем ни очень в программировании. Довольно примитивный язык, практически нет нужных библиотек, намертво прибито к квику, разбросаны данные и управление в квике на два потока, нет бэктестов.
Есть QuikSharp(который реализован через QLua), и другие разные фрэймворки, даже бесплатные типа OsaEngine.
avatar
vlad1024, 
Довольно примитивный язык, практически нет нужных библиотек,
В Луа есть все, абсолютно любые библиотеки и сколько угодно потоков. Называется C-API.))
avatar
vlad1024, Да, согласен, много недостатков, к тому же сама арка не особо торопится их устранять или прикручивать что-то интересное. Но при этом он достаточно прост. Это как vba в excel: простые макросы и функции можно легко и быстро прописать, а уже какие-то масштабные расчеты и выгрузки лучше делать на других языках - будет в десятки и сотни раз быстрее. Также и здесь: сделать советника, индикатор, скрипт управления заявками, выгрузки данных, простой алгоритм торговый автоматизировать можно достаточно легко. А управлять десятками или сотнями стратегий уже либо через профессиональное ПО, либо в связке с другими языками.
avatar
alfacentavra, можно к вам обратиться за разработкой небольшого индикатора? (точнее мне график надо строить по данным получаемым из Quik).
Илья Нечаев, индикаторы будем рассматривать, но не в самое ближайшее время.

У разработчиков есть свой мануал по ним (можно скачать здесь, например: euvgub.github.io/QLUA_create_indicators/index.html?page=1) полистайте его. Плюс можно посмотреть примеры реализации встроенных в терминал индикаторов, оттолкнуться от этого (https://arqatech.com/upload/iblock/398/INDICATORS.zip).
Если не справитесь после этого напишите в личку. 

Квик топорно визуализирует (в отличие от многих других терминалов, за что, собственно в т.ч. его и не любят массы). Поэтому чаще из терминала просто тянут данные, а сама отрисовка проходит вне (например уже через python с добавлением любых удобных для этого библиотек).
avatar
Господа, разбудите, когда дойдете до раздела «Наносекундные транзакции»
Все, довольно таки, понятно. Спасибо за труды.
avatar
спасибо за материал. вот такая табличка умножения получилась


for b = 1, 10 do
local a = 0


repeat
a = a + 1
x = a * b
message(a.." * "..b.." = "..x)
until(a > 9)
end

avatar

теги блога alfacentavra

....все тэги



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