Запустил скрипт на "боевом" сервере по SiM5. Результаты несколько неожиданные:
Получается "пачки" OnAllTrade приходят даже реже, чем обновления в ТТП по параметру "NUMTRADES". К тому же позже.
Интереса ради написал скрипт, считающий колбеки OnQuote. Результат:
Счётчик Count в OnParam увеличивается на единицу при изменении одного из параметров: 'BID', 'OFFER', 'BIDDEPTH', 'BIDDEPTHT', 'OFFERDEPTH', 'OFFERDEPTHT' при условии, что между колбеками прошло более 33 мс (на случай одновременного изменения нескольких параметров)
И в сравнении с OnQuote ТТП даёт информацию об изменении лучших спроса и предложения чаще и раньше.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель пишет: Получается "пачки" OnAllTrade приходят даже реже, чем обновления в ТТП по параметру "NUMTRADES".
А может картину искажает слишком большое время, заданное для разделения колбэков между пачками? И в итоге за этот интервал времени успевают на самом деле прийти две пачки или даже больше. Думаю, колбэки OnAllTrade правильней делить на пачки не по времени между ними (или не только по времени), а еще проверяя, не срабатывали ли между ними колбэки другого типа (OnParam и OnQuote).
Egor Zaytsev пишет: Приоритет получения данных выглядит следующим образом:
- таблица котировок, - далее таблица текущих параметров - таблица всех сделок, - графики.
А вот это, похоже, уже не соответствует сказанному техподдержкой:
Цитата
Старатель пишет: И в сравнении с OnQuote ТТП даёт информацию об изменении лучших спроса и предложения чаще и раньше.
Хотелось бы понять почему... Может неправильно тестировали? Или все же техподдержка ошиблась? А может получается раньше потому что чаще...? Хотя насчет подсчета частоты хочу отметить, что сравнивать частоту обновлений стакана и ТТП по перечисленным параметрам не совсем корректно, т.к. 'BIDDEPTHT' и 'OFFERDEPTHT' отражают общий спрос и предложение, изменение которых может происходить и при неизменном стакане (т.к. стакан нам показывает не все заявки).
Кстати, не только сделки, но и обновления ТТП и стаканов тоже пачками приходят, по-моему. А формируются такие пачки, возможно, потому что терминал получает с сервера только изменения параметров или только сделки или только обновления стаканов до тех пор, пока очередь с накопившимися данными одного типа на сервере не опустеет. Только после этого терминал, наверное, переходит к обработке данных другого типа.
Дмитрий пишет: А может картину искажает слишком большое время, заданное для разделения колбэков между пачками? И в итоге за этот интервал времени успевают на самом деле прийти две пачки или даже больше.
Уменьшил разницу до 5 мс, но это не изменило сути:
Кстати, со временем наблюдается всё увеличивающаяся разница между количеством сделок, посчитаных по OnAllTrade и OnParam (на демо не было). Очевидно, это из-за того, что в ТТП учитываются сделки, которые не отображаются в ТВС.
Цитата
Дмитрий пишет: Хотя насчет подсчета частоты хочу отметить, что сравнивать частоту обновлений стакана и ТТП по перечисленным параметрам не совсем корректно, т.к. 'BIDDEPTHT' и 'OFFERDEPTHT' отражают общий спрос и предложение, изменение которых может происходить и при неизменном стакане (т.к. стакан нам показывает не все заявки).
Согласен. Но изменения в стакане чаще всего происходят вблизи спреда.
Старатель пишет: И в сравнении с OnQuote ТТП даёт информацию об изменении лучших спроса и предложения чаще и раньше .
Хотелось бы понять почему... Может неправильно тестировали? Или все же техподдержка ошиблась?
Раннее я уже проводил исследования на эту тему. Код:
Скрытый текст
Код
local sClassCode, sSecCode = 'SPBFUT', 'SiM5'
local offer, bid
function OnQuote(class_code, sec_code)
if not bRun or sec_code ~= sSecCode then return end
local tStakan = getQuoteLevel2(class_code, sec_code)
local nOffer_Count, nBid_Count = tonumber(tStakan.offer_count), tonumber(tStakan.bid_count)
if nOffer_Count ~= 0 and nBid_Count ~= 0 then
local nOffer = tonumber(tStakan.offer[1].price)
local nBid = tonumber(tStakan.bid[nBid_Count].price)
if nOffer ~= offer then
_toLog('[OnQuote] offer='..nOffer)
offer = nOffer
end
if nBid ~= bid then
_toLog('[OnQuote] bid='..nBid)
bid = nBid
end
end
end
function OnParam(class_code, sec_code)
if not bRun or sec_code ~= sSecCode then return end
local Offer, Bid = getParamEx(class_code, sec_code, "OFFER"), getParamEx(class_code, sec_code, "BID")
Offer, Bid = tonumber(Offer.param_value), tonumber(Bid.param_value)
if Offer ~= offer then
_toLog('[OnParam] offer='..Offer)
offer = Offer
end
if Bid ~= bid then
_toLog('[OnParam] bid='..Bid)
bid = Bid
end
end
насчёт разницы в количестве коллбеков м/у OnParam и OnAllTrade: думаю. тут нет ничего удивительного - т.к. в OnParam - коллбек приходит на каждое изменение параметра и: параметры изменяются не единой строкой за так называемый "срез", а только те, что реально изменились. Те, что не изменились имеют значение с предыдущего апдейта (что иной раз усложняет жизнь - бо как невсегда понятно: "он уже" или "ещё нет" (если коллбек к тому же пропущен)).
Добрый день. Сравнивать частоту обновлений стакана и таблицы текущих параметров не совсем корректно. Они, конечно, будут между собой коррелировать, но стоит учитывать следующее: 1. Стакан обычно поступает ограниченного размера. Любое изменение заявок вне области видимости приводит к изменениям в ТТП; 2. По ТТП формируются временные срезы на уровне торговой системы и сервера QUIK. 3. Некоторые изменения в ТТП могут вообще не отражаться в стакане котировок. Например внесистемные сделки.
sam063rus пишет: т.е. у нас появляется небольшое конкурентное преимущество.
Никакого преимущества. они влияют только на открытый интерес. Не помню точно насчет общего количества сделок. В таблице всех сделок они не отображаются. Насчет сходимости не совсем понятно. Что это такое?
в том сообщении - всё есть. я пытался считать количество сделок разными путями и на основе ТВС и ТТП с помощью соответствующих коллбеков. Суть в том, что у меня это не получилось. я - считал, что параметр TIME в ТТП имеет своё отражение и на основе сделок в ТВС (столбец "Время")
т.е. возвращаясь в самое начало: в OnParam - пропадают параметры или, по другому: этот коллбек невсегда срабатывает и не успев сработать - теряет данные.
хотелось бы уже подытожить: то, считалось, что OnAllTrade даёт более быстрый и достоверный результат то, OnParam. На старом форуме - OnParam. На этом форуме - не менее "жарче" разгорелись мнения за OnAllTrade и в итоге - всё-равно OnParam. Так курица или яйцо???
касательно всего того, то я здесь услышал и, с учётом многих новых подробностей - я так и не понял в таком случае, что такое "срез" и как он влияет (и влияет ли) на мои версии скриптов. Хочу заметить, что чтобы тут до этого не говорилось - мы всё-равно работаем в рамках концепции единого хранилища данных.
на самом деле, все 3 топика - об одном и том же: CreateDataSource, этот топик и "Вопросы по OnAllTrade"
в очередной раз, "Арка" самоустранилась (лень читать топики, "много букАв" и всё такое). В очередной раз, я услышал от Михаила Булычева его "Что это такое?". Он ещё любит говорить "непонимаю о чём Вы?" после долгого обсуждения, чтобы вконец отбить всё желание, что-то обсуждать, а начать пытаться искать ответы другими способами...
sam063rus пишет: хотелось бы уже подытожить: то, считалось, что OnAllTrade даёт более быстрый и достоверный результат то, OnParam. На старом форуме - OnParam. На этом форуме - не менее "жарче" разгорелись мнения за OnAllTrade и в итоге - всё-равно OnParam. Так курица или яйцо???
Может, OnParam будет и быстрей немного, но однозначно OnAllTrade будет давать более точные результаты.
Цитата
sam063rus пишет: я так и не понял в таком случае, что такое "срез"
sam063rus пишет: насчёт разницы в количестве коллбеков м/у OnParam и OnAllTrade: думаю. тут нет ничего удивительного - т.к. в OnParam - коллбек приходит на каждое изменение параметра
При сравнении с OnAllTrade я считал только колбеки OnParam, увеличивающие количество сделок.
Цитата
Michael Bulychev пишет: Сравнивать частоту обновлений стакана и таблицы текущих параметров не совсем корректно.
Согласен. Это я так, до кучи посчитал количество колбеков. Основной целью же было выяснить, что приходит раньше: OnParam или OnQuote с новой котировкой.
sam063rus, своё мнение, откуда брать данные, я выразил ещё здесь: если нам нужны только цена последней сделки и/или лучшего спроса/предложения, то эти данные лучше брать из ТТП, т.к. туда они поступают, чаще всего, раньше других.
Надо делать так, как надо. А как не надо - делать не надо.
я к тому, что среза никакого может и не быть вовсе. Есть главный источник данных. После каждого апдейта - происходит сравнение новых данных к предыдущем по таблице в памяти квика. Если новое значение не равно старому - вызывается соответствующий коллбек. И далеко не факт, что это будет OnAllTrade - всё зависит от преходящих данных.
единственное верно - то, что это всё в главном цикле, равно как и коллбеки, а значит последовательно - по определению. И величина "среза" - ненормирована по времени, а зависит лишь от очередной, поступившей от биржи порции данных. Если же квиковцы сделали жёсткий срез по их внутреннему представлению времени - то это уже даже близко нельзя назвать стабильной МТС и даже ИТС.
Дмитрий пишет: Я имел в виду для реализации задачи подсчета числа сделок в секунду
А, ну, да. По OnAllTrade будет точнее по любому. Я так и не понял, с чем у автора возникли проблемы: в пределах одной торговой секции OnAllTrade приходят в хронологическом порядке. Если не баловаться галочками в процессе подсчёта, да и то после подкачки дозаказанных сделок хронология восстанавливается.
Надо делать так, как надо. А как не надо - делать не надо.
Однако, принимая всё вышесказанное - остаётся открытым вопрос: если OnParam впереди планеты всей то, куда делось 21:18:19?
Проблема может решиться только если разработчики официально признают, что часть коллбеков всё же теряется. А также то, что модель единого хранилища данных - в корне не верна.
другими словами, для ТВС - есть внутренний кеш подкачки пропущенных данных, а для ТТП - нет. Если разработчики это признают - то у меня не останется никаких вопросов.
Вот пример простого скрипта, который будет считать количество сделок в секунду по заданному классу (точней, сумму сделок за секунду по всем инструментам этого класса, по которым в терминал поступают обезличенные сделки). При этом архивные сделки по какому-то дополнительно добавленному в ТВС (уже после начала торгов) инструменту из того же класса не исказят текущую статистику. В лог пишутся те сделки, которые могли бы нарушить нормальный ход подсчетов. Если таковые обнаружатся, то интересно посмотреть, что это за сделки...
Код
local file = io.open("C:\\TEST\\Log.txt", "w+t")
local cur_day = getTradeDate().day
local last_time = 0
local count = 0
function OnAllTrade(tr)
if tr.class_code == "SPBFUT" then
if tr.datetime.day == cur_day then
local time = tr.datetime.hour * 3600 + tr.datetime.min * 60 + tr.datetime.sec
if time == last_time then
count = count + 1
elseif time > last_time then
message(tostring(count/(time-last_time))) -- делим на число секунд (на случай, если сделки совершаются редко)
count = 1
last_time = time
else -- (time < last_time) - скорей всего закачка истории сделок по вновь добавленному в ТВС инструменту
file:write(tr.class_code," ",tr.sec_code," ",tr.trade_num," ",tr.datetime.hour,":",tr.datetime.min,":",tr.datetime.sec,".",tr.datetime.mcs,"\n")
end
else
file:write("Пришла вчерашняя сделка - ", tr.trade_num, "\n")
end
end
end
local not_stopped = true
function OnStop(stop_flag)
not_stopped = false
end
function main()
while not_stopped do
sleep(1000)
end
file:close()
end
Например, сохранить в файл данные, которые он вычисляет. В конце дня выгрузить таблицу всех сделок в другой файл, обработать его своим скриптом и сравнить результаты.
Впрочем, ТВС в файл выгружать не обязательно, можно сразу обработать ее своим скриптом. И потом Вы ведь как-то поняли, что Ваш скрипт выдавал неадекватные данные. Значит, есть возможность проверить.
я почему-то всегда считал, что число сделок в секунду - всегда целое по определению. Бо как сделка ну никак не может быть "половинчатой" или "четвертованной"
Проблема в том, что если сделки происходят редко, то интервал между срабатываниями OnAllTrade может превышать 1 секунду. В таком случае, если при очередном срабатывании OnAllTrade будет обнаружено, что с момента ее предыдущего вызова прошло больше секунды, то число сделок будет разделено на число секунд и получено среднее значение. Либо можете не делить это значение и не получать среднее, а считать, что в первую секунду прошли все сделки (как и есть на самом деле), а в остальные - 0
Дмитрий пишет: Либо можете не делить это значение и не получать среднее, а считать, что в первую секунду прошли все сделки (как и есть на самом деле), а в остальные - 0
я в своём скрипте на среднее вообще не закладывался: нет сделок - нет счёта, нет нулей - просто ничего не выводил.
Дмитрий пишет: Если не делить число сделок на число секунд и не выводить нули когда сделок не было, то индикатор будет запаздывать при низкой активности торгов.
мне главное, чтоб правильно считал: т.е. есть сделка - есть счёт, нет - нет, и без всяких запаздываний.
Дмитрий пишет: Если не делить число сделок на число секунд и не выводить нули когда сделок не было, то индикатор будет запаздывать при низкой активности торгов.
То есть фактически выдавать недостоверные данные. К примеру за 1 секунду у нас было 10 сделок, а потом 5 секунд сделок не было вообще. Скрипт узнает о том, что 1-я секунда закончилась, только после прихода новой сделки (на 7-й секунде). Если выдать при этом просто число сделок, не поставив нули за последние 5 секунд (или не поделив число сделок на число секунд), то будет впечатление, будто 10 сделок пришли не 6 секунд назад, а буквально только что.