Здесь вынужден согласиться, есть много других задач. Встроенные индикаторы на самом последнем месте по приоритетам. Работают и ладно. Внешние индикаторы даже выше по приоритету, чем встроенные.
Илья написал: Хотел сделать через замыкание, но, опять же, где хранить этот объект?
Если речь про хранение между запусками, то во внешнем мире к терминалу. Или, понимая, что вызовов будет не меньше двух, организовать кеш данных, рассчитанных на первом проходе (после применения настроек). Тогда последующий вызов будет "холостым". Тогда можно будет организовать расчет только один раз. Иногда это существенно ускоряет вывод индикатора на график.
Это такое поведение. Скорее баг, но ему уже лет 10. На графиках с очень большим число баров или на очень сложных "жадных" алгоритмах надо быть аккуратным.
Не думаю, что будут заметный эффект. Результат выполнения функции pairs есть функция next и t. Т.е. это просто синтаксический сахар, и это описано в книге по языку. Минус один вызов, да.
Херня это все У вас очередь - это массив. Если в массиве хранятся числа, то для них не отводится дополнительной памяти. Но даже если Вы храните указатель, то сам элемент массива останется в памяти. Запись nil - это запись 0 в тип элемента массива. Элементы массива никуда не денутся пока Вы не уничтожите весь массив путем записи nil в его имя. а не в его элементы.
Для текущей задачи, когда постоянно происходить увеличение числа элементов массива, в конечном итоге будет произведен shrink таблицы. As a consequence, if you traverse a table erasing all its fields (that is, setting them all to nil), the table does not shrink. However, if you insert some new elements, then eventually the table will have to resize. Usually this is not a problem: if you keep erasing elements and inserting new ones (as is typical in many programs), the table size remains stable. However, you should not expect to recover memory by erasing the fields of a large table: It is better to free the table itself.
Но также там описан и грязный трюк по очистке. Kогда очень надо, то можно и воспользоваться.
Я не могу ничего ответить по показанной структуре, т.к. я не понимаю задачи. Например, зачем хранить данные баров, если они прекрасно получаются? Можно предположить, что для более быстрого расчета индикатора, но и здесь вопрос, т.к. сам алгоритм индикатора может хранить все, что ему надо, контролируя объем хранимых данных.
В тех же примерах от разработчиков так и сделано. Есть экземпляр метода расчета, полученный через замыкание, хранящий все, что ему надо. Задача просто вызвать его для каждого бара, передав номер этого бара. Прогнали на истории, а далее только при поступлении нового бара. И этот экземпляр расчета будет хранить данных столько, сколько надо для расчета и не более. Конечно, можно хранить данные начиная с индекса 1, но зачем, если для расчета надо всего три.
Владимир написал: Nikolay, Чтобы буферизовать пиковые нагрузки. Забиваются по ситуации, а разгребаются спокойно по таймеру.
Да, но речь про расчет индикатора, с частотой максимум раз в 1 минуту. Если, конечно, самому не строить поток данных с меньшим интервалом, чего явно нет, раз используется DS. даже если 100 сотня тикеров и десять индикаторов, то это не столь критично.
Пробежался и так не понял в чем проблема, и причем здесь очередь. Озвучена проблема роста памяти при расчете индикаторов. Ок. Но для расчета индикаторов нужен банальный массив. Тупо для каждого индекса бара от 1 храним какое-то значение. Пришел новый бар - записали данные по его индексу. Все. Но такой вариант - это постоянное увеличение хранимых данных. Что можно сделать? Банально очищать неиспользуемые данные, присваивая nil. Правда помня, что перестанет работать #. Но это решается очень просто. Сложнее - можно сделать массив фиксированного размера и записывать данные по кольцу. Так сделали разработчики терминала в последней версии примеров расчета индикаторов. Что это дает - объем занимаемой постоянен и контролируем.
Зачем здесь очереди, стеки и др. списки - не ясно.
Погрузитесь в крайнюю степень использования _ENV и все на чистом Lua. Правда не ясно зачем, но, как говорится, красиво.
А по теме, я уже написал Вам, что стоит изучить вопрос коллекций как таковых. Чтобы не было вопросов где очереди, где стек, где дерево и т.д. Для каждой задачи будет что-то свое.
Ну ведь можно local A={} value = A[varname] В двойной очереди он этот прием демонстрирует.
Все будет зависеть где будет объявлена переменная А. А так, конечно, можно. Но при этом надо не забывать, что эта А не будет видна в других файлах.А если нужна видимость, то чаще всего и решают это через глобальный контекст, что приемлимо, но значит, что это правильно. Хотя это субъективное понятие, конечно. Работает, устраивает, только для себя - значит правильно.
VPM написал: Nikolay, Ну первый вопрос зачем лезть в глобальное окружение, я видел у Вас такой прием?
Это более сложный вопрос. Чаще всего с ним и работают, что вполне нормально для небольшого скрипта, выполняющего простые действия. А если скрипт - это десятки файлов и много строк, то так уже лучше не делать. Причина банальна - очень легко допустить ошибку, переписав значение какой-то переменной. В этом плане, как я считаю, в Lua все должно быть наоборот - переменные должны быть локальными по смыслу, с блочной областью видимости. А глобальные создаваться специальным образом. Но как есть, так есть.
Поэтому я не использую глобальный контекст. Но его приходится использовать, если это методы и переменные из Qlua. Разработчики терминала все поместили в глобальный контекст. Поэтому и приходится к нему обращаться. А для того чтобы это визуально различать и чтобы linter не выдавал ошибки, пишется _G, не более. Если бы интерфейс qlua был в библиотеке, например qlua, то было бы все лаконичней. Подключил библиотеку - получил методы и контекст терминала.
VPM написал: Вот поднята тема, которая требует пояснений, есть две записи:
1) value = loadstring("return " .. varname)() 2) value = _G[varname] -- в десятки раз эффективнее
А в чем здесь вопрос? Первое это кодогенерация из произвольной строки. Второе прямое обращение к переменной. Естественно, что первое - это медленно, т.к. необходимо строку подготовить, скомпилировать текст в анонимную функцию и выполнить ее.
Я Вам советую изучить вопрос структур данных. Не в применении к языку Lua, а в общем. Языки разные, концепции одинаковые. Тогда у Вас отпадут многие вопросы по организации хранения, исполнения и т.д. Форум это, конечно, хорошо, но фундаментальные знания получаются в библиотеке.
Да, DS - это таблица (класс) (в LUA всё таблицы), но там только методы и недокументированные переменные. Сами данные получаются через эти методы.
Что касается организации замыкания, то я никогда не понимал зачем в учебных примерах, предоставляемых ARQA, настройки и DS передаются в метод расчета на каждой итерации. Когда более логично их передать один раз при вызове конструктора экземпляра. Они будут запомнены через upvalue и никуда не денутся. Сам метод расчета требует только индекс бара (и что еще, если алгоритм требует), и не более.
Зачем здесь очередь? Какую задачу надо решить, что нужна именно очередь? Нужен простой массив или кольцевой буфер (что тоже массив). И как сам DS влияет на занимаемую память? DS ничего не хранит - это интерфейс к данным, а не сами данные, и поэтому один тот же DS, одного и того же инструмента, можно использовать в различных расчетах.
Я, кажется, уже писал Вам, что почти все индикаторы не требую хранения данных более чем период расчета. А у еще большего числа индикаторов таки вообще достаточно хранения данных на прошлой итерации, как, например, у EMA. Поэтому, для начала, просто произведите оптимизацию расчетов. Большинство примеров из просторов глобальной помойки, совершенно не заботятся о том, что баров может быть под 60 тыс, и экземпляров расчета от 100 и более.
Какое-то странное обсуждение. Если это оперативные данные, то, чаще всего, их не так и много, если, конечно, это не данные модели, которые лучше в памяти держать. Думаю, что здесь задача тривиальная - хранить какие-то простые данные для работы скрипта. И уж как организовать их хранение не столь важно, важно, чтобы они было доступны, просто получаемые, без лишних поисков.
А обезличенные сделки - зачем их держать в памяти? Прочитал партию - записал в файл, базу данных, передал в socket. Все, забыли. Либо произвели агрегацию, вычисления и храним только данные расчета, сами-то ВСЕ сделки зачем хранить.
Думается, что это проблема выбора реляционной базы для хранения данных (правда мой опыт обработки всех сделок, всех акций за 2016 год на MsSQL не вызывал каких-то проблем, кроме объема, но это год). Хотя организовать порционную подачу данных вполне можно. Заказали - начинают поступать данные. Если же сделано, что сначала все данные подготавливаются, кешируются и только потом выдаются всем объемом, то, наверно, это и приводит к таким задержкам. Плюс, видимо, у таких данных очень низкий приоритет, так что не во все пакеты попадают.
Вы очереди перебираете в цикле, цикл идет с какой то определенной задержкой на исполнение.
Корутины имеют накладные расходы. Внимательно посмотрите на код решения, что Вы используете, и Вы увидите там точно такой же цикл опрашивающий корутины. Что касается быстрых и медленных задач, то они реализуются одинаково. У них разное время выполнения, поэтому одна завершится быстро, другая будет долго выполняться, а какая-то будет вообще всегда работать. Техническая же реализация - это в одном случае Вы их заворачиваете в корутину через wrap, а в другом реализуете более сложный объект, точно так же хранящий свое состояние. А уже какая будет скорость работы самого этого объекта, корутины - сами и определяете. Я не вижу никакого смысла добавлять какие-то задержки в исполнение, что в одном случае, что в другом. Также как и нет никакого смысла перебирать объекты, корутины с задержкой. Единственная задержка добавляется в бесконечный цикл в main, и то, потому что иначе Квик зависнет. Вот и вся разница. Используйте, никто не мешает. Но не надо говорить о многопоточности, многозадачности и т.д.
VPM написал: Нет нельзя, это две задачи исполняемые с разными скоростями. В моем примере функция Trade() имеет свой внутренний цикл без всяких ограничений.
Скорости здесь ни причем. Раз сделано так в этом решении, не значит что так нельзя сделать. Я вместо корутин использую очереди задач и переход от одной к другой, управляя этим. Надо в одной задаче подождать дольше - идем дальше. Можно было бы сделать через корутины - да. Но в моем случае проще сделать иначе. Корутины же хороши в качестве генераторов для итераторов, да.
Странное обсуждение. Корутины в lua - это синхронные вытесняющие сопрограммы. Т.е. никакой многопоточности здесь нет. Если бы была, то пришлось бы в язык вводить многие другие элементы, отвечающие за синхронизацию. А так - это просто такая методика замыкания состояния окружения функции. И все это можно воспроизвести на обычном цикле, опрашивая методы-объекты: готово - выполни это, нет - ждем дальше. Они удобны - да, но сказать, что без них нельзя - нет.
Подниму тему. Необходимо получить данные по календарным спредам. Набор параметров для них хоть и близок, но другой. Для примера, две даты эксприации. Но вот незадача - у меня нет Excel и нет желания его устанавливать. Тем более, что он платный. Украсть просьба не предлагать. А получить иначе набор параметров Вы не предлагаете. Собственно вопрос: как быть? Я воспользуюсь, конечно, библиотеками, соберу DDE сервер. Но это не решение вопроса. Неужели так сложно обновлять информацию в документации? У Вас теперь релизы терминала выходят чаще, чем этот набор параметров изменяется. И я банально не понимаю причины, почему это не делается.
Раз уже здесь писали об ошибках потоков... Поймал ошибку, видимо ошибка потоков. Версия 11.0.0.92, lua 5.4
Обрыв связи, восстановление. Заново приходят все коллбеки с начала сессии до момента разрыва связи (здесь сразу вопрос - как бы это отключить?). В этот момент алгоритм находиться в цикле, перебирая некую таблицу. По логу вижу, что есть сообщение колбека, есть сообщения из цикла. И в какой-то момент цикл разрушается - получает данные из другой области памяти. Итеративная переменная 10, а получены данные по индексу 20, например. Или еще хуже - получены данные из совсем другой таблицы.
Воспроизвести не могу, но явно что-то случилось с стеком, при работе двух потоков.
Это одновременно и простой и сложный вопрос. Таблицы в луа это ссылочный объект. Т.е. запись my_array ={} создает новый объект - объявляет и инициализирует. В переменной будет новая ссылка, а старая безвозвратно утеряна, и очищена сборщиком мусора, если на нее не было больше ссылок.
Поэтому, если вопрос: как очистить существующий объект, то ответ - пройтись циклом и присвоить nil для ключей, индексов.А запись my_array ={} "как бы" очищает, да. Но при этом будет новая ссылка и если есть блоки кода, хранящие ссылку на my_array, то они не увидят новую, без повторного присвоения.
Проверьте все задаваемые параметры в документации или здесь https://luaq.ru/AddLabel.html Например, нет такого параметра datetime. Также имена параметров регистрозависимые.
Как показывает история, программисты сами себе не делают Продукт, а делают костыли. Чтобы сделать продукт одних программистом мало. А капитализация не имеет никакого отношения к этому. Есть компании с огромной капитализацией, но польза от них ничтожна.
VPM написал: Поставил уже на верно лет 20 назад (когда там 5.1 вышло), накидал разного сервиса и забыл как лезть в него.
Ну это дело такое - когда-то turbo pascal был чудесен. Или, для примера, Emacs, как среда разработки, - великолепна. И до сих пор великолепна. Так что SciTE - это такой же новодел как VSCode.
Цитата
luac54.exe -o "*.luac" "*.lua"
А лучше добавить параметр -s. Правда если цель - писать скрипты для себя и только для себя, то зачем вообще компилировать. Квик это сам сделает перед запуском.
Кошек надо просто уметь готовить. VSCode - это просто среда. Все компилируется в терминале скриптами, самим же lua (или любым другим bash). Зачем для этого редактор - не ясно. SciTE хорош, но, для примера, ZeroBrane Studio (по моему мнению) - лучше. Но она не умеет win1251. Также советую проверить какую команду выдает SciTE для компиляции. Скорее всего без -s, что оставит отладочную информацию и позволит декомпилировать код, если он компилировался в чистом виде.
Хотя не знаю может в lua 5.4 не уже ограничения по количеству локальных переменных, но решил Вам оставить сообщение, сам не разбирался.
В lua 5.1 в исходном файле luaconf.h переменная LUAI_MAXUPVALUES = 60. Хотя можно увеличить до 250 и скомпилировать свою dll. Хотя Квик и не даст с ней работать. В lua 5.3 кажется увеличили это число. Было бы конечно хорошо, если бы OnCalculate давал возможность работать с таблицей, а не конкретными значениями, или как-то иначе задавать значения линий. Иначе большое число линий вызывает проблемы.
Видимо Вы просто не разу не пытались заказывать данные по инстурменту, который у Вас не открыт в Квике.
Нормальный терминал - это тот, где нет ни одного графика, может только таблицы, для оценки взглядом цифр. Все делает сам скрипт. Так что это нормальная практика - заказать данные, рассчитать все данные, принять решения. SetUpdateCallback - очень неудобный колбек с точки зрения использования.
Во-первых, он вызывается на каждое изменение цены, даже внутри одного и того же бара. Если это необходимо отслеживать, то есть более удобные способы. А если не надо, то проще самому обрабатывать данные, реагировать только если Size потока изменился. Во-вторых, после заказа данных, он будет вызван для всех баров, начиная от 1. И опять - это проще сделать самому, перебрав данные в цикле. Ну и, наконец, - он медленный.
Anton Belonogov написал: Для получения информации о наличии спроса или предложения по инструменту рекомендуем проверять значения параметров "Суммарный спрос" (biddeptht) / "Суммарное предложение" (offerdeptht).
В теории да. Но меня прямо коробит (без обид) такая запись. Переменная ds глобальная, объявляется где-то там. В первом варианте анонимная функция хотя бы видит ее как up-value, а во втором - вся надежда на то, что она объявлена и инициализирована.
Станислав написал: Больше двух лет не запускал своего робота и возникла в нем необходимость. При отображении таблиц робота вместо русских блов отображаются непонятные символы (СКИРН). Как исправить проблему?
Ничего с начала времен не изменилось - кодировка до сих пор ANSI win1251
Kolossi написал: Полагаю что при получении нуля по одному из двух параметров просто проверяется второй и его ненулевое значение однозначно говорит о том, что данные получены.
Да, но хотелось бы без бубна. Раз нулевые цены есть, значит значение 0, везде где это допустимо, должно быть таким же значимым. Это, кстати, также относится к параметру LAST, который после клиринга очень часто принимает значение 0.
Такая запись установит nil по индексу, а значит сборщик мусора освободит память. Но такая запись не позволит использовать типовой метод #. Так что, если # необходимо, то либо использовать другие методы оптимизации, либо переопределить метаметод __len.
На примере массива Price, т.к. я вижу где он используется. Значения дальше P-1 уже не нужны. Поэтому вполне можно написать Price[index - P - 1] = nil. Хотя алгоритм поиска экстремума за период иногда проще делать иначе, через unpack. (Правда для малых P - это не существенно).
Иногда проще не создавать массивы, а просто ввести переменные, постоянно изменяя значения. На примере той же EMA, если не надо иметь данные дальше чем прошлое значение, то достаточно ввести переменную, отвечающую за прошлое значение EMA, вместо массива.
Очередь - это просто такой массив, абстракция, не более. Вопрос применения. Где-то они необходимы, а где-то не нужны. И так для каждой сущности, для каждой задачи выбирается оптимальное решение.
VPM написал: Мы один раз продумали структуру данных, а дальше через присвоение пользуемся - "по образу и подобию", не задумываясь почему там таблица не обновилась, где ты там забыл переменную локализовать, + "синтаксический сахар". Это просто удобно при использовании портфеля из бумаг.
Это, конечно, так. В теории. Если объект действительно детерминирован. Но, как обычно, примеры ООП из кошек, собак, животных - это просто примеры. Но это также не отменяет простого подхода через вызов метода, возвращающего готовую структуру. Тоже вызвал, получил экземпляр нового объекта.
Есть два параметра таблицы текущих торгов - BID, OFFER. Вопрос разработчикам - правильно ли я понимаю, что при отсутствии с одной из сторон данных (планка) будет возвращен 0 в качестве значения? Либо result будет "0", сообщающий, что данные не получены? Если просто 0, то как тогда это соотносится с возможностью нулевых цен для части инструментов. Не хотелось бы опрашивать стакан для такой простой задачи
VPM написал: Область видимости это как минимум 3 блока, если записать так
Причем здесь три блока, и почему три? Область видимости - это конкретное определение. Это может быть весь контекст файла, может быть функция, может область do end, цикл и др. Каждый раз - это конкретный пример, и нет магического значения числа блоков. В книге автора языка есть целый раздел посвященный локальным переменным.
Цитата
Код
do
local a = 1
end
то она не очистится, получается так?
Очиститься, а точнее, цитируя: "локальная переменная перестает существовать, как только заканчивается ее область видимости, позволяя сборщику мусора освободить память, занимаемую ее значением". Блок же закончился. И в вышеупомянутой книге - это описывается.