У меня ведется локальная таблица заявок поданных роботом. При исполнении заявки она из таблицы убирается. Периодически эта таблица проверяется на соответствие таблицы заявок квика. В случае несовпадения подается команда на удаление из списка или на снятие заявки в зависимости от типа расхождения.
Nikolay написал: Так данные не обязаны прийти сразу. Установили соединение, ждем данные. Да. было бы хорошо иметь что-то определяющее приход данных. Но этого нет. Можно как минимум проверить, что загружены классы, счета, денежные лимиты. А потом уже заказывать потоки.
Не так. Всегда было: установили соединения, заказали данные, ждем данные. Я не спорю насчет необходимости наличия флага прихода данных, но с тем, что бы при заказе данных выявлялось отсутствие наименования класса столкнулся впервые за много лет.
Nikolay написал: Не уверен, что здесь что-то изменилось. Это просто данные с сервера шли долго (справочники, данные таблиц и т.д.) после установки соединения. На форме уже столько раз об этом спорили, просили разработчиков дать методы определения прихода пактов данных.
Дак вот же оно, в логе - сообщение о коннекте через целую секунду после IsConnected()==1. Что мешает этот признак выставлять после сообщения?
Обнаружилось, что при запуске терминала вместе со скриптом и последующем коннекте функция IsConnected() возвращает значение 1 раньше чем устанавливается фактическая связь с сервером.
в итоге
Код
if isConnected()==1 then
message("IsConnected "..tostring(Isconnected()))
csi,error_desc=CreateDataSource("INDX", "IMOEX", INTERVAL_D1)
...
...
пишет в лог: 10:06:35 isConnected 1 10:06:35 csi Source error==>INDX - unknown class code. 10:06:36 Соединение установлено. Предыдущий вход был 07.03.2024 10:05:04 с адреса 92.62.59.149.
Что за ...? В этой части скрипта я уже лет пять ничего не трогал. Приходится перезапускать скрипт после коннекта.
Для того что бы понять нужна ли вам такая логика достаточно вставить в скрипт использующий эту библиотеку функцию выставления заявок и дать доступ к деньгам. Своим деньгам ;)
Nikolay написал: Для массивов так, конечно, быстрее. pairs применяют для хеш таблиц, где простой итератор не применить.
Я конечно пошутил, но все же полагаю что если (по возможности) использовать массив вместо хэш-таблицы то перебор будет быстрее. Во всяком случае такие выводы у меня получились при сравнении обработки таблицы обезличенных сделок с приличным объемом. in pairs проигрывает построчному перебору.
Через файлы это хорошо, сам пользую. Как для передачи, так и для сохранения для последующего запуска. Вот только бэкапится приходится т.к. при коллизиях и вывыливании терминала в дамп файлы частенько бьются. А поскольку в файл писать приходится часто это становится проблемой.
function main()
message("Script's start local time: "..os.date("%d-%b-%Y %X"))
SessionDate=getTradeDate().date
message("Session date "..SessionDate)
ParamRequest(p_classcode,ticker,"TRADINGSTATUS")
--
while is_run==true do
t_status=tonumber(getParamEx2("TQBR",ticker, "TRADINGSTATUS").param_value) -- текущий статус
if status~=t_status then -- изменение статуса сессии
status=t_status
if status==3 or status==1 then
if not ds or type(ds)~="table" then
ds,error_desc=CreateDataSource("TQBR", ticker, INTERVAL_TICK)
if error_desc~=nil and error_desc~="" then message(" Source error==>" .. error_desc) end
local nn=0
while ds:Size()<5 and nn<100 do
sleep(100) nn=nn+1
end
ds:SetEmptyCallback()
message(os.date(" %X").." Ready. Session status:"..tostring(status).." Data size:"..tostring(ds:Size()))
end
while n<10 and status==1 do
local size=ds:Size()
if size~=old_size then
message(tostring(n)..os.date(" %X").." Get data. Session status:"..tostring(status).." Data size:"..tostring(ds:Size()))
old_size=size
n=n+1
end
sleep(50)
end
end
end
sleep(100)
end
end
Ничего не изменилось, данные поступают только после перезапуска скрипта.
nikolz написал: То что тики подписываются со второго пинка было указано давно, но воз и ныне там.
Наткнулся на интересную фишку: если тики не едут после подписки при открытой сессии, то подписка на другой тикер даже в другом скрипте толкает все подписки и они приходят в чувство.
В итоге я таки поймал этот баг за хвост. Вот скрипт, который его ловит:
Код
-- Скрипт проверки корректности получения данных обезличенных сделок.
-- Терминал запускается вместе со скриптом ДО начала сессии.
-- Таблица обезличенных сделок не открыта
-- Тикера нет в Таблице текущих торгов.
--
ticker="MAGN"
status,t_status=0,0
old_size=0
n=0
is_run=true
SessionDate=""
function main()
message("Script's start local time: "..os.date("%d-%b-%Y %X"))
SessionDate=getTradeDate().date
message("Session date "..SessionDate)
ParamRequest(p_classcode,ticker,"TRADINGSTATUS")
--
while is_run==true do
if SessionDate~=getTradeDate().date and status==1 then -- новая сессия
SessionDate=getTradeDate().date
message("New session date "..SessionDate)
n=0
end
t_status=tonumber(getParamEx2("TQBR",ticker, "TRADINGSTATUS").param_value) -- текущий статус
if status~=t_status then -- изменение статуса сессии
status=t_status
if status==3 or status==1 then
if not ds or type(ds)~="table" then
ds,error_desc=CreateDataSource("TQBR", ticker, INTERVAL_TICK)
if error_desc~=nil and error_desc~="" then message(" Source error==>" .. error_desc) end
local nn=0
while ds:Size()<5 and nn<100 do
sleep(100) nn=nn+1
end
ds:SetEmptyCallback()
message(os.date(" %X").." Ready. Session status:"..tostring(status).." Data size:"..tostring(ds:Size()))
while n<10 and status==1 do
local size=ds:Size()
if size~=old_size then
message(tostring(n)..os.date(" %X").." Get data. Session status:"..tostring(status).." Data size:"..tostring(ds:Size()))
old_size=size
n=n+1
end
sleep(50)
end
end
end
end
sleep(100)
end
end
function OnStop(stop_flag)
message("Script's stop local time(MSK-1): "..os.date("%d-%b-%Y %X"))
if ds then ds:Close() end
is_run=false
end
Скрипт был запущен вместе с терминалом до начала сессии (status==0), после открытия предторговой (status==3) отработали функции CreateDataSource и SetEmptyCallback. После открытия основной сессии (status==1) должны были начать поступать данные по обезличенным сделкам и показаны первые 10 изменений базы. Однако данные по сделкам в терминал НЕ поступали:
20.12.2023 08:00:10 Script's start local time: 20-Dec-2023 08:00:10 20.12.2023 08:00:10 Session date 20.12.2023 20.12.2023 08:00:34 Соединение установлено. Предыдущий вход был 20.12.2023 07:57:31 с адреса 92.62.58.114. 20.12.2023 09:50:10 09:50:10 Ready. Session status:3.0 Data size:0 20.12.2023 10:05:35 Script's stop local time: 20-Dec-2023 10:05:35
В 10-05 скрипт был перезапущен и отработал корректно:
20.12.2023 10:06:05 Script's start local time: 20-Dec-2023 10:06:05 20.12.2023 10:06:05 Session date 20.12.2023 20.12.2023 10:06:05 10:06:05 Ready. Session status:1.0 Data size:406 (406 записей базы было пропущено при первом запуске) 20.12.2023 10:06:05 0 10:06:05 Get data. Session status:1.0 Data size:406 20.12.2023 10:06:05 1 10:06:05 Get data. Session status:1.0 Data size:418 20.12.2023 10:06:05 2 10:06:05 Get data. Session status:1.0 Data size:421 20.12.2023 10:06:06 3 10:06:06 Get data. Session status:1.0 Data size:424 20.12.2023 10:06:12 4 10:06:12 Get data. Session status:1.0 Data size:425 20.12.2023 10:06:14 5 10:06:14 Get data. Session status:1.0 Data size:426 20.12.2023 10:06:16 6 10:06:16 Get data. Session status:1.0 Data size:428 20.12.2023 10:06:20 7 10:06:20 Get data. Session status:1.0 Data size:429 20.12.2023 10:06:20 8 10:06:20 Get data. Session status:1.0 Data size:430 20.12.2023 10:06:24 9 10:06:24 Get data. Session status:1.0 Data size:431
Не знаю насколько важно - терминал запускался на "тихоходном" компе c Intel Core i5
Полагаю что при получении нуля по одному из двух параметров просто проверяется второй и его ненулевое значение однозначно говорит о том, что данные получены.
В общем, как не искал, ничего не нашел. Все работает как надо за исключением отписки. Полагаю в последних версиях (у меня 11.0.0.92) эта проблема пофиксилась с чем-то вместе "за компанию". Либо я не учел какой-то дополнительный фактор. В любом случае дальше искать черную кошку в темной комнате смысла нет. Проявится снова, продолжу.
- ничего не появляется в фильтре таблицы обезличенных сделок
Если речь идет о том, что инструмент не добавляется в фильтр отдельной Таблицы обезличенных сделок, такое поведение корректно.
Цитата
- убрать эту подписку можно только вручную после похода в меню настроек.
Воспроизвели данное поведение при условии, что в терминале присутствует открытая Таблица обезличенных сделок. Проблема изучается. Постараемся в ближайшее время дать ответ.
Цитата
1. Достаточно ли такой подписки для корректной работы в скрипте колбэка OnAllTrade и выборки SearchItems("all_trades", .....) не имея этого инструмента в таблице обезличенных сделок?
Достаточно, наличие инструмента в открытой Таблице обезличенных сделок не обязательно.
Цитата
2. Как отписаться от этого счастья средствами Qlua при следующей смене иструмента?
Если в терминале нет открытых Таблиц обезличенных сделок, при вызове ds:Close() исключается получение обезличенных сделок по инструменту.
Антон, спасибо за ответ! Раз уж вы решили разобраться то посмотрите пожалуйста этот баг когда данные по обезличенным сделкам не получаются после запуска терминала со скриптом при закрытой сессии. Т.е. потом, когда сессия открывается, данные не поступают. При смене даты то же самое. Это при условии, что подписка оформлена в Настройках, но таблица обезличенных сделок не открыта. Если ТОС открыта и там прописан инструмент, то все работает корректно. Т.е. надо либо пофиксить этот баг, либо дать возможность CreateDataSource(..... INTERVAL_TICK) одновременно с внесением выбранного тикера в заказ данных вносить его и в открытую таблицу обезличенных сделок. В этом случае мы бы просто держали ТОС открытой и туда добавлялся бы и убирался тикер по CreateDataSource и Close(). Сейчас, для корректной работы скриптов, приходится после CreateDataSource(..... INTERVAL_TICK) руками вносить тикер в ТОС и потом после Close() руками же его убирать из Настроек и ТОС
nikolz написал: Еще есть такой глюк. Если Вы запустите КВИК и потом запустите скрипт, в котором есть подписка на обезличенные сделки, то ничего не получите. Если скрипт снять и снова запустить, то все заработает . Раньше уже про это писали, но воз вроде и ныне там.
Nikolay написал: В теории да, я так тоже делаю. Правда не советую так ждать прихода данных. Тиковые данные могут приходить долго, очень долго. В прошлых версиях данные приходили и без открытой таблицы обезличенных сделок. В текущих - уже нет, по крайней мере, по моим наблюдениям. Отписаться как и от обычного потока данных - закрыть. Собственно Вы это и делаете OnStop. Хотя, если говорите, что не убирается (как я понял), то, возможно, что-то опять изменилось между версиями. В последнее время мажорные релизы выходят как кролики.
Субъективно вроде работает, затыки появляются при смене даты торговой сессии на следующий день. Close() из меню подписку не убирает.
При возникновении стандартной ситуации смены рабочего тикера для робота довольно просто подписатся/отписатся на/от свечных баз данных. В случае же с обезличенными сделками ситуация выглядит иначе. Я предположил, что подписка на тиковую базу при помощи CreateDataSource решает эту проблему. Тестовый скрипт:
Код
is_run=true
function main()
ds,error_desc=CreateDataSource("TQBR", "GAZP", INTERVAL_TICK)
if error_desc~=nil and error_desc~="" then message(" Source error==>" .. error_desc) end
local nn=0
while ds:Size()<5 and nn<100 do
sleep(100) nn=nn+1
end
message("Data "..tostring(ds:Size()))
ds:SetEmptyCallback()
while is_run do
sleep(100)
end
end
function OnStop(stop_flag)
ds:Close()
is_run=false
end
Запускаю скрипт и , о чудо(!), в фильтре Основные_настройки/Программа/Получение_данных/Обезличенные_сделки появляется Газпром. Т.е. задача подписки на ленту сделок успешно решена и данные заказаны. Но... - ничего не появляется в фильтре таблицы обезличенных сделок - убрать эту подписку можно только вручную после похода в меню настроек.
В связи с вышеописанным имею два вопроса:
1. Достаточно ли такой подписки для корректной работы в скрипте колбэка OnAllTrade и выборки SearchItems("all_trades", .....) не имея этого инструмента в таблице обезличенных сделок? 2. Как отписаться от этого счастья средствами Qlua при следующей смене иструмента?
Vladimir spb написал: А если создать копию ТТТ, то ее можно изменять (удалять, добавлять строки) ?
Если абстрагироваться от того, зачем вам это счастье, то вы можете создать пользовательскую таблицу и заполнять ее в цикле теми же данными. Получите точную копию ТТТ с динамически меняющимися данными и возможностью менять строки как вам заблагорассудится в том числе добавлять строки тикеров и удалять их средствами Qlua. В этом случае выводить ТТТ в терминале вам как бы и не к чему.
Считаю это ошибками терминологии при составлении документации. Словом "таблица" обозначено все, что имеет табличную структуру. Данные, выводимая в терминал информация, создаваемые пользовательские структуры - все в кучу. Не удивительно появление таких вопросов.
Kolossi написал: Как всегда, хороший вопрос перевели в срач. В продолжение темы: насколько реально когда-нибудь объем свечи ds:V(n) получать в виде V(n).maker+V(n).taker?
Так это и 10 лет назад можно было, ещё на Qpile такое писали. Пишете скрипт, который ТОС обрабатывает, и выводите результат в таблицу или метками на график.
И как я не догадался :). Только вот как-то не хочется держать открытыми тиковые базы по всем нужным тикерам и шуршать фильтрами когда мне нужны такие данные по часовым свечам. На сервере брокера при подготовки свечной базы по любому периоду это сделать гораздо проще и логичнее.
Я просто сделал проверку на то, что каждый получаемый trade_num , был больше предыдущего и дубли исчезли.
Код
function OnTrade(trade) -- обработчик события сделки
if trade.client_code~=p_clientcode or trade.sec_code~=trw.p_seccode then return end -- чужая заявка
local tnord=trade.trade_num --номер сделки
local on ord=trade.order_num --номер заявки
local price=trade.price --цена сделки
local dir="" if bit.test(trade.flags,2)==true then dir="S" else dir="B" end -- направление сделки
if tnord>last_trade then --в обработку
last_trade=tnord
...
...
...
end
end
Как всегда, хороший вопрос перевели в срач. В продолжение темы: насколько реально когда-нибудь объем свечи ds:V(n) получать в виде V(n).maker+V(n).taker?
Подскажите по какой причине может быть расхождение позиции по одному из инструментов (в моем случае MAGN) ? В таблице "Состояние счета" --> "Позиция" --> -240 (T1) - правильное значение В таблице "Позиции по инструментам" --> "Текущий остаток" --> -2400 (Т1) В указаных таблицах еще четыре инструмента, по ним все ровно
Если у вас не открыта таблица текущих торгов, то можно оформить подписку на параметр ParamRequest(classcode,seccode,"LAST") и потом его получать c_price=tonumber(getParamEx2(classcode,seccode, "LAST").param_value)
Ну если вам нравится так называть текущую цену и получать ее таким способом то почему бы нет. Если что, для получения текущего прайса совсем не обязательно создавать базу. Можно, например, использовать getParamEx( class_code, sec_code, LAST)
"Кроме мордобития никаких чудес". В базе только свечи, их параметы, ну и размер самой базы. В тиковой чуть больше, но тоже без фантазий. Так сказали японцы и в своей религии "Японские свечи" и разработчики их адепты.
Наткнулся на то, что иногда значения param_value совсем не соответствуют значениям param_image Например: -- local aaa=getParamEx(p_classcode,"GMKN","EV_SESS_ALLOWED").param_value local bbb=getParamEx(p_classcode,"LSRG","EV_SESS_ALLOWED").param_value message(aaa.."/"..bbb)
--> 0.0000/0.0000 -- тоже с param_image : -- local aaa=getParamEx(p_classcode,"GMKN","EV_SESS_ALLOWED").param_image local bbb=getParamEx(p_classcode,"LSRG","EV_SESS_ALLOWED").param_image message(aaa.."/"..bbb)
local tt={name={},score={}} for x=1,10 do tt.name[x]=tostring(x) tt.score[x]=10-x end table.sort(tt, function(a,b) return a.score < b.score end) for x=1,10 do message(tt.name[x]..":"..tostring(tt.score[x])) end