Единый счет - это конструкция, когда данные собираются из разных мест. Вы бы сказали хоть какие изменения должны вызывать событие. Если деньги - это одно. Если позиции по бумагам - это другое. Портфель - слишком общее понятие.
Если говорить о доступных call back, то их список описан в документации. Не очень ясно, что требуется. Но можно предположить, что если речь про денежные средства, а не позиции, может подойти: OnMoneyLimit.
Но можете и сами организовать вызов некой функции при изменении данных портфеля, сделав регулярную проверку оного.
Верну вопрос, т.к. он потерялся за потоком бессмысленных сообщений:
Можно ли утверждать, что время в параметре 'TIME', полученное в колбеке OnParam через getParamEx(class_code, sec_code, 'TIME') не может быть больше чем время последней записи getInfoParam('LASTRECORDTIME')?
Чтобы получить данные по деньгам, позициям надо обратиться к определенной таблице и просканировать строки, либо использовать специализированные функции для получения денежных лимитов, позиций и т.д., допустим getMoneyEx или getPortfolioInfoEx.
Вам надо уточнить, что Вы подразумеваете под "по новой запускает main". Также не очень понятно работает ли Квик круглосуточно или перезапускается.
main - это точка входа работы скрипта, если эта функция завершит свою работу, то скрипт прекратит выполнение. Поэтому повторный запуск main - это либо новый запуск скрипта, либо у Вас все же организованы циклы ожидания нового дня, где происходят какие-то действия приводящие к очистке переменных. Собственно объявленные Вами переменные могут только Вами и быть переопределены, т.е. тем кодом, что написан.
Nikolay написал: include файлы и lua54.lib взято с оф. сайта lua.
Не точно, но возможно, вы взяли статическую библиотеку lua54.lib (~300 кб.). Надо использовать библиотеку импорта dll lua54.lib (~30 кб.) с тем, чтобы использовались функции QUIK из его lua54.dll. Либо надо самому создать библиотеку импорта lua54.lib, используя lua54.dll из QUIK.
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Приведенный список можно продолжить, но, кому это интересно, может прочесть в файле OS_Quesha.pdf.
Дело в том, что Вы привели пример простого диалога, который очень просто пишется на lua. При этом у меня уже давно написан dsl, где я даже проще чем у вас создаю формы и реакции.
Хотелось бы понять, зачем это для реальной работы. Ведь диалог - это вообще последняя вещь, хоть и важная если пишешь не для себя.
Проверил подключение библиотек dll на версиях 11, 12 в режиме lua 5.4. Случайно подключил библиотеку для lua 5.3. Квик молча упал. Воспроизводится стабильно.
Вроде как моя ошибка, но хотелось бы наверно, чтобы это не приводило к аварийному падению.
Так такая ситуация бывает редко. Иначе бы это было явно видно. Просто когда выходит цена из прошлого, то она зачастую гораздо выше(ниже) текущей. Некоторые алгоритмы анализируют диапазон изменения цены и такие выпады мешают.
Колбек OnOParam здесь используется просто как триггер, не более.
Цена берется последняя из параметра LAST в момент срабатывания колбека. Так что это тоже самое, что делаете Вы.
Но вот незадача, последняя цена кривая. Поэтому время и анализируется, чтобы понять почему она кривая. Иначе просто опрашивая цену, получаем ту, что была вчера. Ну так отправил брокер.
Вот сегодня брокер сбербанк выдал такую цену и время по SRH1: price = 26588, time = 184459
Это было примерно в такое время 2021-01-29 16:03:01
Возвращаясь к вопросу - это как понять? Почему время, полученное в колбеке OnParam через getParamEx(class_code, sec_code, 'TIME') - будущее. Хотя, судя по цене, это прошлое. Но т.к. здесь мы имеем только время, то равновероятно прошлое и будущее.
Можно ли утверждать, что время в параметре 'TIME' не может быть больше чем время последней записи getInfoParam('LASTRECORDTIME')? Хотелось бы верить, что хотя бы это выполняется.
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Я уже видел изделие в прошлый раз, на другом ресурсе. Кажется, что кота в мешке лучше не здесь показывать. Тем более с ссылкой на архив непонятного содержания на mail.ru. Код библиотек не проверить, луа код - ... Вы бы хоть абсолютные пути и отладочные выражения убрали из поставки, если это продукт. Лицензия не ясна. Я такое только в виртуалках распаковываю. А уж про запуск на рабочем сервере - даже не обсуждается. Интерфейс на iup уже вызывает вопрос о необходимости даже пробовать.
Что касается простой/сложный робот, то как-то не увидел проблем в написании скрипта с сложным интерфейсом и псевдоасинхронной обработкой очередей событий.
Раз уж Вы разместили это здесь, то хотелось бы увидеть пример применения, где средств lua будет явно недостаточно и необходимо использовать данный продукт.
Маленький совет со временем: переходите на unix-time.
Если Вам надо сравнивать времена, то определите строковые представления в конфигурации и переведите их в числа при старте алгоритма, чтобы не делать это постоянно. Тогда уже сравнивать время будет проще, т.к. это будут просто числа. Ну и прибавлять, убавлять время намного проще, т.к. все в секундах.
Как заставить индикатор отреагировать в нужный момент на какие-то внешние изменения, вот же в чем вопрос.
Если инструмент ликвиден и сделки часты, то OnCalculate часто дергается. Если будет внешний флаг "прочитай данные", то задержка будет малая. А если мало сделок, то здесь уже только если самому сделку сделать, чтобы заставить индикатор отработать.
Сдвинуть обе метки в скрипте. Индикатор видит новые координаты меток (опрашивает метку) и рисует по ним линию.
С другой стороны, раз есть связка скрипт-индикатор, то проще с Вашей библиотекой передавать новые координаты в индикатор.
Я обычно метки использую для обратной передачи, когда надо из индикатора передать информацию от пользователя в скрипт. Пользователь метку двигает - т.е. он интерактивно с графика задает какой-то уровень в скрипт.
Нанести линию на график можно. Правда с использованием костыля: меток. Наносите пары метки на график. А также пишите индикатор, который читает положения парных меток на графике и строит по ним линию.
Я бы сказал, что это просто порочная практика жить в глобальном окружении. Не в смысле плохая - иногда можно, но лучше не надо. Иначе в одном месте написал f = 5 и все сломалось.
1. берем минимальные бары за указанный диапазон. Может и тиков хватит, если период в недавнем прошлом. Распределяем объем бара по цене. Можно просто с шагом цены, можно что-то свое придумать. По этой методике много индикаторов. Если тики, то объем точный, распределять не надо, а надо просто агрегировать объемы по ценам, с необходимым шагом.
2. Пишем скрипт, который создает файлы объемов для каждого тайм-фрейма. Скрипт получает данные из обезличенных сделок и формирует агрегации по тайм-фреймам. Далее просто записать в файлы. Структура хранения по желанию. В других скриптах читаем эти исторически данные. Можно использовать базу данных вместо файлов, сути это не меняет.
3. оформляем подписку на архив данных Мосбиржи и через ее API забираем данные сделок. Далее просто их распределяем с необходимым шагом цены. Это как и в пункте 2, но уже не нужен промежуточный скрипт, а просто читаем данные.
Любой скрипт lua не проблема запустить из командной строки, используя интерпретатор lua. Но с скриптами для Квика так не выйдет, т.к. окружение у qlua специфическое. В частности, интерпретатор, по сути, это и будет терминал. Если только Вы не эмулировали набор методов и переменных их глобального контекста qlua.
У меня тестер наносит на график метки сделок. Их, конечно не тысячи, но 500 и более спокойно может быть. График "подтормаживает" только при масштабировании. Особых "тормозов" при перемещении нет.
Памяти на рабочей станции немного - 32 ГБ. Правда быстрый SSD.
Скрипт с таблицей имеет очередь передачи сообщений - она же таблица в staticVаr, допустим. При возникновении события в таблице в эту очередь записывается информация. Как Вы и написали проблем с передачей нет.
Другой скрип, смотрит на эту очередь и читает информацию, если в ней что-то появилось. Опрашивать, допустим по увеличению размера. Не такая и проблема выполнить что-то типа: last_count < #Table
На самом деле, даже если это один скрипт, некоторые команды нежелательно исполнять в колбеке таблицы. А значит их надо передавать в дополнительный поток скрипта, через любую переменную видимого контекста. Это мало отличается от схемы с разделяемой переменной. Неэффективность будет только в том, что все события пойдут через очередь.
Легко давать советы не особенно вникая.) Передать колбэк не проблема только вот что бы принять его другим скриптом механизма прерывания и включения параллельного потока нет. Или вы предлагаете main() в цикле опрашивать переменную на случай наступления события?
Да, опрашивать по изменению количества в очереди. Собственно, это не такая и редка задача: Квик исполнитель, а интерфейс может быть в базе данных, на таблицах. Ясно, что лучше написать прямую библиотеку, но раз ее нет, надо передавать команды по каналам связи.
Раз необходимо иметь разные события для разных окон, то дайте имена этим событиям разные или сопровождайте их разным наборов параметров, чтобы обработчик понимал с чем имеет дело.
А что касается интерфейса, то он может быть расположен на устройстве на Марсе. А сервер должен получить события, что пользователь инициировал и как-то прореагировать: ракету запустить или вернуть ответ в тот же интерфейс. Интерфейс и сервер (обработчик и т.д.) это не обязательно единое целое.
Что касается групп событий, то здесь надо формализовать как эта группа формируется. Возможно на клиенте с интерфейсом надо сгруппировать по какому-то признаку и уже передать эту группу в очередь как единое целое.
Если у Вас ячейки привязаны к конкретному скрипту (т.е. реакция на нее однозначно для скрипта №2), особой разницы нет, где событие прошло. Делаете очередь событий и передаете события с параметрами обратно в скрипт через тот же механизм. А скрипт уже, в свою очередь, опрашивает на предмет нового события из своей области обмена.
А в других перечисленных вами вариантах ждать не будут?
Так смотря что ждать. Если база данных, то смотрим какой уровень изоляции транзакции оная поддерживает. Можно сделать несколько таблиц для каждой пары (примерно как и с файлами). Писатель блокирует таблицу, другие таблицы доступны. Читатель читает те таблицы, что доступны.
Если библиотеки обмена, то их авторы доступны.
Если socket, то он по умолчанию блокирующий. Т.е. надо ждать. В книге Роберту Иерузалимски. «Программирование на языке Lua» есть пример Невытесняющая многонитевость.
named pipes позволяют сделать многопоточное подключение, к серверу. Хотя именованные каналы - это по сути файлы, только в памяти.
Для чтения. Записать одновременно в один файл с двух сторон, то еще занятие. Да, файл-флаг здесь решит проблему, чтоб все ждали пока он есть. А когда его нет, то все писатели одновременно ринутся писать в один тот-же файл.
Если источник-приемник один, то достаточно в источнике открыть файл в режиме записи, а в приемнике в режиме чтения и просто проверять новые данные в этом файле через read("*l"). Писатель записал, читатель их прочитал. Скрипт индикатору может спокойно так передавать информацию.
Старатель написал: Второй файл как раз служит для писателей индикатором, что первый файл занят, и запись не возможна. Как только приёмник прочитает данные, он удаляет 2-й файл, что сигнализирует о возможности записи. Т.е. организуются синхронные запись/чтение.
Кстати, ни разу не видел, блокировок файлов, одновременно открытых несколькими Lua-скриптами. Если файл открыт другим приложением, то, да, было.
Блокировки видел, хоть lua и очень быстр в части работы с файлами. Если пара одна, то это приведет к тому, что все будут ждать пока он освободится. А если несколько, то приемник сможет переключаться между парами, чтобы не ждать.
Конечно, все это для обмена большими объемами и несколькими источниками-потребителями. Если данных мало и они редки, то все это излишне.
Старатель написал: Вот тут пример организации обмена с двумя файлами: 1-й файл для передачи данных, 2-й - пустой файл, служит флагом для индикации готовности данных к считыванию.
Это надо для каждый пары источник-приемник создавать пару файлов. Как только несколько писателей, с двумя файлами может быть блокировка. А приемник должен псевдо-асинхронно это читать.
Есть такая "особенность": Вызов С функции форсирует более агрессивный режим работы сборщика мусора. Если код содержит много циклов с формированием локальных переменных, то мусор неохотно убирается.
Конструкция такого вида помогает, вместо прямого вызова сборщика. _G.SearchItems('money_limits', 0, 0, empty_func, "currcode")
---@param num number
---@param idp any
local function round(num, idp)
if num then
local mult = 10^(idp or 0)
if num >= 0 then
return math.floor(num * mult + 0.5) / mult
else
return math.ceil(num * mult - 0.5) / mult
end
else
return num
end
end
Обычно, все же, применяют округление к итоговому результату. У Вас math.ceil(price/options.price_step) * options.price_step есть результат работы с вещественными числами. Его и надо привести к нужной точности, а потом уже сравнивать.
Владимир, Вы опять смешиваете язык и его синтаксис с поведением терминала. Даже не терминала, а особенностям потока данных, получаемого от ядра биржи. Статус, биржа отдает, либо брокера на серверной части "режет" его.
И да, точно также, у многих есть претензии к поведению исполнительного механизма (терминала), потоку данных и т.д. Сообщениям о нескольких вызовах колбеков на одно событие уже много лет.
Но язык здесь причем.
Что касается tonumber(GetCell(T,p1,0).value), то чтобы ответить надо понять из какого поля получаются данные. Если из колонки типа "строка", то и не будет работать, т.к. у него value нет.
Цитата
BOOLEAN SetCell(NUMBER t_id, NUMBER key, NUMBER code, STRING text, NUMBER value) Функция задает значение для ячейки в строке с ключом «key», кодом колонки «code» в таблице «t_id». Параметр «text» задает строковое представление значение параметра «value». Параметр «value» необязательный и по умолчанию равен «0». Для столбцов со строковыми типами данных параметр «value» не задается. Если параметр «value» не задан для ячеек всех остальных типов, то по столбцам, содержащим такие ячейки, не будет корректно работать сортировка, фильтрация и условное форматирование (см. Приложение 2). Функция возвращает «true» в случае успешного завершения, иначе – «false».
В сообщении написано же, что нужен валидный токен. Необходимо сначала создать бота в телеграме, узнать его токен, вписать его в настройки: файл settings.ini.
Я использую luacheck (по мне самый лучший). В VS Code он не сложно подключается. Но и сами плагины lua для VS Code тоже умеют отлавливать простые ошибки. Если используете всеми любимый Notepad ++, то для него надо искать плагины, поддерживающие проверку синтаксиса. Или запускать в командной строке luacheck с проверяемым скриптом, что, конечно, не так удобно.
Если у Вас не синтаксическая ошибка, а логическая, то, конечно, ошибки не будет при компиляции. Такие ошибки ловятся дебагом. Но для индикатора, лучше делать print-debug. Т.е. выводить значения в некий поток (файл лога) и смотреть на данные.
Типовая ошибка в индикаторах связана с дырявыми массивами данных. Т.е. не заполнены данные для каждого индекса. Если индекса нет, т.е. дырка на графике, это не повод пропустить данные в массиве.
А чтобы Квик не умирал от бесконечного потока сообщений об ошибке, лучше завернуть критическую секцию в pcall и перехватывать текст ошибки, выводя его все один раз для одного и того же сообщения.