Хочу получать суммарные обновляемые объемы сделок для каждого ценового уровня внутри дня, чтобы затем выводить их в обновляемую таблицу. Возможно ли это реализовать в QLUA? Какие есть варианты решения для начинающего?
s_mike@rambler.ru, 1. Вы что, предполагаете самостоятельно разработать и графическую библиотеку? Если нет, то сложность представления данных в виде таблицы или графика ОДНОГО порядка. 2. Нет там ответа на его вопрос, ибо совершено очевидно, что вся тамошняя хрень написана НЕ на Lua.
Владимир написал: s_mike@rambler.ru, 1. Вы что, предполагаете самостоятельно разработать и графическую библиотеку? Если нет, то сложность представления данных в виде таблицы или графика ОДНОГО порядка. 2. Нет там ответа на его вопрос, ибо совершено очевидно, что вся тамошняя хрень написана НЕ на Lua.
s_mike@rambler.ru, Вот уж АБСОЛЮТНО до лампочки! Достаточно взглянуть в начало текста: Версия:5.05 Требования:Quik 8.6 Размер:1.57 MB и любому дебилу ясно, что это никак не Lua.
Достаточно взглянуть в конец: Адаптировано для работы с библиотекой bot4sale.dll и любому дебилу...
Владимир написал: s_mike@rambler.ru, Вот уж АБСОЛЮТНО до лампочки! Достаточно взглянуть в начало текста: Версия:5.05 Требования:Quik 8.6 Размер:1.57 MB и любому дебилу ясно, что это никак не Lua.
Достаточно взглянуть в конец: Адаптировано для работы с библиотекой bot4sale.dll и любому дебилу...
прекрасно.
как вы замечательно про дебила-то... Сами, никто за язык не тянул.
скрипт этот я написал как раз на луа. Это чистый незамутненнвй луа, который просто помещен в контейнер.
s_mike@rambler.ru, ЭТО Я, дорогой, "скрипт написал как раз на луа". И объём его в сто раз меньше (точнее, в 86,.79 раза) и обслуживает он не какой-то сраный график, а весь мой портфель по всем параметрам, включая индикацию и торговлю, и ему насрать и на версию Квика, и на версию Lua, и на "адаптацию для работы с библиотекой bot4sale.dll", равно как и со всеми другими библиотеками. Именно потому, что это "чистый незамутненный луа".
s_mike@rambler.ru написал: Вот такой вариант. Но не в таблицу выводит, а рисует на графике.
Знакомо.Неинтересно.
вывести результаты в таблицу на порядок (или на два порядка) проще, чем нарисовать все эти уровни и на графике.
Поэтому ответ на ваш вопрос о возможности реализации на lua имеет вполне себе утвердительный ответ.
А в чем конкретно состоит ответ на мой вопрос, кроме "посмотреть на Ваш график", а мне нужны данные для дальнейшей обработки?
если вам хочется обрабатывать результаты, можно просто читать базу соответствующего дня и получать в луа сразу готовую таблицу с разблюдовкой по ценам сделок. Базы лежат в виде отдельных файлов в текстовом виде в формате языка луа.
s_mike@rambler.ru написал: Вот такой вариант. Но не в таблицу выводит, а рисует на графике.
Знакомо.Неинтересно.
вывести результаты в таблицу на порядок (или на два порядка) проще, чем нарисовать все эти уровни и на графике.
Поэтому ответ на ваш вопрос о возможности реализации на lua имеет вполне себе утвердительный ответ.
А в чем конкретно состоит ответ на мой вопрос, кроме "посмотреть на Ваш график", а мне нужны данные для дальнейшей обработки?
если вам хочется обрабатывать результаты, можно просто читать базу соответствующего дня и получать в луа сразу готовую таблицу с разблюдовкой по ценам сделок. Базы лежат в виде отдельных файлов в текстовом виде в формате языка луа.
Ну, собственно, это я и пытаюсь выяснить - какими средствами QLUA можно читать базу текущего дня и получать готовую таблицу?
s_mike@rambler.ru написал: Вот такой вариант. Но не в таблицу выводит, а рисует на графике.
Знакомо.Неинтересно.
вывести результаты в таблицу на порядок (или на два порядка) проще, чем нарисовать все эти уровни и на графике.
Поэтому ответ на ваш вопрос о возможности реализации на lua имеет вполне себе утвердительный ответ.
А в чем конкретно состоит ответ на мой вопрос, кроме "посмотреть на Ваш график", а мне нужны данные для дальнейшей обработки?
если вам хочется обрабатывать результаты, можно просто читать базу соответствующего дня и получать в луа сразу готовую таблицу с разблюдовкой по ценам сделок. Базы лежат в виде отдельных файлов в текстовом виде в формате языка луа.
Ну, собственно, это я и пытаюсь выяснить - какими средствами QLUA можно читать базу текущего дня и получать готовую таблицу?
Вот такой функцией читают файлы базы индикатор из архива, ссылку на который я писал выше
Код
-----------------------------------------------------------------------------------------------------------------------------------
-- Чтение таблицы из файла в массива или таблицу. Вырезает сигнатуру из файла
-- Параметры:
-- Имя файла
-- Функция декодирования (или nil)
-- Возвращает:
-- Таблицу или nil
-- Сообщение об ошибке или nil
-- Полное имя читаемого файла
ifuse(`table',`read',`
function table.read(filename,decode)
m4_assert(type(filename) == "string","Вместо строки передано (" .. type(filename) .. ") " .. tostring(filename))
m4_assert(type(decode) == "function" or decode == nil,"Вместо функции или nil передано (" .. type(decode) .. ") " .. tostring(decode))
filename = io.makepath(filename,".dat")
local result
local f,status = io.open(filename,"r")
if f then
local str = f:read("*a")
f:close()
local _,_,s = string.find(str,"^%-%-%s.*%s%-%-\n(.*)$")
str = s or str
if decode then
str = decode(str)
end
status,result = pcall(loadstring("return " .. str))
if status then
status = nil
else
status = "Файл поврежден" ifdef(`DEBUG',`.. ": " .. result')
result = nil
end
end
return result,status,filename
end
')
тут есть немного того, что вам не потребуется (инструкции препроцессора, декодирование), просто выкиньте это лишнее.
Таблица в файле содержит две подтаблицы. [1] это общие итоги по дню [2] это таблица данных по каждой торговой цене дня
Последовательность полей
Код
dnl Общие данные за день
pushdef(`COUNTER', 0) dnl Поля в разделе DAT_TOTALS
define(`TOTAL_VOLUME_BUY', m4_inc(`COUNTER')) dnl Объём покупок за день
define(`TOTAL_VOLUME_SELL', m4_inc(`COUNTER')) dnl Объём продаж за день
define(`TOTAL_VOLUME', m4_inc(`COUNTER')) dnl Объём за день
define(`TOTAL_MAXVOLUME', m4_inc(`COUNTER')) dnl Максимальный объём, прошедший по какой-либо цене за день
define(`TOTAL_TRADES_BUY', m4_inc(`COUNTER'))
define(`TOTAL_TRADES_SELL', m4_inc(`COUNTER'))
define(`TOTAL_TRADES', m4_inc(`COUNTER'))
define(`TOTAL_MAXTRADES', m4_inc(`COUNTER')) dnl Максимальное кол-во сделок, прошедших по какой-либо цене за день
define(`TOTAL_MINPRICE', m4_inc(`COUNTER')) dnl Минимальная цена дня
define(`TOTAL_MAXPRICE', m4_inc(`COUNTER')) dnl Максимальная цена дня
define(`TOTAL_TABLE_SIZE', COUNTER) dnl Размер таблицы total
popdef(`COUNTER')
Код
dnl Структура данных по конкретной цене
pushdef(`COUNTER', 0) dnl Поля в разделе DAT_DATA
define(`VOLUME_BUY', m4_inc(`COUNTER'))
define(`VOLUME_SELL', m4_inc(`COUNTER'))
define(`TRADES_BUY', m4_inc(`COUNTER'))
define(`TRADES_SELL', m4_inc(`COUNTER'))
define(`VOLUME_BS', m4_inc(`COUNTER'))
define(`TRADES_BS', m4_inc(`COUNTER'))
define(`PRICE_TABLE_SIZE', COUNTER) dnl Размер таблицы по одной конкретной цене
popdef(`COUNTER')
Глебов Александр написал: суммарные обновляемые объемы сделок для каждого ценового уровня внутри дня
Как-то так:
Код
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 задействовать для боле быстрого поиска.
Надо делать так, как надо. А как не надо - делать не надо.
Глебов Александр написал: суммарные обновляемые объемы сделок для каждого ценового уровня внутри дня
Как-то так:
Код
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 задействовать для боле быстрого поиска.
можно. Но в этом случае индикатор будет подвешивать терминал в случае запуска на ликвидном инструменте ближе к концу торговой сессии. А если таких индикаторов будет несколько - терминал умрет.
Старатель, Насколько вижу, в таблице "all_trades" все записи идут вперемешку, Так на кой ковыряться ТАМ? снимать время от времени очередную порцию от i1 до i2 - и считай что хошь У СЕБЯ! Какой там размер этой таблицы? Сколько миллионов строк?
Старатель написал: И первичный поиск можно и 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 одновременно будут рассчитываться объёмы по одной цене. Сходу не придумал, как это исключить. Есть идеи?
Надо делать так, как надо. А как не надо - делать не надо.
Я в колбеке ставлю событие и все, мейн по событию просыпается и вытаскивает все, чего еще не видел. Но это в длл, в луа не знаю, как без внешних сей засинхронизировать.
Anton написал: мейн по событию просыпается и вытаскивает все, чего еще не видел.
Так это понятно, в одном потоке: OnInit + OnAllTrade или main only А так, чтобы от OnAllTrade не отказываться и не подвешивать терминал, если скрипт запущен не в начале дня? В голову приходит только считать объёмы внутри table.ssort
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: считать объёмы внутри table.ssort
А оно ведь тоже подвесит на первом же колбеке?
Была бы интересна функция вида
Код
VOID OnAllTrade2(INTEGER row_index)
В ней можно было бы либо внутри достать новую строку (и все пропущенные, если таковые есть), либо переправить индекс в мейн и достать там. Но был бы недостаток: существование записи по этому индексу в момент попытки ее достать уже не гарантируется, т.е. можно и нил получить. Хотя это можно было бы явно оговорить в документации, не то чтобы проблема большая.
Старатель написал: считать объёмы внутри table.ssort
А оно ведь тоже подвесит на первом же колбеке?
Смотря что подразумевать под "подвесит". Сложить два числа и положить в табличку под локом - это одно. А посчитать все накопленные на текущий момент сделки в OnInit - это совсем другое.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель, что-то я протупил в аккурат до закрытия, теперь на ходу не проверить, а мысль пошла в такую сторону
Код
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') - 1
end
function OnAllTrade(alltrade)
if N >= 0 then N = N + 1 else Claster(alltrade) end
end
function main()
while N >= 0 do
Claster(getItem('all_trades', N))
N = N - 1
end
while run do sleep(500) end
end
Не, прям вот так точно работать не будет, надо в качестве индекса в мейне отдельную переменную использовать, растущую от нуля и до эн, тогда может быть. А так он на одном месте будет пилить, пока колбеки идут.
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') - 1
end
function OnAllTrade(alltrade)
if N >= 0 then N = N + 1 else Claster(alltrade) end
end
function main()
local i = 0
while N >= 0 do
Claster(getItem('all_trades', i))
i = i + 1
N = N - 1
end
while run do sleep(500) end
end
Да не надо никаких колбеков! Идём по таблице до [текущего] конца, (которое при следующем вызове станет новым началом блока) и распределяем поток на части по тем тикерам, которые нас интересуют. Дальше по ним считаем чего надо и забываем данные самих потоков, если уже получен интегральный результат.
Владимир написал: которое при следующем вызове станет новым началом блока
Так и делаю на сях, там синхронизация есть человеческая. Тут если таймер поставить, его надо на ноль ставить, будет бесполезная дрызготня в цикле, включая выходные и праздники. Если на время поставить, будет задержка, в среднем половина этого времени. Задача как раз и рыбку съесть и пальчики облизать и все на чистом луа, без сей и виндов.
Anton, А какие проблемы таймер поставить? Та утилита, которая вызывается из мейна в цикле со sleep и есть таймер. У меня их даже три штуки: для реакции на действия юзера (было 150 мс, потом увеличил до 500, потом уменьшил до 300, на этом и остановился), затем "тиковый" обработчик (прорисовка таблиц, принятие решений - раз в полторы секунды) и, наконец, "свечной" (раз в 15 секунд - расчёт свечей по разным таймфреймам и принятие более глобальных решений). Задержка будет? Да и хрен с ней - мы же не микросекунды ловим! Я даже знать не хочу, какая там задержка, и "в среднем половина этого времени" меня вполне устраивает. Именно что "и рыбку съесть и пальчики облизать и все на чистом луа, без сей и виндов".
И откуда будет "бесполезная дрызготня в цикле"? Какой там период для работы с этой таблицей? Пять минут? Минута? Ну, проверили её размер, да запустили цикл от его старого до нынешнего значения. Сколько там успеет натикать за 5 минут? Вот эти данные и забираем.
Не вижу причин по которым собственно надо использовать задержки. Загрузится ЦП на 100% да и фиг с ним, сейчас в каждом тостере по 12 ядер. Вы же не батарею на ноутбуке экономите?
Владимир написал: Какой там период для работы с этой таблицей?
А неизвестно, какой там период. Там - это во внешнем приложении, моя задача (если о моей говорить) - доставить ему данные немедленно, как только они приехали в квик. А здесь конкретный был вопрос, для меня он как шахматная задачка, мат в три хода, зачем и почему так фигуры расставили - я ж не спрашиваю у шахматной задачки.
Цитата
Артем написал: Загрузится ЦП на 100% да и фиг с ним
Ой. Прям вот на простейшую задачу сразу ядро отдадим? А если на компе два квика, то два, да? И принимающую сторону так же сделаем, еще два ядра минус. Ну а если уж нам задачу поставят UKF посчитать, мы сразу выкатим требования на датацентр, не меньше. Интел одобряет.
Артем, сидят два старпера, обсуждают потерю точности при обращении плохо определенных матриц. Подходит школотрон - ээээ, какая потеря точности, я джва года квадратные уравнения решал, нет никакой потери точности, дураки вы старперы, в утиль вас, прекрасное айти будущего наступает. Ну вот оно и наступает, точнее вступает, куда - видно. Чо там в вики про вытесняющую написано, как она задействуется, расскажите нам немедля, мы усе горим.
Anton, тут скорее что два старпёра привыкли программировать с аутизмом олимпийского уровня потому что иначе в 2 килобайта 2 мегагерца не влезало, а теперь даже если делать через жопу то всё равно получается микроскопическая нагрузка. По итогу имеем что у старпёров тратится большое количество времени разработки ради экономии на спичках, а могли бы в это время чем-то полезным заниматься. Уже двадцать лет учат людей что не надо делать оптимизацию там, где и так хорошо работает, потому что это пустая трата времени - алё очнись Нео ты обосрался.
Старатель написал: Не может получиться такой порядок?
Теоретически может, в текущей реализации должно выполняться атомарно, луа не выпускает лок на таких операциях. Вероятность, что в версии луа 55.99 станет неатомарным - есть. Надо будет погонять еще, я сам не пробовал толком, просто идея клюнула.
Это не оптимизация, это вы архитектуру закладываете заведомо кривую. Потом ее "оптимизировать" - это переписать заново, вот это, видимо, и будет то самое полезное дело, куда полезнее, чем сразу написать ровно.
Anton, дрочение таймаута слипа это не архитектура. Ну и да, примерно также двадцать лет методом ватерфол никто не разрабатывает, потому что в итоге получается долго, дорого и криво, т.к. от апгрейда архитектуры в процессе разработки стараются отказываться.
Старатель написал: if N >= 0 then N = N + 1Это атомарная операция?
Фрагмент if N >= 0 then N = N + 1 это "чистый" Lua, а при текущей реализации QLua все такие участки (и в мейне и в колбеках) выполняются под общей блокировкой. Поэтому это атомарная операция.
Старатель написал: Тогда это тоже атомарная операция:
А тут я б не поручился, на первый взгляд доступ к таблице тоже чисто байткод, но там внутри может дернуться метаметод, а он может дернуть сишное что-нибудь; при добавлении нового поля может дернуться коллектор, а там вообще мрак полный, кто там сейчас на очереди к удалению и есть ли у него финализаторы и не сишные ли они и т.д., в общем уже не отследить это все. Интересно вот что, если этот кусок таки окажется атомарным, то от зависания мы не ушли, получается? Тогда, получается, функцию Claster надо намеренно сделать неатомарной? Или я перемудрил уже?
Anton, Ну, если неизвестно - значит задаём переменной.
Ну, допустим, секунда (меньше уж совсем неприлично). И чего? Проверим размер таблицы, да считаем 2-3 записи - в чём проблемы?
Нет, задача - дать мат. А уж во сколько ходов - дело стопятидесятое. Какой первым подвернётся. Во всяком случае, у нашей шахматной программы было именно так.
О! Вот наглядный до тошноты пример, как надо загаживать комп всяким дерьмом! ЛЮБЫЕ ресурсы будут засраны! Интел одобряет.(с)
Артем, Вся ваша шобла "молодых" ХОТЬ ЧТО-НИБУДЬ сделала полезного за весь XXI век? НУ ХОТЬ ЧТО-НИБУДЬ? Только пальцы веером. Да и то до первого щелчка по носу.
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.
Надо делать так, как надо. А как не надо - делать не надо.