Блог им. morefinances
Продолжаем погружаться в основы языка. Сегодня рассмотрим:
Циклы 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(условие)
Выполняет условие цикла минимум один раз, если условие соблюдается запускается повторное выполнение тело цикла.
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 рандомно формирует порядок вывода.
Т.е. массив будет проитерирован весь, но, в отличие от работы с массивом по индексу (когда мы проходили обычным циклом с 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)
На выходе получим:
Аналогично можно обрабатывать даты, добавляя нули в те значения, что меньше 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 для начинающих, кружок авиамоделизма.
В инете все есть в свободном доступе.
Есть QuikSharp(который реализован через QLua), и другие разные фрэймворки, даже бесплатные типа OsaEngine.
У разработчиков есть свой мануал по ним (можно скачать здесь, например: euvgub.github.io/QLUA_create_indicators/index.html?page=1) полистайте его. Плюс можно посмотреть примеры реализации встроенных в терминал индикаторов, оттолкнуться от этого (https://arqatech.com/upload/iblock/398/INDICATORS.zip).
Если не справитесь после этого напишите в личку.
Квик топорно визуализирует (в отличие от многих других терминалов, за что, собственно в т.ч. его и не любят массы). Поэтому чаще из терминала просто тянут данные, а сама отрисовка проходит вне (например уже через python с добавлением любых удобных для этого библиотек).
for b = 1, 10 do
local a = 0
repeat
a = a + 1
x = a * b
message(a.." * "..b.." = "..x)
until(a > 9)
end