Надо делать так, как надо. А как не надо - делать не надо.
Удаление элемента из массива, который прошёл проверку
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
18.04.2021 14:15:12
Цитата
Старатель написал: Вариант 1 неожиданно может дать ошибку
Прошу прощения. Та ошибка касается только ассоциативных массивов. В текущей постановке задачи, когда таблица с целочисленными ключами, можно использовать оба варианта.
Надо делать так, как надо. А как не надо - делать не надо.
Удаление элемента из массива, который прошёл проверку
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
17.04.2021 19:13:06
Цитата
Anton написал: если этот кусок таки окажется атомарным, то от зависания мы не ушли, получается?
О каком "зависании" речь? Функция Claster у меня получается атомарной, но это не точно.
Скрытый текст
Код, демонстрирующий атомарность функции Claster. Пока выполняется цикл в main ни один колбек не вызывается.
Код
local class, sec = "CLASS", "SEC"
local alltrade = {price = 1, qty = 1, class_code = "CLASS", sec_code = "SEC"}
local run = true
function OnStop()
run = nil
end
local Volume = {}
local function Claster(alltrade)
if alltrade.sec_code == sec and alltrade.class_code == class then
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
end
end
local N
function OnInit()
N = 100000000
end
function OnAllTrade()
run = false
end
function OnParam()
run = false
end
function main()
for i = 0, N-1 do
Claster(alltrade)
if not run then break end
end
message(tostring(run) .. '\n' .. Volume[alltrade.price])
end
Цитата
Anton написал: получается, функцию Claster надо намеренно сделать неатомарной? Или я перемудрил уже?
Перемудрил. Зависнуть нам не даст getItem.
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
17.04.2021 17:40:58
Тогда это тоже атомарная операция:
Код
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
И можно не заморачиваться и остановиться варианте
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
17.04.2021 14:42:16
Цитата
Anton написал: Вот так, ежли ничего не упустил опять
Код
if N >= 0 then N = N + 1
Это атомарная операция? Не может получиться такой порядок?
Код
-- N = 0
[OnAllTrade] if N >= 0 then
[main] N = N - 1 --> N = -1
[main] while N >= 0 do --> Выход из цикла
[OnAllTrade] N = N + 1 --> N = 0
Надо делать так, как надо. А как не надо - делать не надо.
Смотря что подразумевать под "подвесит". Сложить два числа и положить в табличку под локом - это одно. А посчитать все накопленные на текущий момент сделки в OnInit - это совсем другое.
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
16.04.2021 22:46:23
Цитата
Anton написал: мейн по событию просыпается и вытаскивает все, чего еще не видел.
Так это понятно, в одном потоке: OnInit + OnAllTrade или main only А так, чтобы от OnAllTrade не отказываться и не подвешивать терминал, если скрипт запущен не в начале дня? В голову приходит только считать объёмы внутри table.ssort
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
16.04.2021 22:16:21
Цитата
Старатель написал: И первичный поиск можно и main делать, чтобы не подвешивать терминал.
Код
local run = true
function OnStop()
run = nil
end
local Volume = {}
local function Claster(alltrade)
if alltrade.sec_code == sec and alltrade.class_code == class then
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
end
end
local N
function OnInit()
N = getNumberOf("all_trades")
end
function OnAllTrade(alltrade)
Claster(alltrade)
end
function main()
for i = 0, N-1 do
Claster(getItem("all_trades", i))
end
while run do sleep(500) end
end
Сразу возник вопрос. Существует ненулевая вероятность неверного расчёта объёмов, если в OnAllTrade и main одновременно будут рассчитываться объёмы по одной цене. Сходу не придумал, как это исключить. Есть идеи?
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
16.04.2021 21:38:17
И первичный поиск можно и main делать, чтобы не подвешивать терминал.
Надо делать так, как надо. А как не надо - делать не надо.
Насколько я понял, ТС интересует простой скрипт, не индикатор.
Цитата
s_mike@rambler.ru написал: в случае запуска на ликвидном инструменте
На скорость поиска влияет не ликвидность инструмента, а количество записей в таблице.
А про SearchItems я написал, как замену цикла
Код
for i = 0, getNumberOf("all_trades")-1 do
при первичном запуске.
Надо делать так, как надо. А как не надо - делать не надо.
Получать объемы сделок
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
16.04.2021 20:07:36
Проще самому написать.
Цитата
Глебов Александр написал: суммарные обновляемые объемы сделок для каждого ценового уровня внутри дня
Как-то так:
Код
local Volume = {}
local function Claster(alltrade)
if alltrade.sec_code == sec and alltrade.class_code == class then
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
end
end
function OnInit()
for i = 0, getNumberOf("all_trades")-1 do
Claster(getItem("all_trades", i))
end
end
function OnAllTrade(alltrade)
Claster(alltrade)
end
Можно SearchItems задействовать для боле быстрого поиска.
Надо делать так, как надо. А как не надо - делать не надо.
Кривые шибки в QLua
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
16.04.2021 10:04:53
QUIK v.8.13.0.106, Lua 5.4
Очередная ошибка
Цитата
attempt to call a nil value (method 'pop')
Скрипт:
Скрытый текст
Код
Queue = {
new = function (self)
return setmetatable({first = 1, last = 0}, {__index = self})
end,
push = function (self, v)
local last = self.last + 1
self[last] = v
self.last = last
return last
end,
pop = function (self)
local first = self.first
if first > self.last then return nil end
local v = self[first]
self.first = first + 1
self[first] = nil
return v
end,
size = function (self)
return self.last - self.first + 1
end
}
local OnAllTra des = Queue:new()
local function f(alltrade)
...
OnAllTrades:push(alltrade)
...
end
function OnAllTrade(alltrade)
... -- Во время ошибки параллельный поток находился где-то здесь
f(alltrade)
end
local run = true
function main()
while run do
...
if OnAllTrades:size() > 0 then
local alltrade = OnAllTrades:pop() -- Тут ошибка "attempt to call a nil value (method 'pop')"
...
end
end
end
Queue работает годами в разных скриптах. И (условно) раз в год (или реже) скрипты ругаются на nil. Было в 7-й или 6-й версии квика. Какое тогда было сообщение об ошибке не помню.
Скрытый текст
И ещё претензия к code highlighter на форуме: в строке 24
Код
local OnAllTra des = Queue:new()
он зачем-то добавляет пробел внутри слова
Надо делать так, как надо. А как не надо - делать не надо.
Ноли в значении тренда в индикаторе
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
15.04.2021 13:05:10
А мужики-то не знали:
Цитата
Евгений написал: Возможно что ошибка только в этом индикаторе
Косяк на большинстве индикаторов. Просто на индикаторах, значения которых сопоставимы с ценой, этого не видно.
Надо делать так, как надо. А как не надо - делать не надо.
Вертикальное масштабирование графика
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
14.04.2021 23:56:54
Цитата
Евгений написал: Как его отключить это авто масштабирование?
Евгений написал: Сделайте возможность отключения автомасштабирования
Оно?
Надо делать так, как надо. А как не надо - делать не надо.
[8.13] регрессия - CreateDataSource возвращает ошибку при запуске после подключения
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
11.04.2021 00:41:22
Цитата
Старатель написал: даже если CreateDataSource, вызванный в момент подключения до OnConnected(), не вернул ошибку, то Size так и останется нулевым.
Цитата
Старатель написал: в предыдущих версиях, просто вместо ошибки возвращалась пустая DataSource.
Вместо тысячи слов:
Скрытый текст
Код
local class = "TQBR"
local sec = "SBER"
local run = true
function OnStop()
run = nil
end
function OnConnected()
message("OnConnected")
end
function main()
while isConnected() ~= 1 and run do sleep(1) end
local ds, err = CreateDataSource(class, sec, INTERVAL_M1)
if ds then
message("OK")
ds:SetEmptyCallback()
else
message(err, 3)
return
end
for i = 1, 1000 do
sleep(600)
if not run then break end
end
message(string.format("size: %u", ds:Size()))
ds:Close()
end
Никто не говорит, что это нормально. Просто факт: отсутствие ошибки ещё не гарантирует удачный заказ графика.
Надо делать так, как надо. А как не надо - делать не надо.
IMOEX - сильные различия формы свечей в quik и tradingview, почему так?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
10.04.2021 10:53:19
Цитата
Roman Azarov написал: Имелась в виду именно разница в показателях свечи. Касательно свечи до начала торгов, проблема изучается.
Именно этот тик до начала торгов рисует Open дневной (и часовых) свечи и влияет на её вид.
Надо делать так, как надо. А как не надо - делать не надо.
[8.13] регрессия - CreateDataSource возвращает ошибку при запуске после подключения
Вы заблуждаетесь. У вас стоит 10-секундное ожидание после подключения, поэтому часть DataSource может быть запрошена уже после OnConnected. Ещё если графики были открыты до запуска скрипта, то DataSource по ним сразу будут иметь ненулевой размер (при наличии свечей, естественно). Вот специально написал демонстрационный скрипт:
Скрытый текст
Код
local run = true
function OnStop()
run = nil
end
function main()
while isConnected() ~= 1 and run do sleep(1) end
local n = 0
local m = 0
local sources = {}
local list = ""
for sec in getClassSecurities(class):gmatch("([^,]+)") do
if not run then break end
local ds, err = CreateDataSource(class, sec, INTERVAL_M1)
if ds then
ds:SetEmptyCallback()
n = n + 1
sources[n] = {ds, sec}
list = list .. sec .. ","
else
message(string.format("Failed to create data source: %s\n%s %s", err, class, sec))
m = m + 1
end
end
message(string.format("OK: %u, ERROR: %u\n%s", n, m, list))
while n > 0 and run do
for i = n, 1, -1 do
local source = sources[i]
local size = source[1]:Size()
if size > 0 then
n = n - 1
message(string.format("%s: %u\n%u", source[2], size, n))
source[1]:Close()
table.remove(sources, i)
end
end
sleep(500)
end
end
Запускаем при установленном соединении - работает нормально.
Если запустить при неустановленном соединении а затем подключиться, то скрипт так и будет висеть в ожидании. Кроме того, если после этого открыть диаграмму с графиком из списка list (если не был открыт до запуска скрипта), то график будет пустой. Свечи появятся только после разрыва соединения.
Проверялось в 8.13 и 8.1
Надо делать так, как надо. А как не надо - делать не надо.
[8.13] регрессия - CreateDataSource возвращает ошибку при запуске после подключения
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
09.04.2021 23:40:57
Просто наблюдение: сначала isConnected() меняется на 1, затем через некоторое время вызывается OnConnected. Если в это время вызвать CreateDataSource, то он завершится неудачей. Есть подозрение, что так было и в предыдущих версиях, просто вместо ошибки возвращалась пустая DataSource. Можете проверить их Size().
Кстати, обнаружилась ещё одна неприятность: В 8.13 даже если CreateDataSource, вызванный в момент подключения до OnConnected(), не вернул ошибку, то Size так и останется нулевым. Suport, обратите внимание.
Надо делать так, как надо. А как не надо - делать не надо.
Использование данных по фьючерсам, вышедшим из обращения
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
09.04.2021 12:20:59
Цитата
Andrey Bezrukov написал: Данное пожелание было реализовано как функционал склейки графиков
Это совсем не то. Это какое-то другое пожелание.
Долго пытался разобраться, как склейку реализовали. В итоге оказалось, что склеить можно только те инструменты, которые остались в открытой ТТТ или других окнах. Если инструмент из таблиц был удалён, то даже при наличии сохранённой истории в dat-архиве склеить невозможно.
Надо делать так, как надо. А как не надо - делать не надо.
Использование данных по фьючерсам, вышедшим из обращения
Если я правильно понимаю, как работает терминал, то главная проблема именно в исключении необращающихся фьючерсов из списка доступных инструментов. Технически данные графика содержатся в папке архива. Но даже при их нахождении там, в файле, содержащем перечень доступных инструментов после подключении к актуальной сессии идентификаторы и внутренние ссылки исчезают. Было бы очень хорошо, если бы появился такой функционал: в панель выбора инструмента добавить еще один раздел "Архив", в котором и появлялись бы те инструменты, срок обращения которых истек, но данные по которым для терминала доступны.
Цитата
Zoya Skvorcova написал: Ваше пожелание было реализовано в версии 7.18.1 терминала QUIK.
Где же это всё?
Надо делать так, как надо. А как не надо - делать не надо.
IMOEX - сильные различия формы свечей в quik и tradingview, почему так?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
09.04.2021 09:05:40
Цитата
Roman Azarov написал: Выполните, пожалуйста, перезаказ архива данных для построения графиков.
Результат тот же: на графиках индексов присутствует левый , значение которого равно закрытию предыдущего дня.
Цитата
Roman Azarov написал: У себя дневную свечку по IMOEX за 15.03.21 видим вот так:
А на М4? Это где у себя? Я не вижу индексов на вашем Junior
Надо делать так, как надо. А как не надо - делать не надо.
Неверная дата и время, Стандартные функции Lua возвращают неверное время сервера
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.04.2021 08:48:22
Цитата
sysdate
Функция возвращает системные дату и время с точностью до микросекунд.
Цитата
Roman Azarov написал: Данное поведение обусловлено, дополнительным вызовом функции конвертации, в которой происходит округление миллисекунд, в os.sysdate().
Это как? Что во что конвертируется и по каким правилам округляется?
Надо делать так, как надо. А как не надо - делать не надо.
Если не считать злоупотребление метками вкупе с пробелами по темам типов и области видимости переменных. Но дискутировать на эту тему у меня нет ни малейшего желания. Мне по барабану будете ли вы искать ошибку.
Надо делать так, как надо. А как не надо - делать не надо.
[BUG] Пропадает текст в таблицах
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
07.04.2021 16:52:52
Владимир, учитывая ваш стиль программирования, это наиболее вероятная причина.
Надо делать так, как надо. А как не надо - делать не надо.
[BUG] Пропадает текст в таблицах
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
07.04.2021 14:32:51
Или так, чтобы не пропустить ошибку:
Код
local SetColor_ = SetColor
function SetColor(t_id, row, col, b_color, f_color, sel_b_color, sel_f_color)
if row == -1 and col == -1 and (b_color == -1 or f_color == -1 or sel_b_color == -1 or sel_f_color == -1) then
message(debug.traceback(), 3)
end
return SetColor_(t_id, row, col, b_color, f_color, sel_b_color, sel_f_color)
end
Надо делать так, как надо. А как не надо - делать не надо.
Можете сделать проверку передаваемых параметров в SetColor, например, так:
Код
local SetColor_ = SetColor
function SetColor(t_id, row, col, b_color, f_color, sel_b_color, sel_f_color)
if row == -1 and col == -1 and (b_color == -1 or f_color == -1 or sel_b_color == -1 or sel_f_color == -1) then
message(debug.traceback(), 3)
return nil
else
return SetColor_(t_id, row, col, b_color, f_color, sel_b_color, sel_f_color)
end
end
Надо делать так, как надо. А как не надо - делать не надо.
Несчастное окно
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
07.04.2021 08:30:18
Цитата
Roman Azarov написал: Правильно понимаем, что под пустым полем Вы имеете в виду самую правую колонку таблички "Загруженные скрипты"?
Правильно.
Цитата
Roman Azarov написал: при каких условиях (в какой версии терминала) окно открывается с пустым полем?
8.13. При открытии окна или запуске QUIK, если оно было открыто раннее.
Скрытый текст
Надо делать так, как надо. А как не надо - делать не надо.
IMOEX - сильные различия формы свечей в quik и tradingview, почему так?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
06.04.2021 23:18:52
Для сравнения как выглядит дневной график в QUIK и на официальном сайте биржи:
Многие другие индексы также кривые в квике.
Скрытый текст
Индекс МосБиржи (Дополнительная сессия) в QUIK и на сайте биржи
Это не считая объёмов, которые в QUIK показывают не пойми что.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: При активном окне "Доступные скрипты" не работают никакие горячие клавиши.
Надо делать так, как надо. А как не надо - делать не надо.
Несчастное окно
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
05.04.2021 14:42:07
Цитата
Старатель написал: сделать, чтобы окно сохраняло ширину колонок в списке скриптов
Или хотя бы убрать это пустое поле при открытии окна. Уже будет "прогресс" Как на скрине в руководстве QLua:
Надо делать так, как надо. А как не надо - делать не надо.
Несчастное окно
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
05.04.2021 00:23:49
Такое ощущение, что дизайн этого окна отдали на аутсорс школьникам. Что надо сделать, чтобы окно сохраняло свои координаты (при закрытии и повторном открытии) и ширину колонок в списке скриптов?
Надо делать так, как надо. А как не надо - делать не надо.
IMOEX - сильные различия формы свечей в quik и tradingview, почему так?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
02.04.2021 14:53:34
Любой брокер. Любая версия до текущей (8.13) Только время первой свечи будет отличаться у разных брокеров. Походу, это время запуска шлюзов. Теперь понятно, почему на дневках Open всегда равен Close предыдущего дня.
Надо делать так, как надо. А как не надо - делать не надо.
IMOEX - сильные различия формы свечей в quik и tradingview, почему так?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
02.04.2021 14:42:14
Откуда на графике индекса свеча в пять утра?
Надо делать так, как надо. А как не надо - делать не надо.
Таблица состояние счета, закрытие позиции., Ошибка 167.
Кто сказал? Возможно, и пригодилось бы для какой-то задачи... Просто показал вам, что "актуальность значения параметра" понятие относительное, особенно на неликвиде. И хотел уточнить, каким образом
Цитата
Артем написал: Наличие такого поля позволит оценить актуальность значения параметра
Надо делать так, как надо. А как не надо - делать не надо.
Добавить в вывод GetParamEx() поле с указанием времени последнего обновления
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
28.03.2021 15:01:11
Артем, ещё есть мнение, что вы также не понимаете, как будете использовать параметр время, о котором просите. Допустим, GetParamEx() для параметра P у бумаги ABC вернет "время последнего обновления" 14:50, а у бумаги XYZ для того же параметра - 12:34. Как вы собираетесь применять эту информацию?
Надо делать так, как надо. А как не надо - делать не надо.
QUIK не отправляет заявку, в которой цена представлена переменной
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
25.03.2021 15:11:09
Цитата
Старатель написал: 1) Если работаем только с целыми, перед арифметикой преобразуем все операнды в int
Забыл добавить: это относится именно к целочисленным операциям, таким как сложение, вычитание, умножение. И после вычислений - просто tostring.
Цитата
Артем написал: tostring ( ) это стандартная функция Lua
tostring как раз лишних нулей не дописывает, можете смело пользоваться. Если у вас int, то и tostring вернёт строку без точки.
написал: Тут не надо ничё предполагать. Операции сложении и умножения над целыми числами, как в данном конкретном примере, не влекут потерю точности.
Шаг цены бывает например 0.1 и тут будут проблемы.
Речь про целые числа. Для дробных шагов - округление с точностью шага цены и
Цитата
Старатель написал: 2) На вход в sendTransaction подаём отформатированную строку, с учётом количества знаков.
Надо делать так, как надо. А как не надо - делать не надо.
QUIK не отправляет заявку, в которой цена представлена переменной
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
25.03.2021 13:05:40
Цитата
swerg написал: неужели до сих пор нельзя сделать так, чтобы параметр Transaction["PRICE"] можно было задавать числом, а не строкой?
Давно можно было, если кто не знал. Но QUIK всё одно преобразует аргумент в строку по своему усмотрению. А считает он, что надо 6 знаков после запятой, не меньше. И плевать он хотел на точность шага.
Тут не надо ничё предполагать. Операции сложении и умножения над целыми числами, как в данном конкретном примере, не влекут потерю точности. А поскольку getParamEx отдаёт всегда сырые данные во float, а sendTransaction принимает строго с точность шага цены, то варианта тут два: 1) Если работаем только с целыми, перед арифметикой преобразуем все операнды в int либо 2) На вход в sendTransaction подаём отформатированную строку, с учётом количества знаков.
Надо делать так, как надо. А как не надо - делать не надо.