Учебник qlua: QLua основы | QUIKBOT . EVOLUTION …
QLua основы | QUIKBOT . EVOLUTION …
Чтобы скомпилировать(получить байт-код) Ваш скрипт, Вам понадобится файл luac.exe, находится в корневом каталоге Вашей LuaForWindows, если у Вас ее еще нет, то установите отсюда code.google.com
Затем, положите в папку с Вашим скриптом копию файла luac.exe, создайте в этой папке текстовый файл, добавьте в него строчку:luac.exe -o MyScript.luac MyScript.lua
«MyScript» замените на имя Вашего скрипта и сохраните этот файл под любым названием, главное с расширением .bat
Теперь выполните этот файл и в папке появится еще один файл с расширением .luac, перекиньте его куда-нибудь, поменяйте его расширение на .lua и запускайте в терминале как обычный скрипт.
Тот же результат можно получить программным путем:
1 2 3 | local f = io.open(FilePathLuac, 'wb') -- FilePathLuac по этому пути будет создан скомпилированный файл, например: "C:\\MyScript.lua" f:write(string.dump(loadfile(FilePathSrc))) -- FilePathSrc путь к Вашему исходному файлу .lua f:close() |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Файл CSV-формата это обычный текстовый файл, с которым Excel и аналогичные программы могут работать как с таблицей. Каждая строка таблицы в этом файле записывается как новая строка со знаком переноса в конце, а значения полей разделены между собой каким-то символом, чаще «;». В самой первой строке такого файла можно (не обязательно) указать названия столбцов, так же через «;».
Ниже приведен пример создания такого файла и записи в него данных о совершенных сделках средствами QLua(Lua):
Смотреть полностью…
Сейчас в QLua появилась встроенная функция bit.test, которая решает ту же задачу, т.е. смысла в использовании функции CheckBit больше нет !
true — флаг установлен
false — флаг не установлен
-- Функция проверяет установлен бит, или нет (возвращает true, или false) CheckBit = function(flags, _bit) -- Проверяет, что переданные аргументы являются числами if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!") end if type(_bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!") end if _bit == 0 then _bit = 0x1 elseif _bit == 1 then _bit = 0x2 elseif _bit == 2 then _bit = 0x4 elseif _bit == 3 then _bit = 0x8 elseif _bit == 4 then _bit = 0x10 elseif _bit == 5 then _bit = 0x20 elseif _bit == 6 then _bit = 0x40 elseif _bit == 7 then _bit = 0x80 elseif _bit == 8 then _bit = 0x100 elseif _bit == 9 then _bit = 0x200 elseif _bit == 10 then _bit = 0x400 elseif _bit == 11 then _bit = 0x800 elseif _bit == 12 then _bit = 0x1000 elseif _bit == 13 then _bit = 0x2000 elseif _bit == 14 then _bit = 0x4000 elseif _bit == 15 then _bit = 0x8000 elseif _bit == 16 then _bit = 0x10000 elseif _bit == 17 then _bit = 0x20000 elseif _bit == 18 then _bit = 0x40000 elseif _bit == 19 then _bit = 0x80000 elseif _bit == 20 then _bit = 0x100000 end if bit.band(flags,_bit ) == _bit then return true else return false end end |
Пример использования
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | Run = true; function main() -- ОСНОВНОЙ ЦИКЛ while Run do sleep(500); end; end; function OnOrder(order) --бит 0 (0x1) Заявка активна, иначе – не активна --бит 1 (0x2) Заявка снята. Если флаг не установлен и значение бита «0» равно «0», то заявка исполнена --бит 2 (0x4) Заявка на продажу, иначе – на покупку. Данный флаг для сделок и сделок для исполнения определяет направление сделки (BUY/SELL) --бит 3 (0x8) Заявка лимитированная, иначе – рыночная --бит 4 (0x10) Разрешить / запретить сделки по разным ценам --бит 5 (0x20) Исполнить заявку немедленно или снять (FILL OR KILL) --бит 6 (0x40) Заявка маркет-мейкера. Для адресных заявок – заявка отправлена контрагенту --бит 7 (0x80) Для адресных заявок – заявка получена от контрагента --бит 8 (0x100) Снять остаток --бит 9 (0x200) Айсберг-заявка -- Проверка бита 2 if CheckBit(order.flags, 2) then message("Заявка на продажу"); else message("Заявка на покупку"); end; end; function OnStop() Run = false; end; -- Функция проверяет установлен бит, или нет (возвращает true, или false) CheckBit = function(flags, _bit) -- Проверяет, что переданные аргументы являются числами if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!") end if type(_bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!") end if _bit == 0 then _bit = 0x1 elseif _bit == 1 then _bit = 0x2 elseif _bit == 2 then _bit = 0x4 elseif _bit == 3 then _bit = 0x8 elseif _bit == 4 then _bit = 0x10 elseif _bit == 5 then _bit = 0x20 elseif _bit == 6 then _bit = 0x40 elseif _bit == 7 then _bit = 0x80 elseif _bit == 8 then _bit = 0x100 elseif _bit == 9 then _bit = 0x200 elseif _bit == 10 then _bit = 0x400 elseif _bit == 11 then _bit = 0x800 elseif _bit == 12 then _bit = 0x1000 elseif _bit == 13 then _bit = 0x2000 elseif _bit == 14 then _bit = 0x4000 elseif _bit == 15 then _bit = 0x8000 elseif _bit == 16 then _bit = 0x10000 elseif _bit == 17 then _bit = 0x20000 elseif _bit == 18 then _bit = 0x40000 elseif _bit == 19 then _bit = 0x80000 elseif _bit == 20 then _bit = 0x100000 end if bit.band(flags,_bit ) == _bit then return true else return false end end |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | -- Флаг поддержания работы скрипта IsRun = true; function main() -- Пытается открыть файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); -- Если файл не существует if f == nil then -- Создает файл в режиме "записи" f = io.open(getScriptPath().."\\Test.txt","w"); -- Закрывает файл f:close(); -- Открывает уже существующий файл в режиме "чтения/записи" f = io.open(getScriptPath().."\\Test.txt","r+"); end; -- Записывает в файл 2 строки f:write("Line1\nLine2"); -- "\n" признак конца строки -- Сохраняет изменения в файле f:flush(); -- Встает в начало файла -- 1-ым параметром задается относительно чего будет смещение: "set" - начало, "cur" - текущая позиция, "end" - конец файла -- 2-ым параметром задается смещение f:seek("set",0); -- Перебирает строки файла, выводит их содержимое в сообщениях for line in f:lines() do message(tostring(line));end -- Закрывает файл f:close(); -- Цикл будет выполнятся, пока IsRun == true while IsRun do sleep(100); end; end; function OnStop() IsRun = false; end; |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Во время работы терминала QUIK в нем происходят различные события, такие, как приход новой обезличенной сделки, выставление заявки, сработал стоп-ордер и т.п. Для того, чтобы своевременно и определенным образом реагировать на эти события, в скрипте QLua можно использовать функции обратного вызова, которые будут выполнять блок кода, расположенного внутри них, в тот момент, когда это событие произойдет.
Для каждого определенного события есть своя предопределенная разработчиками QLua функция!Смотреть полностью…
isConnected() — возвращает 1, если QUIK подключен к серверу и 0, если не подключен
getScriptPath() — возвращает путь, по которому находится скрипт, без последнего обратного слэша («\»), например, «C:\Program Files (x86)\Info\MyLua»
getInfoParam() — возвращает значение параметра из окна:«Связь» -> «Информационное окно…»
Смотреть полностью…
Для приведения типов в QLua(Lua) служат всего 2 функции:
tostring() — принимает любой параметр и конвертирует его в строку в подходящем формате, для применения конкретного формата, используйте функцию string.format
tonumber() — пытается преобразовать переданный параметр в число, иначе возвращает nil
Стандартные арифметические операции:
«+» — сложение,
«-« — вычитание,
«/» — деление,
«*» — умножение,
«%» — остаток от деления (5%2 == 1).
math.abs (x) — Модуль x.
math.acos(x) — Возвращает арккосинус x
math.asin(x) — Возвращает арксинус x (в радианах).
math.atan(x) — Возвращает арктангенс x (в радианах).
math.atan2(x, y) — Возвращает арктангенс x/y (в радианах), но использует знаки обоих параметров для вычисления «четверти» на плоскости. (Также корректно обрабатывает случай когда y равен нулю.)Смотреть полностью…
Материал статьи взят здесь: http://www.bot4sale.ru/blog-menu/qlua/spisok-statej/368-lua-time.html
Дата/время в QLua(Lua) может быть представлено либо в виде секунд, прошедших с полуночи 1 января 1970 года, либо в виде таблицы, имеющей следующие поля:
year — год (четыре цифры)
month — месяц (1 – 12)
day — день (1 – 31)
hour — час (0 – 23)
min — минуты (0 – 59)
sec — секунды (0 – 59)
wday — день недели (1 — 7), воскресенью соответствует 1
yday — день года
isdst — флаг дневного времени суток, тип booleanСмотреть полностью…
Qlua для чайников. Часть 1
Многие хотели бы научиться писать биржевых роботов или хотя бы автоматизировать некоторые свои биржевые операции, но пугаются самого процесса программирования, считая его чем-то сложным. Эта статья написана для того, что бы помочь тем, кто только начинает программировать. Вы сами увидите, что на самом деле тут все просто.
Прежде чем приступить к уроку, хочу сказать пару слов о языке программирования qlua, который мы будем изучать. На сегодняшний день этот язык – самый удобный и доступный способ что-либо автоматизировать для начинающих программистов. Язык qlua гораздо лучше и удобнее его предшественника – qpile, он содержит больше возможностей, и роботов, написанных на нем, можно сделать гораздо боле гибкими. Что особо радует, так это, например, наличие так называемых CALLBACK функций (функций обратного вызова), благодаря которым появилась возможность легко писать роботов, реагирующих на разные события: изменение статуса заявки, приход сделки и т. д. (см. статью robostroy.ru/community/article.aspx?id=765).
Итак, начнем. Для начала мы просто возьмем и создадим программу, которая просто выведет на экран сообщение «Hello, World!». Очень многие начинали именно с этого. Вот текст этой очень и очень простой программы:
message(«Hello, World!»,1) |
Текст программы можно набрать в блокноте:
Но лучше, конечно, воспользоваться специализированной программой типа «Notepad++», там есть даже подсветка синтаксиса:
Обратите внимание, что сохранять файл нужно обязательно с расширением lua.
Итак, программа набрана, запускаем ее. Для этого идем в меню «Таблицы» -> «Lua» -> «Доступные скрипты».
У нас откроется вот такое окошко:
Жмем кнопочку добавить, выбираем там наш файл:
Он появился в списке доступных скриптов:
Выделяем его, жмем на кнопочку «Запустить» и видим результат:
Поздравляю, вы написали свою первую программу. Просто, не правда ли?
Но слышу разочарованные вздохи. Несмотря на просто изумительную простоту, наша программа абсолютно бесполезна. Ну что я могу сказать? Наберитесь терпения! Сейчас мы научится делать более сложные вещи.
Итак, давайте попробуем ввести заявку. Создаем новый скрипт (файл lua) вот с таким текстом:
t = { [«CLASSCODE»]=«TQBR», [«SECCODE»]=«LKOH», [«ACTION»]=«NEW_ORDER», [«ACCOUNT»]=«L01-00000F00», [«CLIENT_CODE»]=«52134», [«TYPE»]=«L», [«OPERATION»]=«B», [«QUANTITY»]=«1», [«PRICE»]=«1950», [«TRANS_ID»]=«1» } res=sendTransaction(t) message(res,1) |
Это программа чуть-чуть сложнее, поэтому я подробно сейчас разберу ее. Итак, сначала у нас идет строка t={…
t – это переменная. Она хранит в себе какое-то значение (число, строку, массив, таблицу, какой либо специальный объект или ничего не хранит, если ничего ей не присваиваем). В данном примере мы переменной t присваиваем целую структуру. У этой структуры есть поля. Они указываются в квадратных скобках, после них идет знак «=» и то, чему они равны. Такие пары перечисляются через запятую. Первое поле CLASSCODE. Это код класса. Его можно посмотреть, например, в текущей таблице параметров:
В нашем случае мы используем код класса акций ЛУКОЙЛ.
Саму текущую таблицу параметров можно открыть через меню «Таблица» -> «Текущая таблица».
В этой таблице необходимо настроить колонки, которые мы хотим видеть:
Следующее поле SECCODE – это код бумаги, в данном случае код ЛУКОЙЛа, так же смотрим его в текущей таблице параметров:
Поле ACTION – это действие, которое мы производим. В нашем случае это NEW_ORDER – новая заявка.
Поле ACCOUNT – это номер брокерского счета, можно посмотреть в таблице счетов, колонка «Счет»:
Эта таблица находиться в меню «Торговля» -> «Торговые счета»:
Далее идет поле CLIENT_CODE – это код клиента, можно посмотреть в таблице «Клиентский портфель»:
Открывается данная таблица через «Лимиты» -> «Клиентский портфель»:
Поле TYPE – тип заявки. «L» — лимитированная, «M» — рыночная.
OPERATION – тип операции, «B» если покупаем, «S» если продаем.
QUANTITY – количество, как правило, в лотах. Но у разных брокеров может быть по-разному (в лотах или в штуках акций).
PRICE – цена.
TRANS_ID – идентификатор транзакции. Иногда он бывает нужен, например, в случае, описанном в одной из моих предыдущих статей: http://robostroy.ru/community/article.aspx?id=765. Но чаще всего безразлично, что вы зададите в этом поле, например, можно просто поставить единичку.
После заполнения полей переменной t мы вызываем функцию sendTransaction, она вернет нам сообщение, которое мы выведем на экран функцией message, которую мы ранее использовали для вывода сообщения “Hello, World!”. Обратите внимание, что res идет без кавычек, это переменная, а не жестко заданный текст, как в предыдущем примере.
Итак, поставим в текст программы те параметры, которые правильные для вашего случая (номер счета, код клиента, параметры бумаги, цену и количество) и запускаем скрипт. Если все правильно, то вы увидите примерно такое сообщение:
Иначе может вылезти сообщение с ошибкой. Проверьте, действительно ли выставилась заявка.
И так, мы уже научились писать скрипт, выставляющий заявки. Но опять слышу разочарованные вздохи. По-прежнему мы не написали ни одной полезной программы. Ну что ж, для начала давайте напишем простенький скрипт, который выставит серию заявок на покупку и на продажу с шагом от заданной цены.
Полная версия саться на robostroy.ru
QLua
Тема сегодняшней публикации — скриптовый язык QLUA. QLUA — мощнейший инструмент для написания торговых роботов. И сегодня мы обсудим его плюсы и минусы. Посмотрим как написать простой индикатор и первого робота на нём. В начале своего пути долго выбирал среду разработки, искал эффективное и в тоже время простое решение для написания торговых роботов и советников. Этот путь занял несколько лет, и что я только не перепробовал в то время. Excel, Metastock, TsLab. Но в итоге остановился на QLua, справедливо решив, что это то, что мне нужно.
Оглавление
1) Почему стоит выбрать QLua.
2) Немного истории и о преимуществах QLua в сравнении с предшественником QPile.
3) Написание индикаторов на QLua.
4) Написание робота на QLua под Quik
5) Заключение
1. Почему стоит выбрать QLua.
Постараюсь коротенько описать плюсы и минусы. Начать стоит с того, что в рамках РФ самый распространенный терминал для торговли акциями и фьючерсами является Quik. Если отталкиваться от того, что наш терминал Quik, то выбор будет между: программами для тестирования, языками высокого уровня и встроенными языками в терминал Qlua , QPile.
Если сравнивать с системами, где алгоритм выстраивается путем построения блок-схем, то преимуществом Qlua является отсутствие платы за использование торговой системы как в TsLab и нет необходимости в использовании доп. «прокладок» как Wealth-lab. В системах построения из блоков таких как: TsLab, Wealth-lab и т.д. проблематично выстраивать сложные системы, а для уменьшения количества блоков и получения доп. функций требуется знание высокоуровневых языков типа: C#, Pascal для написания кубиков вручную.
Если рассматривать написание роботов на таких языках как: C#, Delphi , то здесь однозначным минусом является сложность написания кода и его размер для создания простейшего робота. Скриптовые же язык QLua или Qpile позволяют реализовать идею в более короткие сроки.
Сценарный язык (язык сценариев, жарг. скриптовый язык, от англ. scripting language) — высокоуровневый язык сценариев (англ. script) — кратких описаний действий, выполняемых системой. Сценарий — это программа, имеющая дело с готовыми программными компонентами, что очень сильно упрощает написание кода торгового робота. То есть для получения данных по значению закрытия свечи достаточно написать строчку кода типа: ds:C(20) все, и мы получаем значение закрытия двадцатой свечи инструмента. Нет необходимости писать «километры» кода. При этом доступен весь функционал как в полноценном языке программирования.
Из минусов можно отметить, что QLua используется только в рамках терминала Quik и данный язык не доступен для работы с другими терминалами и торговыми системами. Так же учитывая, что Quik является только терминалом и не позволяет производить тестирование торговых алгоритмов. В QLua нет простого решения для тестирования роботов, как это можно сделать в рамках таких платформ как: TsLab и Wealth-Lab.
2. Немного истории и о преимуществах QLua в сравнении с предшественником QPile.
До QLua был QPile, в общем–то он и сейчас есть. Интерпретатор скриптового языка QPile был разработан ARQA Technologies в 2002г. и развивался до 2012г., позже в терминал Quik был добавлен Lua интерпретатор. Так же есть вероятность, что компания ARQA Technologies возможно в ближайшем будущем откажется от дальнейшей поддержки QPile. Qpile как и Qlua является скриптовым языком и обладает рядом возможностей. По праву он является первым языком для написания роботов и советников для терминала Quik. Является простым для изучения и функциональным инструментом, но обладает рядом минусов.
И так, какими плюсами обладает QLua в сравнении с QPile:
— у QLua нет задержки на обработку торговой логики робота в 1сек. Это конечно не критично для среднесрочных стратегий, но для написания скальперских роботов может стать критичным.
— у QLua есть многопоточность. Реализовано это в виде основного потока торговой логики и функций обратного вызова(«колбэков»).
— есть возможность писать и подключать библиотеки на других языках, сам Lua кстати написан на Си
— появилась возможность писать пользовательские индикаторы и использовать их как стандартные.
— синтаксис языка немного похож на JavaScript и C#, отсюда удобство работы с операторами переменными и т.д.
— скрипты обычно интерпретируются, а не компилируются. QLua обладает JIT-компиляторами так как в его основе лежит язык Lua. Что позволяет прятать исходный код, в то время как у Qpile он всегда открыт. Ссылка как компилятор для скрытия исходного кода Qlua
3. Написание индикаторов на QLua.
(1) Пользовательский индикатор
Как уже упоменалось выше в рамках терминала Quik существует два скриптовых языка это: Qpile и QLua. Qpile являестя более ранним языком, который появился в Quik и на нем нельзя было писать индикаторы. Позже разработчики расширили функционал и добавили QLua, в рамках которого стало возможным писать индикаторы. В данной части статье пойдет речь о создании индикатора под Quik.
Индикатор на QLua представляет из себя файл с расширением *.lua или *.luac и визуально ничем не отличается от робота. Исключением является его месторасположение. Для того чтобы Quik увидел индикатор его надо разместить в папке LuaIndicators. Папка LuaIndicators должна храниться в корне папки Квика , если ее там нет , то ее надо создать. Для того чтобы быстро открыть папку Квика надо нажать на его ярлык на рабочем столе правой кнопкой мыши и выбрать «Расположение файла».
И так перейдем к созданию индикатора. Для этого нам понадобится любой текстовый редактор типа Notepade.
Индикатор на QLua для Quik состоит из трех основных частей.
Первая часть это объявление и заполнение глобального массива Settings , который содержит в себе переменные параметров индикатора, тип линии для отображения, толщину, цвет. В массиве Settings располагаются пользовательские переменные для изменения параметров индикатора из пользовательского интерфейса Квика.
Вторая часть это функция Init , она запускается один раз при инициализации индикатора. Возвращает количество линий индикатора.
Третья часть функция OnCalculate(index) получает на вход номер свечи. Она запускается интерпретатором столько раз сколько свечей на графике и возвращает численное значение индикатора. Если линий несколько в индикаторе , то несколько численных значений. Для удобства понимания кода там будут комментарии. Для комментирования строки в QLua используется «—». Все содержимое после двух дефисов интерпретатором кода на QLua не воспринимается.
--[[ Многострочные комментарии располагаются между символами двух дефисов и квадратных скобок ]]-- Settings= { Name = "Channel", -- название индикатора period=5, -- параметр индикатора line= { { Name = "High", Type =TYPE_LINE, Width = 1, Color = RGB(120,90, 140) }, { Name = "Low", Type =TYPE_LINE, Width = 1, Color = RGB(120,90,140) } } }
Здесь мы описали массив настроек, ввели название индикатора, параметры описали параметры двух линий индикатора Именно эти параметры будут доступны в пользовательском индикаторе для изменения при загрузке индикатора на Qlua в Quik
- (1)Название индикатора
- (2)Установка значения для переменной period
- (3)Установка цвета по умолчанию для линии High
- (4)Название линии индикатора , которое мы прописали в ячейке «line» нашего листа настроек
- (5)Тип линии который мы установили для использования по умолчанию Type =TYPE_LINE
- (6)Толщина линии индикатора Width = 1
function Init() return 2 end -- выводить на график будем две линии --[[ В функции OnCalculate мы рассчитаем индикатор Price Channel – это две линии построенные по экстремумам значений свечей за определенное количество баров. То есть первое значение, которое будем рассчитывать это максимальное значение за period в нашем случае он равен пяти, а второе значение, которое будет возвращать функция это минимальное значение за period. Итак приступим к расчету. ]]-- function OnCalculate(index) local high=0 local low=0 Period = math.floor(Settings.period) if index<=Period then high=H(index) low=L(index) for i=index , 1 , -1 do if H(i)>high then high=H(i) end if low>L(i) then low=L(i) end end else high=H(index) low=L(index) for i=index , (index+1)-Period , -1 do if H(i)>high then high=H(i) end if low>L(i) then low=L(i) end end end return high , low end
Создаем в редакторе файл с расширением lua записываем в него
код и сохраняем его в папке LuaIndicators , после этого у нас появится новый
индикатор и его можно будет добавить к себе на график как стандартный индикатор
Quik (1)
Ссылка для скачивания исходного кода индикатора на QLua
4. Написание робота на QLua под Quik
Написание торгового робота на QLua ведется в обычном текстовом редакторе, так же как и для написания индикатора. Отличие будет в структуре кода и в том, что располагать робот можно в любом удобном для вас месте на компьютере. В роботе является обязательной только одна функция main.
И так приступим. Напишем робота с простым алгоритмом. Рассчитаем внутри робота скользящую среднюю и будем принимать решение о покупке/продаже одного лота по инструменту исходя из количества в клиентском портфеле при закрытии прошлого бара ниже/выше среднего значения посчитанного по закрытию минутных баров инструмента. То есть при пересечении close бара средней снизу вверх проверим количество контрактов в портфеле по инструменту, и если оно меньше одного , то докупим разницу до одного контракта в лонг. Обратная ситуация при пересечении close закрытого бара среднего значения сверху вниз. Отправим транзакцию для получения одного лота в шорт по клиентскому портфелю.
-- переменная для прырывания цикла при срабатывании функции обратного вызова OnStop is_run = true -- присванивание переменным начальных базовых значений торгового алгоритма Account = "NL0011100043" -- торговый счет Class_Code = "QJSIM" -- класс торгуемого инструмента Sec_Code = "SBER" -- код торгуемого инструмента TF = INTERVAL_M1 -- торговый таймфрейм g_lots = 1 -- количество торгуемых лот function main() -- подписываемся на получение данных свечей по инструменту в массив ds ds = CreateDataSource(Class_Code, Sec_Code, TF) while is_run do sleep(1000) -- обрабатываем цикл с задержкой 1сек. ds:SetEmptyCallback() -- обновляем данные по инструменту в массиве ds local serv_time=tonumber(timeformat(getInfoParam("SERVERTIME"))) -- помещене в переменную времени сервера в формате HHMMSS if isConnected()==1 and serv_time>=10000 and serv_time<235000 then -- проверка наличия соеденения с сервером и поподания в торговое окно -- место для размещения торговой логики -- расчет значения скользящей средней local SMA = 0 local period = 20 local count_candle = ds:size() if count_candle>20 then local sum = 0 for i=0 , period-1 do sum = sum + ds:C(count_candle-i) end SMA = sum / period local lots = get_lots() -- получение количества лот в клиентском портфеле по инструменту if ds:C(count_candle)>SMA and lots<g_lots then -- получение минимального шага цены для организации величины проскальзываня в ордере local step=tonumber(getParamEx(Class_Code, Sec_Code, "SEC_PRICE_STEP").param_value) local price_order = ds:C(count_candle)+(step*20) -- цена для ордера будет = цена закрытия + 20-ть минимальных шагов инст. send_order("B", math.abs(g_lots-lots) , price_order) end if ds:C(count_candle)<SMA and lots>(g_lots*(-1)) then -- получение минимального шага цены для организации величины проскальзываня в ордере local step=tonumber(getParamEx(Class_Code, Sec_Code, "SEC_PRICE_STEP").param_value) local price_order = ds:C(count_candle)-(step*20) -- цена для ордера будет = цена закрытия - 20-ть минимальных шагов инст. send_order("S", math.abs(g_lots+lots) , price_order) end end end end end -- функция возвращает количество лот в клиентском портфеле по заданному инструменту function get_lots() local lots = 0 local n = getNumberOf("futures_client_holding") local futures_client_holding={} for i=0,n-1 do futures_client_holding = getItem("futures_client_holding", i) if tostring(futures_client_holding["sec_code"])==Sec_Code then lots=tonumber(futures_client_holding["totalnet"]) end end return lots end ---------------------- -- отправка транзакции function send_order(operation, quantity, price) -- получение минимального шага цены для округления цены отправляемого ордера local step=tonumber(getParamEx(Class_Code, Sec_Code, "SEC_PRICE_STEP").param_value) local trans_params = { CLIENT_CODE = Account, CLASSCODE = Class_Code, SECCODE = Sec_Code, ACCOUNT = Account, TYPE = "L", TRANS_ID = tostring(1), OPERATION = tostring(operation), QUANTITY = tostring(math.abs(quantity)), PRICE = tostring(math.floor(tonumber(price)/step)*step), -- округление цены при отправлении транзакции ACTION = "NEW_ORDER" } local res = sendTransaction(trans_params) if string.len(res) ~= 0 then message('Error: '..res,3) return 0 else return trans_id end end function OnStop(stop_flag) is_run=false stop_flag=1 ds:Close() end function timeformat(time_unf) local in1, in2=0,0 local time_form=0 in1=string.find(time_unf,":" , 0) if in1~=nil and in1~=0 then in2=string.find(time_unf,":" , in1+1) time_form=string.sub(time_unf, 0 ,in1-1)..string.sub(time_unf, in1+1 ,in2-1)..string.sub(time_unf, in2+1 ,string.len(time_unf)) end return time_form end
После редактирования кода сохраняем его в удобном для вас
месте с расширением lua. Для запуска робота надо зайти в Сервисы ->Lua
скрипты
- (1)Добавляем скрипт из сохраненнго места
- (2)Проверяем его появление в таблице запущенных скриптов, после запуска появится зеленая стрелка индицирующая работу скрипта
- (3)Запускаем его в работу
- (4)Проверяем в поле отсутствие ошибок при работе
Ссылка для скачивания исходного кода робота на QLua
5. Заключение
Подводя итоги хочется сказать, что если используется для торговли терминал Quik, то одним из самых простых способов написания автоматизированных торговых систем является скриптовый язык QLua. И надеюсь, сегодня Вы в этом сами убедились.
В рамках торгового робота написанного как пример выше, мы получили готовую механическую торговую систему в сто строк кода. Что является очень хорошим результатом.
Для написания индикаторов в Квик, Qlua является единственно возможным вариантом.
В общем — торгуйте алгоритмами. Используйте хорошие технологии!
Введение в QUIK (Квик) и LUA | K
В этой части мы будем с вами говорить о таком направлении как программирование на языке QLUA. Что же это за язык такой? — Обыкновенный язык программирования, каких существует множество, но с небольшой оговоркой. Вообще говоря существует язык программирования LUA, а первая буква Q в названии, говорит нам о том, что мы применяем данный язык программирования в платформе QUIK (Квик). Ещё этот язык иногда называют QuikLua, что в принципе тоже верно. Ну да ладно, как бы его не называли суть остается неизменной.
Если вы начинаете с самого начала и ещё ни разу не слышали о том как писать индикаторы или скрипты в платформе QUIK, то этот сайт как раз то что вам нужно.
Рекомендую добавить сайт в закладки, так как он вам ещё не один раз пригодится, будет для вас настольной книгой, справочником, где вы всегда сможете найти ответ на свой вопрос
Итак начнем пожалуй с самого главного вопроса который сейчас перед вами стоит это — С чего же начать? Когда-то я сам столкнулся с этим вопросом и перекопал огромное количество информации прежде чем разобрался что это такое и как тут всё устроено. Вам же я предлагаю пройти путь намного короче, так как вся информация будет излагаться последовательно и находиться на одном сайте, как раз на том на котором вы сейчас и находитесь, с чем я вас и поздравляю.
Ну что же, поехали. QUIK это платформа в которой нам позволяют писать на языке программирования lua, а конкретнее мы можем писать индикаторы и скрипты, чем они друг от друга отличаются мы поговорим позже, а сейчас займемся ответом на вопрос где мы будем писать наши собственные индикаторы или скрипты.
Где писать код?
Индикатор или скрипт это обыкновенный текстовый документ который имеет специальное расширение. Поэтому писать мы можем используя любой текстовый редактор, даже самый простой блокнот встроенный в операционную систему Windows. Открываем блокнот, пишем необходимый код сохраняем и всё наш индикатор или скрипт готов, можем использовать его в платформе QUIK, всё просто. Просто, да неудобно. Вы видели как выглядит текст в блокноте? Сплошной черный текст на белом фоне, писать можно, читать тоже можно, но программировать просто ужасно трудно. Поэтому я вам предлагаю использовать расширенную версию блокнота, называется эта программа notepad++. Я никоим образом ни кого не заставляю использовать именно ее, можете использовать любую другую программу. Я же предпочитаю пользоваться именно notepad++.
Если Вы решили как и я использовать для написания кода программу notepad++, то рекомендую перейти в раздел «QLUA (Квик) -> Рабочее Место» изучить все статьи начиниая с первой «Редактор кода notepad++» и настроить свое рабочее место.
Индикатор или скрипт? Что выбрать?
Теперь ответим на второй главный вопрос — Что мы будем писать? Выбор у нас конечно невелик, либо это будет индикатор, либо это будет скрипт. Настало время разобраться чем же отличается скрипт от индикатора. Для простоты понимания и чтобы не загружать вас огромным количеством всякой разной информации на начальном этапе, определимся со следующим. Если то что мы задумали сделать, необходимо отображать на графике, в этом случае выбираем для написания индикатор. В остальных случаях можно выбирать скрипт. Конечно же это очень грубое разграничение, но для начала будет достаточным. Когда вы в процессе изучения получите больше информации, что пишется в индикаторах, а что пишется в скриптах, вы сможете сами определить где вам лучше реализовать то что вы задумали.
в заключении
Это небольшая глава была посвящена введению в lua. Мы не затронули ни грамма кода, но зато мы ответили на главные вопросы где писать и что писать, а также подготовили рабочее место. Если вы действительно выполнили всё что тут написано, а не просто пролистали страницу сверху вниз, уверяю вас, вы сделали большой первый шаг, вам это очень поможет в будущем при освоении языка программирования lua. Вы только что сохранили как минимум пару часов своего драгоценного времени, которое бы потратили на поиски всей информации в интернете на различных сайтах.
Если у вас всё готово, а главное вы сами готовы, то переходим к следующему шагу.
QUIK + QLua | QUIKBOT . EVOLUTION …
Функции сохранения и загрузки параметров с примером использования
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | function main() local FPath = getScriptPath()..'//.params' -- Создание таблицы для примера local Params = {} Params.a = 10 Params.b = 'qwerty' Params.c = true Params.d = {} Params.d[1] = 100 Params.d[2] = 'asdfg' Params.d[3] = false Params.d[4] = { ['a'] = 10, ['b'] = 'qwerty', ['c'] = true } -- Сохраняет таблицу в файл SaveTable(Params, FPath) -- Загружает таблицу из файла local NewParams = LoadTable(FPath) if NewParams ~= nil then message(NewParams.d[4].b) end -- выведет "qwerty" end -- Сохраняет таблицу в файл SaveTable = function(Table, FilePath) local Lines = {} local level = 0 function Rec(a) local first = true level = level + 1 local s = '' for i=1,level do s = ' '..s end for key, val in pairs(a) do if not first then Lines[#Lines] = Lines[#Lines]..',' end local k = '[\''..key..'\']' if type(key) == 'number' then k = '['..key..']' end if type(val) ~= 'table' then if type(val) == 'string' then val = '\''..val..'\'' else val = tostring(val) end table.insert(Lines, s..k..'='..val) first = false else table.insert(Lines, s..k..'={') first = false Rec(val) table.insert(Lines, s..'}') level = level - 1 end end end table.insert(Lines, 'local a = {') Rec(Table) table.insert(Lines, '}') table.insert(Lines, 'return a') local f = io.open(FilePath, 'w') for i=1,#Lines do f:write(Lines[i]..'\n') f:flush() end f:close() end -- Загружает таблицу из файла LoadTable = function(FilePath) local func, err = loadfile(FilePath) if not func then message('Ошибка загрузки таблицы из файла: '..err) return nil else return func() end end |
Данный пример создаст файл «.params» (можно открыть Блокнотом, это обычный текстовый файл, можете назвать его как угодно) со следующим содержимым:
local a = { ['a']=10, ['d']={ [1]=100, [2]='asdfg', [3]=false, [4]={ ['a']=10, ['c']=true, ['b']='qwerty' } }, ['c']=true, ['b']='qwerty' } return a
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Данный движок не предоставляет полный функционал для разработки скриптов на QLua(Lua), но показывает на сколько проще и эффективней становится разработка при таком подходе.
В примере движка реализован следующий функционал:Смотреть полностью…
Блок кода QLua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | -- ПРОВЕРКА ВЫСТАВЛЕНИЯ ЗАЯВКИ ПО ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ -- для примера отправляется транзакция на выставление лимитированной заявки на покупку по определенной цене ACCOUNT = "SPBFUT00k59" -- Код счета CLASS_CODE = "SPBFUT" -- Код класса SEC_CODE = "RIH6" -- Код инструмента OpenPrice = 73000 -- Цена выставления заявки run = true -- Флаг работы цикла while в функции main trans_id = os.time() -- Текущие дата и время в секундах хорошо подходят для уникальных номеров транзакций LastStatus = nil -- Последний статус транзакции, который был выведен в сообщении -- Основная функция скрипта, пока работает эта функция, работает скрипт function main() -- Отправляет транзакцию на открытие позиции TransOpenPos() -- Пока работает данный цикл, работает скрипт while run do sleep(1) end end -- Срабатывает при остановке скрипта function OnStop() run = false end -- Отправляет транзакцию на открытие позиции function TransOpenPos() -- Выставляет заявку на открытие позиции -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local Transaction={ ['TRANS_ID'] = tostring(trans_id), -- Номер транзакции ['ACCOUNT'] = ACCOUNT, -- Код счета ['CLASSCODE'] = CLASS_CODE, -- Код класса ['SECCODE'] = SEC_CODE, -- Код инструмента ['ACTION'] = 'NEW_ORDER', -- Тип транзакции ('NEW_ORDER' - новая заявка) ['OPERATION'] = 'B', -- Операция ('B' - buy, или 'S' - sell) ['TYPE'] = 'L', -- Тип ('L' - лимитированная, 'M' - рыночная) ['QUANTITY'] = '1', -- Количество ['PRICE'] = tostring(OpenPrice) -- Цена } -- Отправляет транзакцию local Res = sendTransaction(Transaction) if Res ~= '' then message('TransOpenPos(): Ошибка отправки транзакции: '..Res) else message('TransOpenPos(): Транзакция отправлена') end end -- Функция вызывается терминалом, когда с сервера приходит новая информация о транзакциях function OnTransReply(trans_reply) -- Если пришла информация по нашей транзакции if trans_reply.trans_id == trans_id then -- Если данный статус уже был обработан, выходит из функции, иначе запоминает статус, чтобы не обрабатывать его повторно if trans_reply.status == LastStatus then return else LastStatus = trans_reply.status end -- Выводит в сообщении статусы выполнения транзакции if trans_reply.status < 2 then -- Статусы меньше 2 являются промежуточными (0 - транзакция отправлена серверу, 1 - транзакция получена на сервер QUIK от клиента), -- при появлении такого статуса делать ничего не нужно, а ждать появления значащего статуса -- Выходит из функции return elseif trans_reply.status == 3 then -- транзакция выполнена message('OnTransReply(): По транзакции №'..trans_reply.trans_id..' УСПЕШНО ВЫСТАВЛЕНА заявка №'..trans_reply.order_num..' по цене '..trans_reply.price..' объемом '..trans_reply.quantity) elseif trans_reply.status > 3 then -- произошла ошибка message('OnTransReply(): ОШИБКА выставления заявки по транзакции №'..trans_reply.trans_id..', текст ошибки: '..trans_reply.result_msg) end end end |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Эта статья начинает серию статей с примерами блоков кода, которые применяются при написании скриптов на QLua(Lua), каждый блок выполняет свою определенную задачу.
С каждой новой статьей блок кода будет усложняться своей функциональностью.
Эти блоки удобно брать и вставлять в свои скрипты, где нужно решить задачу, реализованную в блоке.
Блок кода QLua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | -- ПОЛУЧЕНИЕ РЕЗУЛЬТАТОВ ВЫПОЛНЕНИЯ ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ -- для примера отправляется транзакция на выставление лимитированной заявки на покупку по определенной цене ACCOUNT = "SPBFUT00k59" -- Код счета CLASS_CODE = "SPBFUT" -- Код класса SEC_CODE = "RIH6" -- Код инструмента OpenPrice = 73000 -- Цена выставления заявки run = true -- Флаг работы цикла while в функции main trans_id = os.time() -- Текущие дата и время в секундах хорошо подходят для уникальных номеров транзакций LastStatus = nil -- Последний статус транзакции, который был выведен в сообщении -- Основная функция скрипта, пока работает эта функция, работает скрипт function main() -- Отправляет транзакцию на открытие позиции TransOpenPos() -- Пока работает данный цикл, работает скрипт while run do sleep(1) end end -- Срабатывает при остановке скрипта function OnStop() run = false end -- Отправляет транзакцию на открытие позиции function TransOpenPos() -- Выставляет заявку на открытие позиции -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local Transaction={ ['TRANS_ID'] = tostring(trans_id), -- Номер транзакции ['ACCOUNT'] = ACCOUNT, -- Код счета ['CLASSCODE'] = CLASS_CODE, -- Код класса ['SECCODE'] = SEC_CODE, -- Код инструмента ['ACTION'] = 'NEW_ORDER', -- Тип транзакции ('NEW_ORDER' - новая заявка) ['OPERATION'] = 'B', -- Операция ('B' - buy, или 'S' - sell) ['TYPE'] = 'L', -- Тип ('L' - лимитированная, 'M' - рыночная) ['QUANTITY'] = '1', -- Количество ['PRICE'] = tostring(OpenPrice) -- Цена } -- Отправляет транзакцию local Res = sendTransaction(Transaction) if Res ~= '' then message('TransOpenPos(): Ошибка отправки транзакции: '..Res) else message('TransOpenPos(): Транзакция отправлена') end end -- Функция вызывается терминалом, когда с сервера приходит новая информация о транзакциях function OnTransReply(trans_reply) -- Если пришла информация по нашей транзакции if trans_reply.trans_id == trans_id then -- Если данный статус уже был обработан, выходит из функции, иначе запоминает статус, чтобы не обрабатывать его повторно if trans_reply.status == LastStatus then return else LastStatus = trans_reply.status end -- Выводит в сообщении статусы выполнения транзакции if trans_reply.status == 0 then message('OnTransReply(): Транзакция отправлена серверу') elseif trans_reply.status == 1 then message('OnTransReply(): Транзакция получена на сервер QUIK от клиента') elseif trans_reply.status == 2 then message('OnTransReply(): Ошибка при передаче транзакции в торговую систему. Так как отсутствует подключение шлюза Московской Биржи, повторно транзакция не отправляется') elseif trans_reply.status == 3 then message('OnTransReply(): ТРАНЗАКЦИЯ ВЫПОЛНЕНА !!!') elseif trans_reply.status == 4 then message('OnTransReply(): Транзакция не выполнена торговой системой. Более подробное описание ошибки отображается в поле «Сообщение» (trans_reply.result_msg)') elseif trans_reply.status == 5 then message('OnTransReply(): Транзакция не прошла проверку сервера QUIK по каким-либо критериям. Например, проверку на наличие прав у пользователя на отправку транзакции данного типа') elseif trans_reply.status == 6 then message('OnTransReply(): Транзакция не прошла проверку лимитов сервера QUIK') elseif trans_reply.status == 10 then message('OnTransReply(): Транзакция не поддерживается торговой системой') elseif trans_reply.status == 11 then message('OnTransReply(): Транзакция не прошла проверку правильности электронной цифровой подписи') elseif trans_reply.status == 12 then message('OnTransReply(): Не удалось дождаться ответа на транзакцию, т.к. истек таймаут ожидания. Может возникнуть при подаче транзакций из QPILE') elseif trans_reply.status == 13 then message('OnTransReply(): Транзакция отвергнута, так как ее выполнение могло привести к кросс-сделке (т.е. сделке с тем же самым клиентским счетом)') end end end |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Чтобы получить доступ к графику(не индикатору) какого-либо инструмента нужно создать источник данных при помощи функции CreateDataSource().
ВАЖНО!!! Для получения новых данных, кроме тех, что уже есть в открытом графике на текущий момент (тем более, если он не открыт), требуется использовать одну из следующих функций: SetUpdateCallback(), или SetEmptyCallback(), о которых будет написано ниже.
Описание функции CreateDataSource()
-- Функция предназначена для создания таблицы Lua и позволяет работать со свечами, полученными с сервера QUIK, а также реагировать на их изменение. ds, Error = CreateDataSource (class_code, sec_code, interval [, param]); -- Параметры: -- class_code - (STRING) код класса, например "SPBFUT" -- sec_code - (STRING) код бумаги, например "RIZ5" -- interval - (NUMBER) константа, обозначающая тайм-фрейм графика, например INTERVAL_M5 (полный список: https://quikluacsharp.ru/qlua-osnovy/spisok-konstant-tajm-frejmov-grafikov/) -- param - (STRING) необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы всех сделок, если задан – данные по этому параметру, например "BID" (возможные параметры смотрите ниже) -- Возвращаемые значения: -- ds - (TABLE) таблица с данными по свечам графика -- Error - (STRING) строка ошибки в случае неудачной попытки получить доступ к данным (тогда ds будет nil) -- Если график, к которому нужно подключиться не открыт в терминале, то данные заказываются с сервера, на их получение нужно время, -- по этому, рекомендуется добавлять вот такое ожидание, прежде, чем обращаться к ds: -- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт) while (Error == "" or Error == nil) and ds:Size() == 0 do sleep(1) end if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) end -- Примеры (одновременно можно подключаться к нескольким источникам данных): ds1 = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "last"); ds2 = CreateDataSource("QJSIM", "SBER", INTERVAL_M1); ds3, Error = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "bid"); if ds3 == nil then message('Ошибка подключения: '..Error); end; |
Смотреть полностью…
Скрипт позволяет открывать и закрывать позиции следующего типа:
— покупается 2, выбранных при помощи кнопок, колл-опциона на фьючерс на индекс РТС,
— продается 1, выбранный при помощи кнопок, фьючерс на индекс РТС.
Когда есть открытая данным скриптом позиция, в таблице отображается информация о ней (профит, баланс, ср.цена, дата открытия).
Профит вычисляется по формуле: «Текущая цена, по которой можно закрыть позицию» — «Цена открытия позиции» — «Комиссия 8 р. на каждый лот».
Так же, выполняется запись в лог-файл («Log.txt») выполняемых скриптом операций и в файле состояния («State.txt») хранится информация о текущих выбранных инструментах и о текущей, открытой скриптом позиции.Смотреть полностью…
Для получения данных из таблиц терминала QUIK удобно пользоваться 3-мя функциями: getItem(), getNumberOf() и getParamEx().
Пример:
-- Перебирает строки таблицы "Позиции по клиентским счетам (фьючерсы)", ищет Текущие чистые позиции по инструменту "RIH5" for i = 0,getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do -- ЕСЛИ строка по нужному инструменту И чистая позиция не равна нулю ТО if getItem("FUTURES_CLIENT_HOLDING",i).sec_code == "RIH5" and getItem("FUTURES_CLIENT_HOLDING",i).totalnet ~= 0 then -- ЕСЛИ текущая чистая позиция > 0, ТО открыта длинная позиция (BUY) if getItem("FUTURES_CLIENT_HOLDING",i).totalnet > 0 then IsBuy = true; BuyVol = getItem("FUTURES_CLIENT_HOLDING",i).totalnet; -- Количество лотов в позиции BUY else -- ИНАЧЕ открыта короткая позиция (SELL) IsSell = true; SellVol = math.abs(getItem("FUTURES_CLIENT_HOLDING",i).totalnet); -- Количество лотов в позиции SELL end; end; end; |
Далее перечислены таблицы, их идентификаторы и поля, к которым можно обращаться:Смотреть полностью…
Для получения стакана в QLua(Lua) служит функция обратного вызова OnQuote(). Эта функция вызывается терминалом QUIK при получении изменения стакана котировок. Для получения данных самого стакана служит функция getQuoteLevel2().
В терминале должен быть открыт стакан по нужному инструменту!!!
Пример:Смотреть полностью…
Основы КВИК (QUIK) и языка QLUA
28 августа 2019 Дмитрий Высоцкий Главная страница » Блог Просмотров:
В данной статье начнем рассматривать такую интересную тему как написание скриптов на языке программирования QLUA. Существует язык программирования LUA, а если в названии указан символ Q, то значит, этот язык относится к торговому терминалу QUIK. Пользователи еще говорят, что это Квик_Луа (QUIK LUA). Но суть остается одна, это встроенный язык программирования для КВИК.
Если вы только начинаете изучение разных платформ и языков программирования для написания скриптов для них, торговых роботов или индикаторов, то Вам должно быть интересно узнать подробнее о языке QLUA.
Приступим с самого интересного момента, а с чего надо начать все это осваивать? Все сталкиваются с таким вопросом и начинают копать тонну информации по разным источникам, чтобы разобраться что же это такое и из чего все состоит. Мы же Вам попытаемся немного помочь и ускорить процесс ознакомления с QLUA.
На языке LUA можно запрограммировать скрипты для торговли в терминале КВИК, все возможные индикаторы и торговые роботы, это все понятно, но как и где это делать, в каком редакторе необходимо все это программировать?
Где будем создавать код LUA?
Все скрипты или индикаторы, написанные на LUA представляют собой простой текстовый файл, просто имеет другое специальное расширение. Из этого становится ясно, что написать индикатор/скрипт возможно даже в простом текстовом редакторе, например в программе Блокнот, что есть у всех по умолчанию в Виндоуз. Запускаем текстовый редактор, пишем в нем код скрипта, далее сохраняем файл. Вот в принципе и все, наш скрипт для применения в торговой платформе КВИК готов. Как видите, оказывается очень просто. Да, все просто, но не очень удобно, т.к. текст в блокноте не имеет никакого обозначения, просто сплошной текст без разделений, если вы программировали, то поймете о чем речь идет. Именно поэтому обычно программисты используют подобие блокнота — это программа Notepad++. Повторюсь, что можно код писать в любом редакторе, но, на наш взгляд, программа Notepad++ очень удобна для программировании на LUA. В Notepad++ есть подсветка синтаксиса Lua и это очень большое преимущество в удобстве написания Lua кода.
Что лучше создать Скрипт или Индикатор?
И вот, когда мы поняли, где мы будем создавать наши творения для терминала КВИК, у нас возникает еще один вопрос, а что лучше написать Скрипт или может Индикатор?! Да, выбирать особо не приходится, но необходимо четко понимать в чем отличия между скриптом и индикатором. Тут можно не вдаваться в глубокие подробности структуры того и другого, а можно рассуждать как простой пользователь, если нужно просто видеть нужную информацию на графике в виде линий, точек и прочих обозначений, то значит нужен Индикатора. Если, что-то другое нужно, то значит скрипт. Да, это очень поверхностные различия, но для общего понимания хватит! Далее, когда вы углубитесь в данную тему и начнете понимать из чего состоит структура скрипта, а из чего структура индикатора, то сами легко сможете понять, что нужно сделать, чтобы осуществить задуманную идею.
Заключение
Мы начали с малого, подготовились к написанию кода на LUA и разобрались, что писать код будем в текстовом редакторе Notepad+, а также знаем, что нам выбрать для реализации индикатор или скрипт. Да, пока не коснулись самого кода LUA и структуры, но постараемся сделать цикл статей, чтобы это все постепенно разобрать и понять. Это был Первый и очень важный шаг к изучению языка QLUA. А тем самым даже на этой стадии мы помогли сэкономить Вам немного немало несколько часов рабочего времени!
Продолжение следует, следите за серией статей по языку программирования QLUA для торгового терминала КВИК.
Вы уже сейчас можете записаться на Видео курс и научиться самому делать зарабатывающих торговых роботов!
Можно записаться на следующий поток ОнЛайн курса, информацию по которому можно посмотреть тут:
Если же вам не хочется тратить время на обучение, то вы просто можете выбрать уже готовые роботы из тех, что представлены у нас!
Также можете посмотреть совершенно бесплатные наработки для МТ4, Квика, МТ5. Данный раздел также постоянно пополняется.
Не откладывайте свой шанс заработать на бирже уже сегодня!
Читайте также:
Получение в QLua(Lua) данных из графиков и индикаторов
Чтобы получить доступ к графику(не индикатору) какого-либо инструмента нужно создать источник данных при помощи функции CreateDataSource().
ВАЖНО!!! Для получения новых данных, кроме тех, что уже есть в открытом графике на текущий момент (тем более, если он не открыт), требуется использовать одну из следующих функций: SetUpdateCallback(), или SetEmptyCallback(), о которых будет написано ниже.
Описание функции CreateDataSource()
-- Функция предназначена для создания таблицы Lua и позволяет работать со свечами, полученными с сервера QUIK, а также реагировать на их изменение. ds, Error = CreateDataSource (class_code, sec_code, interval [, param]); -- Параметры: -- class_code - (STRING) код класса, например "SPBFUT" -- sec_code - (STRING) код бумаги, например "RIZ5" -- interval - (NUMBER) константа, обозначающая тайм-фрейм графика, например INTERVAL_M5 (полный список: https://quikluacsharp.ru/qlua-osnovy/spisok-konstant-tajm-frejmov-grafikov/) -- param - (STRING) необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы всех сделок, если задан – данные по этому параметру, например "BID" (возможные параметры смотрите ниже) -- Возвращаемые значения: -- ds - (TABLE) таблица с данными по свечам графика -- Error - (STRING) строка ошибки в случае неудачной попытки получить доступ к данным (тогда ds будет nil) -- Если график, к которому нужно подключиться не открыт в терминале, то данные заказываются с сервера, на их получение нужно время, -- по этому, рекомендуется добавлять вот такое ожидание, прежде, чем обращаться к ds: -- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт) while (Error == "" or Error == nil) and ds:Size() == 0 do sleep(1) end if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) end -- Примеры (одновременно можно подключаться к нескольким источникам данных): ds1 = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "last"); ds2 = CreateDataSource("QJSIM", "SBER", INTERVAL_M1); ds3, Error = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "bid"); if ds3 == nil then message('Ошибка подключения: '..Error); end; |
Функция CreateDataSource возвращает таблицу QLua с параметрами, получать значения которых можно следующим образом:
local O = ds:O(i); -- Получить значение Open для указанной свечи (цена открытия свечи) local H = ds:H(i); -- Получить значение High для указанной свечи (наибольшая цена свечи) local L = ds:L(i); -- Получить значение Low для указанной свечи (наименьшая цена свечи) local C = ds:C(i); -- Получить значение Close для указанной свечи (цена закрытия свечи) local V = ds:V(i); -- Получить значение Volume для указанной свечи (объем сделок в свече) local T = ds:T(i); -- Получить значение Time для указанной свечи (время открытия свечи (таблица datetime)) -- Где i - индекс свечи (от 1 до ds:Size()) local Size = ds:Size(); -- Возвращает текущий размер (количество свечей в источнике данных) ds:Close(); -- Удаляет источник данных, отписывается от получения данных ds:SetUpdateCallback(MyFuncName); -- Позволяет задать пользователю функцию обратного вызова для обработки изменившихся свечей, т.е. когда по выбранному в CreateDataSource параметру в терминал поступит новое значение (возможно такое же), автоматически будет вызвана данная функция, в которую будут передан индекс последней свечи графика, а так же добавятся новые данные в таблицу ds -- Пример функции: function MyFuncName(index) message('На '..index..'-й свече объем вырос до '..ds:V(index)); end; -- Чтобы получать новые данные без использования функции обратного вызова, а просто получать новые данные в ds и брать их оттуда по необходимости существует функция: ds:SetEmptyCallback(); -- Которая подписывается на получение новых данных |
Списки возможных параметров, используемых в функции CreateDataSource():
Список для АКЦИЙ
"LOTSIZE" -- Размер лота "BID" -- Лучшая цена спроса "BIDDEPTH" -- Спрос по лучшей цене "BIDDEPTHT" -- Суммарный спрос "NUMBIDS" -- Количество заявок на покупку "OFFER" -- Лучшая цена предложения "OFFERDEPTH" -- Предложение по лучшей цене "OFFERDEPTHT" -- Суммарное предложение "NUMOFFERS" -- Количество заявок на продажу "OPEN" -- Цена открытия "HIGH" -- Максимальная цена сделки "LOW" -- Минимальная цена сделки "LAST" -- Цена последней сделки "CHANGE" -- Разница цены последней к предыдущей сессии "QTY" -- Количество бумаг в последней сделке "VOLTODAY" -- Количество бумаг в обезличенных сделках "VALTODAY" -- Оборот в деньгах "VALUE" -- Оборот в деньгах последней сделки "WAPRICE" -- Средневзвешенная цена "HIGHBID" -- Лучшая цена спроса сегодня "LOWOFFER" -- Лучшая цена предложения сегодня "NUMTRADES" -- Количество сделок за сегодня "PREVPRICE" -- Цена закрытия "PREVWAPRICE" -- Предыдущая оценка "LASTCHANGE" -- % изменения от закрытия "LASTTOPREVSTLPRC" -- Разница цены последней к предыдущей сессии "MARKETPRICETODAY" -- Рыночная цена "SEC_FACE_VALUE" -- Номинал бумаги "SEC_SCALE" -- Точность цены |
Список для ВАЛЮТЫ
"LOTSIZE" -- Размер лота "BID" -- Лучшая цена спроса "BIDDEPTH" -- Спрос по лучшей цене "BIDDEPTHT" -- Суммарный спрос "NUMBIDS" -- Количество заявок на покупку "OFFER" -- Лучшая цена предложения "OFFERDEPTH" -- Предложение по лучшей цене "OFFERDEPTHT" -- Суммарное предложение "NUMOFFERS" -- Количество заявок на продажу "OPEN" -- Цена открытия "HIGH" -- Максимальная цена сделки "LOW" -- Минимальная цена сделки "LAST" -- Цена последней сделки "CHANGE" -- Разница цены последней к предыдущей сессии "QTY" -- Количество бумаг в последней сделке "VOLTODAY" -- Количество бумаг в обезличенных сделках "VALTODAY" -- Оборот в деньгах "VALUE" -- Оборот в деньгах последней сделки "WAPRICE" -- Средневзвешенная цена "HIGHBID" -- Лучшая цена спроса сегодня "LOWOFFER" -- Лучшая цена предложения сегодня "NUMTRADES" -- Количество сделок за сегодня "PREVPRICE" -- Цена закрытия "PREVWAPRICE" -- Предыдущая оценка "CLOSEPRICE" -- Цена периода закрытия "LASTCHANGE" -- % изменения от закрытия "PRICEMINUSPREVWAPRICE" -- Разница цены последней к предыдущей оценке "LASTTOPREVSTLPRC" -- Разница цены последней к предыдущей сессии "PRICEMAX" -- Максимально возможная цена "PRICEMIN" -- Минимально возможная цена "BASEPRICE" -- Базовый курс "SEC_FACE_VALUE" -- Номинал бумаги "SEC_SCALE" -- Точность цены |
Список для ОПЦИОНОВ
"LOTSIZE" -- Размер лота "BID" -- Лучшая цена спроса "BIDDEPTH" -- Спрос по лучшей цене "BIDDEPTHT" -- Суммарный спрос "NUMBIDS" -- Количество заявок на покупку "OFFER" -- Лучшая цена предложения "OFFERDEPTH" -- Предложение по лучшей цене "OFFERDEPTHT" -- Суммарное предложение "NUMOFFERS" -- Количество заявок на продажу "HIGH" -- Максимальная цена сделки "LOW" -- Минимальная цена сделки "LAST" -- Цена последней сделки "CHANGE" -- Разница цены последней к предыдущей сессии "QTY" -- Количество бумаг в последней сделке "VOLTODAY" -- Количество бумаг в обезличенных сделках "VALTODAY" -- Оборот в деньгах "VALUE" -- Оборот в деньгах последней сделки "WAPRICE" -- Средневзвешенная цена "NUMTRADES" -- Количество сделок за сегодня "PREVPRICE" -- Цена закрытия "PREVWAPRICE" -- Предыдущая оценка "LASTCHANGE" -- % изменения от закрытия "PRICEMINUSPREVWAPRICE" -- Разница цены последней к предыдущей оценке "PREVSETTLEPRICE" -- Предыдущая расчетная цена "NUMCONTRACTS" -- Количество открытых позиций "BUYDEPO" -- Гарантийное обеспечение продавца "SELLDEPO" -- Гарантийное обеспечение покупателя "BGOP" -- БГО по покрытым позициям "BGONP" -- БГО по непокрытым позициям "STRIKE" -- Цена страйк "STEPPRICET" -- Стоимость шага цены "STEPPRICE" -- Стоимость шага цены (для новых контрактов FORTS и RTS Standard) "VOLATILITY" -- Волатильность опциона "THEORPRICE" -- Теоретическая цена "CLPRICE" -- Котировка последнего клиринга "SEC_FACE_VALUE" -- Номинал бумаги "SEC_SCALE" -- Точность цены |
Список для ФЬЮЧЕРСОВ
"LOTSIZE" -- Размер лота "BID" -- Лучшая цена спроса "BIDDEPTH" -- Спрос по лучшей цене "BIDDEPTHT" -- Суммарный спрос "NUMBIDS" -- Количество заявок на покупку "OFFER" -- Лучшая цена предложения "OFFERDEPTH" -- Предложение по лучшей цене "OFFERDEPTHT" -- Суммарное предложение "NUMOFFERS" -- Количество заявок на продажу "HIGH" -- Максимальная цена сделки "LOW" -- Минимальная цена сделки "LAST" -- Цена последней сделки "CHANGE" -- Разница цены последней к предыдущей сессии "QTY" -- Количество бумаг в последней сделке "VOLTODAY" -- Количество бумаг в обезличенных сделках "VALTODAY" -- Оборот в деньгах "VALUE" -- Оборот в деньгах последней сделки "WAPRICE" -- Средневзвешенная цена "NUMTRADES" -- Количество сделок за сегодня "PREVPRICE" -- Цена закрытия "PREVWAPRICE" -- Предыдущая оценка "LASTCHANGE" -- % изменения от закрытия "PRICEMINUSPREVWAPRICE" -- Разница цены последней к предыдущей оценке "PREVSETTLEPRICE" -- Предыдущая расчетная цена "PRICEMAX" -- Максимально возможная цена "PRICEMIN" -- Минимально возможная цена "NUMCONTRACTS" -- Количество открытых позиций "BUYDEPO" -- Гарантийное обеспечение продавца "SELLDEPO" -- Гарантийное обеспечение покупателя "STEPPRICET" -- Стоимость шага цены "STEPPRICE" -- Стоимость шага цены (для новых контрактов FORTS и RTS Standard) "SETTLEPRICE" -- Расчетная цена "PERCENTRATE" -- Агрегированная ставка "CLPRICE" -- Котировка последнего клиринга "REALVMPRICE" -- Текущая рыночная котировка "STEPPRICECL" -- Стоимость шага цены для клиринга "STEPPRICEPRCL" -- Стоимость шага цены для промклиринга "SEC_FACE_VALUE" -- Номинал бумаги "SEC_SCALE" -- Точность цены |
Так же, в QLua есть функции для получения данных как графиков, так и индикаторов по их уникальным идентификаторам(тэгам), для этого необходимо нужному графику(индикатору) назначить уникальный идентификатор, о том как это делается можете ознакомиться в самом начале «Инструкции по использованию» Индикатора «Мои Сделки». Идентификатор для индикатора добавляется аналогичным способом.
После этого, можно использовать следующие функции для доступа к данным:
-- Функция предназначена для получения КОЛИЧЕСТВА ЛИНИЙ в графике (индикаторе) по выбранному идентификатору getLinesCount(tag); -- Возвращает число -- tag - (STRING) идентификатор графика (индикатора), о котором писалось выше -- Функция предназначена для получения информации о КОЛИЧЕСТВЕ СВЕЧЕЙ по выбранному идентификатору getNumCandles(tag); -- Возвращает число -- tag - (STRING) идентификатор графика (индикатора), о котором писалось выше -- Функция предназначена для получения информации о свечах по идентификатору (заказ данных для построения графика функция не осуществляет, поэтому для успешного доступа нужный график должен быть открыт) t, n, l = getCandlesByIndex (tag, line, first_candle, count); -- Параметры: -- tag – (STRING) строковый идентификатор графика или индикатора -- line – (NUMBER) номер линии графика или индикатора. Первая линия имеет номер 0 -- first_candle – (NUMBER) индекс первой свечи. !!! ПЕРВАЯ (САМАЯ ЛЕВАЯ) СВЕЧКА ИМЕЕТ ИНДЕКС 0 !!! -- count – (NUMBER) количество запрашиваемых свечей -- Возвращаемые значения: -- t – таблица, содержащая запрашиваемые свечи, пример работы: local O = t[i].open; -- Получить значение Open для указанной свечи (цена открытия свечи) local H = t[i].high; -- Получить значение High для указанной свечи (наибольшая цена свечи) local L = t[i].low; -- Получить значение Low для указанной свечи (наименьшая цена свечи) local C = t[i].close; -- Получить значение Close для указанной свечи (цена закрытия свечи) local V = t[i].volume; -- Получить значение Volume для указанной свечи (объем сделок в свече) local T = t[i].datetime; -- Получить значение datetime для указанной свечи -- Где i - индекс свечи от 0 до n-1 -- n – количество свечей в таблице t -- l – легенда (подпись) графика |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Программирование на Lua: 1
Программирование на Lua: 1
Это первое издание было написано для Lua 5.0. Хотя все еще актуально для более поздних версий, есть некоторые отличия.
Четвертое издание предназначено для Lua 5.3 и доступно в Amazon и других книжных магазинах.
Покупая книгу, вы также помогаете поддерживать проект Lua.
По традиции,
наша первая программа на Lua просто выводит «Hello World»
:
print ("Привет, мир")
Если вы используете автономный интерпретатор Lua,
все, что вам нужно сделать для запуска вашей первой программы, — это вызвать интерпретатор
(обычно называется lua
) с именем текстового файла, содержащего
ваша программа.Например,
если вы запишете вышеуказанную программу в файл hello.lua
,
следующая команда должна запустить его:
подсказка> lua hello.lua
В качестве немного более сложного примера,
следующая программа определяет функцию для вычисления
факториал заданного числа,
запрашивает у пользователя номер,
и печатает свой факториал:
- определяет факториальную функцию функция fact (n) если n == 0, то возврат 1 еще вернуть n * факт (n-1) конец конец print ("введите число:") а = io.read ("* число") - прочитать число печать (факт (а))
Если вы используете Lua, встроенный в приложение,
такие как CGILua или IUPLua,
вам может потребоваться обратиться к руководству по применению (или к «местному гуру»)
чтобы узнать, как запускать ваши программы.
Тем не менее, Lua остается тем же языком;
большинство вещей, которые мы здесь увидим, действительны независимо от того, как
вы используете Lua.
Для начала рекомендуем использовать автономный интерпретатор.
(то есть исполняемый файл lua
)
для запуска ваших первых примеров и экспериментов.
Copyright © 2003–2004 Роберто Иерусалимши. Все права защищены. |
.
Lua — Начало работы с Lua
Lua — это минималистичный, легкий и встраиваемый язык сценариев. Он разрабатывается, внедряется и поддерживается командой PUC-Rio, Папского католического университета Рио-де-Жанейро в Бразилии. Список рассылки открыт для участия.
Общие варианты использования Lua включают создание сценариев видеоигр, расширение приложений с помощью плагинов и конфигураций, обертывание некоторой высокоуровневой бизнес-логики или просто встраивание в такие устройства, как телевизоры, автомобили и т. Д.
Для высокопроизводительных задач существует независимая реализация с использованием JIT-компилятора под названием LuaJIT.
Версии
Версия | Примечания | Дата выпуска |
---|---|---|
1.0 | Начальный непубличный выпуск. | 28.07.1993 |
1,1 | Первый публичный выпуск.Документ конференции, описывающий это. | 08.07.1994 |
2.1 | Начиная с Lua 2.1, Lua стал свободно доступным для всех целей, включая коммерческое использование. Журнал с описанием этого. | 1995-02-07 |
2.2 | Длинные строки, интерфейс отладки, улучшенная трассировка стека | 1995-11-28 |
2,4 | Внешний компилятор luac | 1996-05-14 |
2.5 | Сопоставление с образцом и функции vararg. | 1996-11-19 |
3,0 | Введен auxlib, библиотека для помощи в написании библиотек Lua | 1997-07-01 |
3,1 | Анонимные функции и закрытие функций через «повышающие значения». | 1998-07-11 |
3.2 | Библиотека отладки и новые табличные функции | 1999-07-08 |
3.2.2 | 2000-02-22 | |
4.0 | Множественные состояния, операторы «для», обновление API. | 2000-11-06 |
4.0.1 | 2002-07-04 | |
5.0 | Сопрограммы, метатаблицы, полная лексическая область видимости, хвостовые вызовы, логические значения перемещаются в лицензию MIT. | 11.04.2003 |
5.0.3 | 2006-06-26 | |
5.1 | Модернизация системы модулей, инкрементный сборщик мусора, метатаблицы для всех типов, luaconf.h переработка, полностью реентерабельный синтаксический анализатор, вариативные аргументы. | 21.02.2006 |
5.1.5 | 2012-02-17 | |
5.2 | Аварийный сборщик мусора, goto, финализаторы для таблиц. | 2011-12-16 |
5.2.4 | 2015-03-07 | |
5,3 | Базовая поддержка UTF-8, побитовые операции, 32/64-битные целые числа. | 12.01.2015 |
5.3.4 | Последняя версия. | 12.01.2017 |
Однострочные комментарии в Lua начинаются с -
и продолжаются до конца строки:
- это однострочный комментарий
- нужна еще одна строка
- а?
Комментарии блока начинаются с - [[
и заканчиваются на ]]
:
- [[
Это комментарий блока.
Итак, это может продолжаться ...
и дальше...
и дальше ....
]]
Блочные комментарии используют тот же стиль разделителей, что и длинные строки; в скобках можно добавить любое количество знаков равенства, чтобы ограничить комментарий:
- [= [
Это тоже комментарий блока
Мы можем включить "]]" в этот комментарий
знак равно
- [== [
Это тоже комментарий блока
Мы можем включить "] =]" в этот комментарий
-] ==]
Изящный трюк, чтобы закомментировать фрагменты кода, состоит в том, чтобы окружить его - [[
и -]]
:
- [[
print'Lua прекрасна '
-]]
Чтобы повторно активировать блок, просто добавьте -
к последовательности открытия комментария:
--- [[
print'Lua прекрасна '
-]]
Таким образом, последовательность -
в первой строке начинает однострочный комментарий, как и последняя строка, а оператор print
не закомментирован.
Идя дальше, два блока кода могут быть настроены таким образом, что если первый блок закомментирован, второй не будет, и наоборот:
--- [[
print 'Lua - это любовь'
знак равно
print 'Lua - это жизнь'
знак равно
Чтобы активировать второй фрагмент при отключении первого фрагмента, удалите ведущие -
в первой строке:
- [[
print 'Lua - это любовь'
знак равно
print 'Lua - это жизнь'
знак равно
Выполнение программ Lua
Обычно Lua поставляется с двумя двоичными файлами:
-
lua
— автономный интерпретатор и интерактивная оболочка -
luac
— компилятор байт-кода
Допустим, у нас есть пример программы ( bottle_of_mate.lua
) вот так:
локальная строка = требуется "строка"
функция bottle_take (bottle_available)
local count_str = "% d бутылок мате на стене."
local take_str = "Взять один, передать," .. count_str
local end_str = "О нет," .. count_str
local buy_str = "Купи немного в магазине" .. count_str
местные бутылки_left = 0
если bottle_available> 0, тогда
print (string.format (count_str, bottle_available))
bottle_left = bottle_available - 1
печать (строка.формат (take_str, bottle_left))
еще
print (string.format (end_str, bottle_available))
Bottle_left = 99
print (string.format (buy_str, bottle_left))
конец
возврат бутылок
конец
local bottle_count = 99
в то время как правда
bottle_count = бутылка_взято (кол-во бутылок)
конец
Саму программу можно запустить, выполнив в вашей оболочке следующее:
$ lua bottle_of_mate.lua
Вывод должен выглядеть так, работая в бесконечном цикле:
Достань в магазине, 99 бутылок мате на стене.
99 бутылок мате на стене.
Сними одну, разнеси, 98 бутылок мате на стене.
98 бутылок мате на стене.
Возьми одну, разнеси, 97 бутылок мате на стене.
97 бутылок мате на стене.
...
...
3 бутылки мате на стене.
Возьми одну, разнеси, 2 бутылки мате на стене.2 бутылки мате на стене.
Возьми одну, разнеси, 1 бутылка мате на стене.
1 бутылка мате на стене.
Возьми одну, разнеси, 0 бутылок мате на стене.
О нет, 0 бутылок мате на стене.
Купи в магазине, 99 бутылок мате на стене.
99 бутылок мате на стене.
Сними одну, разнеси, 98 бутылок мате на стене.
...
Вы можете скомпилировать программу в байт-код Lua, выполнив в вашей оболочке следующее:
$ luac bottle_of_mate.lua -o bottle_of_mate.luac
Также доступен список байт-кода, выполнив следующее:
$ luac -l bottle_of_mate.lua
main <./ Bottle.lua: 0,0> (13 инструкций, 52 байта на 0x101d530)
0+ параметров, 4 слота, 0 повышающих значений, 2 локальных параметра, 4 константы, 1 функция
1 [1] GETGLOBAL 0 -1; требовать
2 [1] LOADK 1-2; "строка"
3 [1] ЗВОНИТЕ 0 2 2
4 [22] ЗАКРЫТИЕ 1 0; 0x101d710
5 [22] ПЕРЕМЕЩЕНИЕ 0 0
6 [3] SETGLOBAL 1 -3; bottle_take
7 [24] НАГРУЗКА 1 -4; 99
8 [27] GETGLOBAL 2–3; bottle_take
9 [27] ПЕРЕМЕЩЕНИЕ 3 1
10 [27] ЗВОНИТЕ 2 2 2
11 [27] ПЕРЕМЕЩЕНИЕ 1 2
12 [27] JMP -5; до 8
13 [28] ВОЗВРАТ 0 1
функция <./bottles.lua:3,22> (46 инструкций, 184 байта на 0x101d710)
1 параметр, 10 слотов, 1 повышающее значение, 6 локальных переменных, 9 констант, 0 функций
1 [5] LOADK 1 -1; "% d бутылок мате на стене".
2 [6] LOADK 2 -2; «Сними один, разнеси»
3 [6] ПЕРЕМЕЩЕНИЕ 3 1
4 [6] СЦЕПИТЬ 2 2 3
5 [7] НАГРУЗКА 3 -3; "О нет,"
6 [7] ПЕРЕМЕЩЕНИЕ 4 1
7 [7] СЦЕПИТЬ 3 3 4
8 [8] НАГРУЗКА 4 -4; "Купи немного в магазине"
9 [8] ПЕРЕМЕЩЕНИЕ 5 1
10 [8] CONCAT 4 4 5
11 [9] НАГРУЗКА 5 -5; 0
12 [11] EQ 1 0 -5; - 0
13 [11] JMP 16; до 30
14 [12] GETGLOBAL 6 -6; Распечатать
15 [12] GETUPVAL 7 0; строка
16 [12] ТАБЛИЦА 7 7 -7; "формат"
17 [12] ПЕРЕМЕЩЕНИЕ 8 1
18 [12] ПЕРЕМЕЩЕНИЕ 9 0
19 [12] ЗВОНИТЕ 7 3 0
20 [12] ЗВОНИТЕ 6 0 1
21 [13] SUB 5 0 -8; - 1
22 [14] GETGLOBAL 6 -6; Распечатать
23 [14] GETUPVAL 7 0; строка
24 [14] ТАБЛИЦА 7 7 -7; "формат"
25 [14] ПЕРЕМЕЩЕНИЕ 8 2
26 [14] ПЕРЕМЕЩЕНИЕ 9 5
27 [14] ЗВОНИТЕ 7 3 0
28 [14] ЗВОНИТЕ 6 0 1
29 [14] JMP 15; до 45
30 [16] GETGLOBAL 6 -6; Распечатать
31 [16] GETUPVAL 7 0; строка
32 [16] ТАБЛИЦА 7 7 -7; "формат"
33 [16] ПЕРЕМЕЩЕНИЕ 8 3
34 [16] ПЕРЕМЕЩЕНИЕ 9 0
35 [16] ЗВОНИТЕ 7 3 0
36 [16] ЗВОНИТЕ 6 0 1
37 [17] НАГРУЗКА 5 -9; 99
38 [18] GETGLOBAL 6 -6; Распечатать
39 [18] GETUPVAL 7 0; строка
40 [18] ТАБЛИЦА 7 7 -7; "формат"
41 [18] ПЕРЕМЕЩЕНИЕ 8 4
42 [18] ПЕРЕМЕЩЕНИЕ 9 5
43 [18] ЗВОНИТЕ 7 3 0
44 [18] ЗВОНИТЕ 6 0 1
45 [21] ВОЗВРАТ 5 2
46 [22] ВОЗВРАТ 0 1
Начало работы
переменных
var = 50 - глобальная переменная
print (var) -> 50
делать
local var = 100 - локальная переменная
print (var) -> 100
конец
print (var) -> 50
- Глобальный var (50) все еще существует
- Локальная переменная (100) вышла из области видимости и больше не доступна.
типов
num = 20 - число
num = 20.001 - по-прежнему число
str = "zaldrizes buzdari iksos daor" - строка
tab = {1, 2, 3} - таблица (у них своя категория)
bool = true - логическое значение
bool = false - единственное другое логическое значение
print (type (num)) -> 'число'
print (type (str)) -> 'строка'
print (type (bool)) -> 'логическое'
тип (тип (число)) -> 'строка'
- Функции - это тоже тип, и первоклассные значения в Lua.print (type (print)) -> печатает 'функцию'
old_print = печать
print = function (x) old_print "Я игнорирую переданный вами параметр!" конец
old_print (type (print)) -> По-прежнему печатает «функцию», так как это все еще функция.
- Но мы (бесполезно) пересмотрели поведение печати.
print ("Hello, world!") -> выводит "Я игнорирую параметр, который вы мне передали!"
Особый тип нет
Другой тип в Lua — nil
.Единственное значение для типа nil
— nil
. nil
существует, чтобы отличаться от всех других значений в Lua. Это своего рода неценностная ценность.
print (foo) - выводит nil, поскольку в переменной 'foo' ничего не хранится.
foo = 20
print (foo) - теперь выводится 20, поскольку мы присвоили 'foo' значение 20.
- Мы также можем использовать `nil` для отмены определения переменной
foo = nil - здесь мы устанавливаем 'foo' равным nil, чтобы его можно было собрать сборщиком мусора.если nil, то выведите "nil" конец -> (ничего не печатает)
- Только false и nil считаются ложными; все остальные значения верны.
если 0, то выведите "0" конец -> 0
если "", то выведите "Пустая строка!" -> Пустая строка!
выражений
а = 3
b = a + 20 a = 2 print (b, a) - трудно читать, также может быть записано как
б = а + 20; а = 2; print (a, b) - легче читать,; не являются обязательными, хотя
истина и истина -> возвращает истину
верно и 20 -> 20
ложь и 20 -> ложь
ложь или 20 -> 20
истина или 20 -> истина
вкладка или {}
-> возвращает вкладку, если она определена
-> возвращает {}, если вкладка не определена
- Это полезно, когда мы не знаем, существует ли переменная
tab = tab или {} - вкладка остается неизменной, если она существует; вкладка становится {}, если ранее она была равна нулю.a, b = 20, 30 - это тоже работает
a, b = b, a - переключает значения
Определение функций
имя функции (параметр)
возвращаемый параметр
конец
печать (имя (20)) -> 20
- см. категорию функций для получения дополнительной информации
name = function (parameter) return parameter end - То же, что и выше
логические
Только false
и nil
оцениваются как false, все остальное, включая 0
и пустую строку, оценивается как true.
сборщик мусора
tab = {"лоты", "из", "данные"}
tab = nil; сбор мусора ()
- вкладка больше не существует и больше не занимает память.
столов
tab1 = {"a", "b", "c"}
tab2 = tab1
tab2 [1] = "d"
print (tab1 [1]) -> 'd' - значения таблицы хранят только ссылки.
-> присвоение таблиц не копирует их содержимое, только ссылку.
tab2 = ноль; сбор мусора ()
print (tab1) -> (выводит адрес таблицы) - tab1 все еще существует; он не собирался сборщиком мусора.tab1 = ноль; сбор мусора ()
- Больше никаких ссылок. Теперь это действительно должно быть стерто из памяти.
Это основы, но есть раздел о таблицах с дополнительной информацией.
условия
если (условие), то
-- сделай что-нибудь
elseif (другое_условие) тогда
- сделай что-нибудь еще
еще
-- сделай что-нибудь
конец
для петель
В Lua существует два типа для цикла
: числовой для цикла
и общий для цикла
.
Числовой
для цикла
имеет следующий вид:для a = 1, 10, 2 do - для начала 1, заканчивая 10, с шагом 2 печать (а) -> 1, 3, 5, 7, 9 конец
Третье выражение в числовом цикле
для
— это шаг, на который цикл будет увеличиваться. Это упрощает выполнение обратных циклов:для a = 10, 1, -1 сделать print (a) -> 10, 9, 8, 7, 6 и т. д.конец
Если выражение step не указано, Lua принимает значение по умолчанию 1.
для a = 1, 10 do print (a) -> 1, 2, 3, 4, 5 и т. д. конец
Также обратите внимание, что переменная цикла является локальной для цикла
для
. Он не будет существовать после завершения цикла.
Общий
для циклов
обрабатывает все значения, возвращаемые функцией итератора:для ключа, значения в парах ({"некоторые", "таблица"}) делать печать (ключ, значение) -> 1 немного -> 2 стола конец
Lua предоставляет несколько встроенных итераторов (например,g.,
пар
,ipairs
), и пользователи могут определять свои собственные итераторы, а также использовать их с общимдля циклов
.
до блоков
местный а = 10
делать
печать (а) -> 10
местный а = 20
печать (а) -> 20
конец
печать (а) -> 10
Привет, мир
Это привет, мировой код:
print («Hello World!»)
Как это работает? Это просто!
Lua выполняет функцию print ()
и использует строку «Hello World»
в качестве аргумента.
Установка
Двоичные файлы
двоичные файлы Lua предоставляются большинством дистрибутивов GNU / Linux в виде пакета.
Например, в Debian, Ubuntu и их производных его можно получить, выполнив следующее:
sudo apt-get install lua50
sudo apt-get install lua51
sudo apt-get install lua52
Есть несколько полуофициальных сборок для Windows, MacOS и некоторых других операционных систем, размещенных на SourceForge.
Пользователи Apple также могут легко установить Lua с помощью Homebrew:
brew установить lua
(В настоящее время Homebrew имеет 5.2.4, для 5.3 см. Homebrew / версии.)
Источник
Источник доступен на официальной странице. Получение исходников и сборка должны быть тривиальными. В системах Linux должно быть достаточно:
$ wget http://lua.org/ftp/lua-5.3.3.tar.gz
$ echo "a0341bc3d1415b814cc738b2ec01ae56045d64ef./lua-5.3.3.tar.gz "| sha1sum -c -
$ tar -xvf ./lua-5.3.3.tar.gz
$ make -C ./lua-5.3.3/ linux
В приведенном выше примере мы в основном загружаем исходный архив tarball
с официального сайта, проверяем его контрольную сумму, а также извлекаем и выполняем make
. (Дважды проверьте контрольную сумму на официальной странице.)
Примечание: вы должны указать, какую цель сборки вы хотите. В этом примере мы указали linux
. Другие доступные цели сборки включают solaris
, aix
, bsd
, freebsd
, macosx
, mingw
и т. Д.Дополнительные сведения см. В документе doc / readme.html
, включенном в исходный код. (Вы также можете найти последнюю версию README в Интернете.)
Модули
Стандартные библиотеки ограничены примитивами:
-
coroutine
— функциональность управления сопрограммами -
отладка
— отладочные хуки и инструменты -
io
— базовые примитивы ввода-вывода -
пакет
— функции управления модулями -
string
— специфичная для строки и Lua функция сопоставления шаблонов -
table
— примитивы для работы с важным, но сложным типом Lua — таблицы -
os
— основные операции ОС -
utf8
— базовые примитивы UTF-8 (начиная с Lua 5.3)
Все эти библиотеки могут быть отключены для конкретной сборки или загружены во время выполнения.
Сторонние библиотеки Lua и инфраструктура для распространения модулей немногочисленны, но улучшаются. Такие проекты, как LuaRocks, Lua Toolbox и LuaDist, улучшают ситуацию. Много информации и много предложений можно найти в старой Lua Wiki, но имейте в виду, что часть этой информации довольно устарела и устарела.
Некоторые хитрости
Иногда Lua ведет себя не так, как можно было бы подумать после прочтения документации.Вот некоторые из этих случаев:
Как и ожидалось, table.insert (my_table, 20)
добавляет значение 20
в таблицу, а table.insert (my_table, 5, 20)
добавляет значение 20 в 5-ю позицию.
Что же делает table.insert (my_table, 5, nil)
? Можно было бы ожидать, что он будет рассматривать nil
как отсутствие аргумента и вставлять значение 5
в конец таблицы, но на самом деле он добавляет значение nil
в 5-ю позицию таблицы.Когда это проблема?
(функция (вкладка, значение, позиция)
table.insert (табуляция, позиция или значение, позиция и значение)
конец) ({}, 20)
- Это заканчивается вызовом table.insert ({}, 20, nil)
- и это не делает того, что должно (вставить 20 в конце)
То же самое происходит с tostring ()
:
print (tostring (nil)) - выводит "nil"
table.insert ({}, 20) - ничего не возвращает
- (не ноль, но на самом деле ничего (да, я знаю, в lua эти два ДОЛЖНЫ
- то же самое, но их нет))
-- неправильно:
print (tostring (table.вставить ({}, 20)))
- выдает ошибку, потому что ничего не ~ = nil
--право:
local _tmp = table.insert ({}, 20) - после этого _tmp содержит ноль
print (tostring (_tmp)) - выводит "nil", потому что внезапно ничего не == nil
Это также может привести к ошибкам при использовании стороннего кода. Если, например, в документации по какой-то функции указано «возвращает пончики, если повезет, в противном случае — ноль», реализация может выглядеть как примерно так:
function func (повезло)
если повезет тогда
вернуть "пончики"
конец
конец
, эта реализация сначала может показаться разумной; он возвращает пончики, когда это необходимо, и когда вы набираете result = func (false)
result будет содержать значение nil
.
Однако, если написать print (tostring (func (false)))
lua выдаст ошибку, которая выглядит примерно так: stdin: 1: плохой аргумент # 1 для 'tostring' (ожидаемое значение)
Почему? tostring
явно вызывает аргумент, хотя это nil
. Неправильно. func вообще ничего не возвращает, поэтому tostring (func (false))
совпадает с tostring ()
и НЕ совпадает с tostring (nil)
.
Ошибки с сообщением «ожидаемое значение» являются убедительным признаком того, что это может быть источником проблемы.
Это огромная ловушка, если вы новичок в lua, и в таблицах категории
много информации.
.
Lua — мощный и быстрый язык программирования Lua разработан как легкий встраиваемый язык сценариев. Увидеть Посмотрите, как выглядят и работают программы Lua в Хорошее место для начала изучения Lua — книга Официальное определение языка Lua дается в Увидеть Наши Если вам нужна помощь на португальском языке, Смотрите также Если вам нужно Вы можете помочь Вы также можете помочь распространить информацию о Lua, купив продукты Lua. | Использовать Чтобы запускать программы Lua на вашем компьютере, Если вы используете Windows, Если вы используете Linux или Mac OS X, Lua также довольно легко собрать из исходного кода, Строительство из источника Lua очень легко собрать и установить.Просто скачайте и Вот простой сеанс терминала, который curl -R -O http://www.lua.org/ftp/lua-5.4.0.tar.gz tar zxf lua-5.4.0.tar.gz cd lua-5.4.0 сделать все испытания Если у вас нет curl, попробуйте wget. Если вы используете Windows и хотите собрать Lua из исходного кода, Заготовка Чтобы встроить Lua в вашу программу C или C ++, |
.
Официальное определение языка Lua — это его В В В В Техническая документация Для получения дополнительной технической информации, Здесь очень много Основная научная статья о Lua
Для обзора того, как разработан Lua, см.
Краткое описание дизайна API см.
Он также доступен на португальском:
Подробнее о реализации Lua см.
Подробнее о роли функций первого класса в Lua см.
Для обсуждения сопрограмм в Lua см.
Полную историю Lua до 2006 г. см.
Историю Lua до 2001 года см.
Первая статья, описывающая Lua, имеет исторический интерес:
Для ранней пояснительной статьи см.
Вводный текст (на португальском языке) см.
| Книги Lua доступны в основных интернет-магазинах. Справочное руководствоОфициальное определение языка Lua:
Справочные руководства для более поздних версий Lua доступны Программирование на Lua Подробное и авторитетное введение в
Четвертое издание ориентировано на Lua 5.3. Первое издание Третья редакция была нацелена на Lua 5.2 и остается весьма актуальной.
Второе издание остается актуальным и доступно в
Самоцветы программирования LuaСборник статей, в которых записаны некоторые из существующих знаний и практик о том, как хорошо программировать на Lua:
Книги другиеЕсть также книги о Lua, написанные другими авторами:
|
.