К примеру: Стакан котировок по акциям брокер может давать глубиной 20. (т.е. параметры bid_count и offer_count должны быть = 20). Я ещё понимаю, когда в стакане мало заявок и реально получается, что bid_count или offer_count может быть меньше.(т.е.19 или 18 или ещё меньше ...). Но когда я получаю глубину стакана 22!!!! (Больше максимального значения), и котировки эти реальные с ценой и объемами.... У меня возникают большие сомнения, что данная функция работает без ошибок. С forts тоже самое. К примеру брокер предоставляет глубину стакана 50. А я получаю стакан со значением 62!!!! Это как нормально.... Это же стакан, основа основ, а не индикатор или график какой второстепенный... P.S. к разработчикам: доведите до ума, исправьте ошибки. И сделайте наконец, зарегистрированное пожелание о дополнительном параметре в этой функции, возвращающее точное время сформированного стакана (с точностью хотя бы до МИЛЛИСЕКУНД!!!)
Интересно узнать от какой базы считать время с погрешностью в миллисекунды. И что потом делать с этими циферками на компе. Это подобно нарезанию морской волны на кусочки с погрешностью мм с помощью бензопилы.
Николай Камынин пишет: Процесс увлекательный, но бессмысленный.
Смысл всегда есть. К примеру не было активности, а потом сразу 10 стаканов пришло. Как определить изменения в каком стакане повлияли на другие?(Т.е. какой стакан первым обновился?) В лучшем случае, можно получить время сервера "SERVERTIME" и предположить, что именно это время когда, был сделан снимок стакана, а оно с точностью до секунды. А если стакан изменится несколько раз за сек?Ставить разным стаканам одинаковую временную метку? Или какие то копии стакана проигнорировать?Какие? Первую копию или последнюю оставить? Как синхронизировать ленту всех сделок с поступающими новыми стаканами(может последний стакан отстаёт на 1-2 сек)? А определить должно быть просто. Время последнего внесённого изменения и есть время этого стакана.
Николай Камынин пишет: Процесс увлекательный, но бессмысленный.
Смысл всегда есть. К примеру не было активности, а потом сразу 10 стаканов пришло. Как определить изменения в каком стакане повлияли на другие?(Т.е. какой стакан первым обновился?) В лучшем случае, можно получить время сервера "SERVERTIME" и предположить, что именно это время когда, был сделан снимок стакана, а оно с точностью до секунды. А если стакан изменится несколько раз за сек?Ставить разным стаканам одинаковую временную метку? Или какие то копии стакана проигнорировать?Какие? Первую копию или последнюю оставить? Как синхронизировать ленту всех сделок с поступающими новыми стаканами(может последний стакан отстаёт на 1-2 сек)? А определить должно быть просто. Время последнего внесённого изменения и есть время этого стакана.
А можно пример из жизни, а то Ваш пример из страшного сна.
Николай Камынин пишет: А можно пример из жизни, а то Ваш пример из страшного сна.
Николай, в прошлом году один человек попросил, что-бы появилась возможность получать информацию по стаканам без открытия стакана(ов). И эту возможность очень быстро сделали. За что, искренняя моя благодарность разработчикам. Я же попросил добавить (временную метку), что бы точно понимать когда был сделан срез стакана. Чтобы можно было точно синхронизировать поступающие сделки(у них есть точное время и миллисекунды) и поступающие стаканы(у них нет привязки ко времени). А вообще, Николай, я был о Вас лучшего мнения...
Я Вас искренне спрашиваю, а Вы обижаетесь. Стаканы получать без открытия просили не в прошлом году а уже десять лет, еще когда лишь QPILE был, потом когда перевели все функции QPILE на луа тоже просили (сам лично просил) это было лет пять назад. Т е то была вполне естественная проблема. То что просите Вы, по моему пониманию - это невозможно технически и бессмысленно практически. попробуйте ответить на мой вопрос про базу отсчета. Допускаю, что Вы в этом не разбирались, но настоятельно рекомендую изучить каким же образом мы на компьютере узнаем на сколько точно в миллисекундах локальное время отстает или опережает время биржи. Посмотрите девиацию задержек ответов сервера. Я этим вопросом занимался подробно поэтому Вам и написал.
Ну вот! Можете же вести диалог, когда захотите, без эмоции и абстракций :) Я Вас понял, что Вы считаете - это невозможно технически и бессмысленно практически. Но почему тогда предложение было принято и рассмотрено как целесообразное к исполнению. А не отвергнуто.К мнению официальных лиц компании я отношусь серьезнее. И да, локальное время тут совсем не причем, т.е. могу предположить, что стакан формируется не на локальной машине, а на сервере брокера(об этом лучше спросить у разработчиков или у Вас если Вы уже в курсе).Так вот в момент когда формируется стакан на стороне брокера, как только стакан сформирован, зафиксировать время сервера и передать его дополнительным параметром. Вот и всё. Если же такой функционал, нужно ждать как Вы говорите 5 лет, тогда печаль....
А я поддерживаю пожелание DronGO И время лучше ставить даже не сервера брокера, а биржи, если есть такая возможность. Тогда можно будет без проблем сопоставить по времени поток обезличенных сделок и обновлений стаканов.
За сегодняшний день собрал небольшую статистику. Выбрал для теста несколько наиболее ликвидных акции и фьючерсов(SBER, LKOH, VTBR, URKA, SBERP, TATN, MTSS, HYDR, SiU5, RIU5). Привожу часть лога всего за 1 час!!! Т.к. весь лог за неполную сессию более 600 строк. В среднем получилось сегодня 1 коллизия в 2 минуты. Интересно было бы посмотреть, как у других складывается ситуация.
00000001 13:59:07 [4716] Стакан не полный. 'SiU5' Значения bid_count = '53' offer_count = '50' 00000002 13:59:11 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000003 14:11:38 [4716] Стакан не полный. 'TATN' Значения bid_count = '21' offer_count = '20' 00000004 14:16:43 [4716] Стакан не полный. 'RIU5' Значения bid_count = '51' offer_count = '50' 00000005 14:18:29 [4716] Стакан не полный. 'SiU5' Значения bid_count = '55' offer_count = '50' 00000006 14:24:23 [4716] Стакан не полный. 'RIU5' Значения bid_count = '51' offer_count = '50' 00000007 14:24:33 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000008 14:25:32 [4716] Стакан не полный. 'LKOH' Значения bid_count = '23' offer_count = '20' 00000009 14:26:33 [4716] Стакан не полный. 'SiU5' Значения bid_count = '52' offer_count = '50' 00000010 14:26:33 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '53' 00000011 14:26:38 [4716] Стакан не полный. 'RIU5' Значения bid_count = '50' offer_count = '51' 00000012 14:26:50 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000013 14:30:23 [4716] Стакан не полный. 'RIU5' Значения bid_count = '50' offer_count = '52' 00000014 14:30:27 [4716] Стакан не полный. 'RIU5' Значения bid_count = '50' offer_count = '51' 00000015 14:30:28 [4716] Стакан не полный. 'SBER' Значения bid_count = '20' offer_count = '21' 00000016 14:30:36 [4716] Стакан не полный. 'SBERP' Значения bid_count = '21' offer_count = '20' 00000017 14:31:17 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000018 14:33:38 [4716] Стакан не полный. 'TATN' Значения bid_count = '24' offer_count = '20' 00000019 14:37:09 [4716] Стакан не полный. 'SiU5' Значения bid_count = '52' offer_count = '50' 00000020 14:38:00 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000021 14:40:03 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000022 14:40:06 [4716] Стакан не полный. 'TATN' Значения bid_count = '20' offer_count = '21' 00000023 14:41:37 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '52' 00000024 14:42:19 [4716] Стакан не полный. 'TATN' Значения bid_count = '22' offer_count = '20' 00000025 14:43:32 [4716] Стакан не полный. 'TATN' Значения bid_count = '21' offer_count = '20' 00000026 14:43:51 [4716] Стакан не полный. 'TATN' Значения bid_count = '22' offer_count = '20' 00000027 14:45:13 [4716] Стакан не полный. 'SiU5' Значения bid_count = '55' offer_count = '50' 00000028 14:45:33 [4716] Стакан не полный. 'TATN' Значения bid_count = '21' offer_count = '20' 00000029 14:49:18 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000030 14:49:51 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000031 14:50:16 [4716] Стакан не полный. 'SiU5' Значения bid_count = '51' offer_count = '50' 00000032 14:50:38 [4716] Стакан не полный. 'RIU5' Значения bid_count = '51' offer_count = '50' 00000033 14:51:35 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '51' 00000034 14:51:45 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '54' 00000035 14:53:22 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '54' 00000036 14:53:38 [4716] Стакан не полный. 'TATN' Значения bid_count = '20' offer_count = '21' 00000037 14:56:12 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '51' 00000038 14:56:34 [4716] Стакан не полный. 'TATN' Значения bid_count = '21' offer_count = '20' 00000039 14:56:34 [4716] Стакан не полный. 'SiU5' Значения bid_count = '50' offer_count = '52' 00000040 14:57:13 [4716] Стакан не полный. 'RIU5' Значения bid_count = '51' offer_count = '50' 00000041 14:59:39 [4716] Стакан не полный. 'SiU5' Значения bid_count = '53' offer_count = '50' 00000042 14:59:56 [4716] Стакан не полный. 'SiU5' Значения bid_count = '52' offer_count = '50' 00000043 15:00:57 [4716] Стакан не полный. 'LKOH' Значения bid_count = '20' offer_count = '21' 00000044 15:02:08 [4716] Стакан не полный. 'SiU5' Значения bid_count = '52' offer_count = '50' 00000045 15:02:17 [4716] Стакан не полный. 'TATN' Значения bid_count = '22' offer_count = '20'
Здравствуйте, Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
Sergey Gorokhov пишет: Просьба привести пример скрипта считывающего bid_count и offer_count
Добрый день.
Не надо делать вид, что вы первый раз об этом слышите! Я отправлял логи со "стаканами" по вашему же скрипту ещё 09.06.2015 в рамках разбора проблем с некорректными данными в очереди котировок (CQ01635062), (CQ01635170). В этих логах, где bid >= offer, размеры стаканов часто не соответствуют стандартным размерам 20х20 или 50х50. Поговорите с Михаилом Шубиным, если не в курсе.
DronGO, вы ещё проверьте, чтобы bid был меньше offer:
Код
function OnQuote(class_code, sec_code)
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 nBid >= nOffer then
_toLog("[OnQuote] "..sec_code..": Bid="..nBid.." >= Offer="..nOffer)
end
end
end
Разработчики утверждают, что у них проблема не воспроизводится на фондовой секции (про валютную пока молчат). Хотя у других проблема имеет место быть как на срочной, так на фондовой и валютной секциях рынка. Просто на фондовой секции пересечения могут возникать не каждый день. Видимо, тестерам не хватает терпения протестировать и зафиксировать проблему...
Надо делать так, как надо. А как не надо - делать не надо.
Старатель пишет: Sergey Gorokhov пишет: Просьба привести пример скрипта считывающего bid_count и offer_count Добрый день.
Не надо делать вид, что вы первый раз об этом слышите! Я отправлял логи со "стаканами" по вашему же скрипту ещё 09.06.2015 в рамках разбора проблем с некорректными данными в очереди котировок (CQ01635062), (CQ01635170). В этих логах, где bid >= offer, размеры стаканов часто не соответствуют стандартным размерам 20х20 или 50х50. Поговорите с Михаилом Шубиным, если не в курсе.
Не надо делать вывод что описанная проблема автора является той же проблемой что Вы упомянули на одних лишь симптомах без проведения какого либо анализа. Просьба не мешать проведению анализа.
Sergey Gorokhov, автор вам сообщает, что размеры "стаканов" часто не соответствуют стандартным. Связана ли эта проблема с упомянутой мной или нет - это вы сами разберитесь. Только зачем делать вид, что вы первый раз об этом слышите и задавать глупые вопросы? Проблема имеет место быть на боевом сервере. И вы давно располагаете кодом и логами, чтобы убедиться в этом воочию и разобраться в проблеме, а не напрягать автора зазря. А то сейчас ещё попросите архив рабочего места и видео прислать.
Весёлые картинки:
Скрытый текст
Надо делать так, как надо. А как не надо - делать не надо.
Старатель пишет: Связана ли эта проблема с упомянутой мной или нет - это вы сами разберитесь.
Вот именно за этим и была запрошена дополнительная информация.
Цитата
Старатель пишет: Только зачем делать вид, что вы первый раз об этом слышите и задавать глупые вопросы?
Приведите мою цитату где об этом было сказано
Цитата
Старатель пишет: Проблема имеет место быть на боевом сервере. И вы давно располагаете кодом и логами, чтобы убедиться в этом воочию и разобраться в проблеме, а не напрягать автора зазря. А то сейчас ещё попросите архив рабочего места и видео прислать.
На это уже был ответ
Цитата
Sergey Gorokhov пишет: Не надо делать вывод что описанная проблема автора является той же проблемой что Вы упомянули на одних лишь симптомах без проведения какого либо анализа.
Sergey Gorokhov, мне не хочется с вами спорить, но сам ваш вопрос
Цитата
Sergey Gorokhov пишет: Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
говорит о том, что вы либо не в курсе проблемы (в чём я сомневаюсь), либо просто не хотите заниматься проведением анализа и всячески пытаетесь оттянуть этот неприятный для вас момент. Поэтому, перестаньте уже пререкаться и займитесь, наконец, проведением анализа: дополнительной информации вам не требуется. Повторяю: проблема имеет место быть на боевом сервере, на версиях QUIK 6.17.x, 6.16.x и ниже. Код и логи уже давно имеются в вашем распоряжении. Было бы желание...
Надо делать так, как надо. А как не надо - делать не надо.
Старатель пишет: Sergey Gorokhov , мне не хочется с вами спорить, но сам ваш вопрос
Цитата
Sergey Gorokhov пишет: Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
говорит о том, что вы либо не в курсе проблемы (в чём я сомневаюсь), либо просто не хотите заниматься проведением анализа и всячески пытаетесь оттянуть этот неприятный для вас момент
Эта фраза говорит только и только о том что мне нужно знать версию терминала, пример скрипта и какой это сервер не более. И если бы мне по каким-то причинам вдруг захотелось бы оттянуть изучение проблемы или вообще не заниматься ей, то я бы с Вами тут не общался.
Цитата
Старатель пишет: Поэтому, перестаньте уже пререкаться и займитесь, наконец, проведением анализа: дополнительной информации вам не требуется. Повторяю: проблема имеет место быть на боевом сервере, на версиях QUIK 6.17.x, 6.16.x и ниже. Код и логи уже давно имеются в вашем распоряжении. Было бы желание...
Еще раз повторяю
Цитата
Sergey Gorokhov пишет: Не надо делать вывод что описанная проблема автора является той же проблемой что Вы упомянули на одних лишь симптомах без проведения какого либо анализа.
Подтверждаю, подобное явление (строк в стакане больше, чем должно быть по идее) наблюдал на боевом сервере неоднократно, правда где-то прошлой осенью на более старых версиях терминала. С тех пор просто не следил за этим, но уверен, что проблема никуда не ушла (если это действительно проблема, то есть если лишние строки в стакане несут в себе недостоверную информацию).
Sergey Gorokhov пишет: Здравствуйте, Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
Добрый день Сергей. Версия терминала 6.17.1.17 Сервер реальных торгов. Скрипт небольшой написал, в нем нужно только два параметра установить, в соответствии с Вашей глубиной стакана.Скрипт выводит информацию на консоль программы DebugView для визуального контроля. А так же сохраняет в файл log_errors_in_quotes.txt
Скрытый текст
local io_open=io.open
-- Таблица кодов инструментов для Акции и фьючерсов forts local stocks_codes = {SBER="TQBR",LKOH="TQBR",VTBR="TQBR",URKA="TQBR",SBERP="TQBR",TATN="TQBR",MTSS="TQBR",HYDR="TQBR",SiU5="SPBFUT",RIU5="SPBFUT"}
while is_run do sleep(50) end stop_subscription_level2() file:close() end
function init_subscription_level2() for key, value in next,stocks_codes do Subscribe_Level_II_Quotes(value, key) end end
function stop_subscription_level2() for key, value in next,stocks_codes do Unsubscribe_Level_II_Quotes(value, key) end end -- Два параметра, нужно изменить на те значения, которые соответствуют Вашему брокеру local depth_stocks = 20 local depth_forts = 50
function OnQuote(class, sec) if not is_run then return end
quote_level2 = getQuoteLevel2(class, sec)
if quote_level2==nil then return end
local bid_count = tonumber(quote_level2.bid_count) local offer_count = tonumber(quote_level2.offer_count)
if bid_count == nil or offer_count == nil then return end
if class == "TQBR" and ( bid_count > depth_stocks or offer_count > depth_stocks) then local tmpMsg =" Error in quotes '"..tostring(sec).."' bid_count = '"..tostring(bid_count).."' offer_count = '"..tostring(offer_count).."'" PrintDbgStr(tmpMsg) local get_time = GetInfoParam("SERVERTIME") file:write(get_time.." "..tmpMsg.."\n")
end if class == "SPBFUT" and ( bid_count > depth_forts or offer_count > depth_forts) then local tmpMsg =" Error in quotes '"..tostring(sec).."' bid_count = '"..tostring(bid_count).."' offer_count = '"..tostring(offer_count).."'" PrintDbgStr(tmpMsg) local get_time = GetInfoParam("SERVERTIME") file:write(get_time.." "..tmpMsg.."\n") end end
Sergey Gorokhov пишет: Здравствуйте, Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
Добрый день Сергей. Версия терминала 6.17.1.17Сервер реальных торгов. Скрипт небольшой написал, в нем нужно только два параметра установить, в соответствии с Вашей глубиной стакана.Скрипт выводит информацию на консоль программы DebugView для визуального контроля. А так же сохраняет в файл log_errors_in_quotes.txt
Здравствуйте!
Информация получена, проблема изучается. Постараемся в ближайшее время дать ответ.
Решил посмотреть, что на валютной секции. Добавил 4 стакана(USDRUB_TOM, USDRUB_TOD, EURRUB_TOM, EURRUB_TOD) ситуация аналогичная. Ниже обновил скрипт, под спойлером. P.S. Для того, чтобы определить, что проблема не у меня в коде, а в поступающих стаканах пришлось потратить неделю рабочего времени. И я думаю я не один такой...
Скрытый текст
Код
local io_open=io.open
-- Таблица кодов инструментов для Акции и фьючерсов forts
local stocks_codes = {SBER="TQBR",LKOH="TQBR",VTBR="TQBR",URKA="TQBR",SBERP="TQBR",TATN="TQBR",MTSS="TQBR",HYDR="TQBR",SiU5="SPBFUT",RIU5="SPBFUT",USD000UTSTOM="CETS",USD000000TOD="CETS",EUR_RUB__TOD="CETS",EUR_RUB__TOM="CETS"}
is_run = true
function main()
file=io_open(getScriptPath().."\\".."log_errors_in_quotes.txt",'a')
init_subscription_level2()
while is_run do
sleep(50)
end
stop_subscription_level2()
file:close()
end
function init_subscription_level2()
for key, value in next,stocks_codes do
Subscribe_Level_II_Quotes(value, key)
end
end
function stop_subscription_level2()
for key, value in next,stocks_codes do
Unsubscribe_Level_II_Quotes(value, key)
end
end
-- Два параметра, нужно изменить на те значения, которые соответствуют Вашему брокеру
local depth_stocks = 20
local depth_forts = 50
local depth_etc = 20
function OnQuote(class, sec)
if not is_run then return end
quote_level2 = getQuoteLevel2(class, sec)
if quote_level2==nil then return end
local bid_count = tonumber(quote_level2.bid_count)
local offer_count = tonumber(quote_level2.offer_count)
if bid_count == nil or offer_count == nil then return end
if class == "TQBR" and ( bid_count > depth_stocks or offer_count > depth_stocks) then
local tmpMsg =" Error in quotes '"..tostring(sec).."' bid_count = '"..tostring(bid_count).."' offer_count = '"..tostring(offer_count).."'"
PrintDbgStr(tmpMsg)
local get_time = GetInfoParam("SERVERTIME")
file:write(get_time.." "..tmpMsg.."\n")
end
if class == "SPBFUT" and ( bid_count > depth_forts or offer_count > depth_forts) then
local tmpMsg =" Error in quotes '"..tostring(sec).."' bid_count = '"..tostring(bid_count).."' offer_count = '"..tostring(offer_count).."'"
PrintDbgStr(tmpMsg)
local get_time = GetInfoParam("SERVERTIME")
file:write(get_time.." "..tmpMsg.."\n")
end
if class == "CETS" and ( bid_count > depth_etc or offer_count > depth_etc) then
local tmpMsg =" Error in quotes '"..tostring(sec).."' bid_count = '"..tostring(bid_count).."' offer_count = '"..tostring(offer_count).."'"
PrintDbgStr(tmpMsg)
local get_time = GetInfoParam("SERVERTIME")
file:write(get_time.." "..tmpMsg.."\n")
end
end
function OnStop()
is_run = false
end
Sergey Gorokhov пишет: Здравствуйте, Просьба привести пример скрипта считывающего bid_count и offer_count Также сообщите версию терминала и уточните это боевой доступ или тестовый?
Добрый день Сергей. Версия терминала 6.17.1.17Сервер реальных торгов. Скрипт небольшой написал, в нем нужно только два параметра установить, в соответствии с Вашей глубиной стакана.Скрипт выводит информацию на консоль программы DebugView для визуального контроля. А так же сохраняет в файл log_errors_in_quotes.txt
Здравствуйте!
Информация получена, проблема изучается. Постараемся в ближайшее время дать ответ.
Добрый день, Мы провели разбор полученной информации и обнаружили причины описанной Вами проблемы. Временное "увеличение строк в стакане котировок" объясняется итеративностью в обновлении стакана котировок, когда обновляются ценовые уровни, один за другим. В связи с этим, при частом обновлении большого количества ценовых уровней, возникает возможность временно наблюдать окно котировок в состоянии, когда обновлена только часть ценовых уровней, а вторая часть ещё не обновлена и соответствует предыдущему состоянию. В этот момент в стакане могут появляться "лишние строки".
Мы постараемся исправить данную особенность обновления стакана котировок в одной из ближайших версий ПО.
Приносим Вам свои извинения за доставленные неудобства.
Sergey Gorokhov пишет: возникает возможность временно наблюдать окно котировок в состоянии, когда обновлена только часть ценовых уровней, а вторая часть ещё не обновлена и соответствует предыдущему состоянию. В этот момент в стакане могут появляться "лишние строки"
Добрый день! Из данного ответа можно сделать вывод, что наличие лишних строк в стакане может быть достаточно надежным признаком того, что некоторые данные в нем неактуальны.
Цитата
Sergey Gorokhov пишет: Мы постараемся исправить данную особенность обновления стакана котировок в одной из ближайших версий ПО.
А приведет ли это к тому, что в моменты, когда часто обновляется большое количество ценовых уровней, данные в стакане будут значительно более корректными, чем сейчас в такие же моменты? То есть будет ли стакан в результате такого исправления выдаваться нам только после обновления всех строчек в нем и благодаря этому всегда отражать действительную картину расстановки в нем заявок (разумеется, с некоторым запаздыванием)? Или просто будет убран внешний признак неактуальности данных (лишние строчки), но качество данных в остальных строчках при этом не изменится?
Sergey Gorokhov пишет: Мы провели разбор полученной информации и обнаружили причины описанной Вами проблемы. Временное "увеличение строк в стакане котировок" объясняется итеративностью в обновлении стакана котировок, когда обновляются ценовые уровни, один за другим. В связи с этим, при частом обновлении большого количества ценовых уровней, возникает возможность временно наблюдать окно котировок в состоянии, когда обновлена только часть ценовых уровней, а вторая часть ещё не обновлена и соответствует предыдущему состоянию. В этот момент в стакане могут появляться "лишние строки".
Мы постараемся исправить данную особенность обновления стакана котировок в одной из ближайших версий ПО.
Никаких "особенностей" при "частом обновлении большого количества ценовых уровней" возникать не должно.
Что-то мне подсказывает, что разбор ситуации проведён не тщательно, и действительные причины проблемы не найдены (свои мысли по этому поводу и возможным причинам я направил по e-mail). Одна из причин - изменения строк не в хронологическом порядке, т.е., не в том порядке, в каком они изменялись в действительности. И, как следствие, мы видим большее (меньшее) количество строк в "стакане" и пересечения цен спроса и предложения (#1, #2).
Отсюда у меня есть опасения, что будет устранена не действительная причина проблемы, а произведены, например, "косметические" правки, типа убраны "лишние" строки. Соответственно, есть опасения и за качество данных после таких исправлений.
Поэтому, предлагаю более тщательно исследовать данную проблему.
Надо делать так, как надо. А как не надо - делать не надо.
Sergey Gorokhov пишет: Добрый день, Мы провели разбор полученной информации и обнаружили причины описанной Вами проблемы. Временное "увеличение строк в стакане котировок" объясняется итеративностью в обновлении стакана котировок, когда обновляются ценовые уровни, один за другим. В связи с этим, при частом обновлении большого количества ценовых уровней, возникает возможность временно наблюдать окно котировок в состоянии, когда обновлена только часть ценовых уровней, а вторая часть ещё не обновлена и соответствует предыдущему состоянию. В этот момент в стакане могут появляться "лишние строки".
Мы постараемся исправить данную особенность обновления стакана котировок в одной из ближайших версий ПО.
Приносим Вам свои извинения за доставленные неудобства.
Спасибо за проделанную работу. Но хотелось бы прояснить несколько моментов: 1. Как передаётся стакан от сервера брокера к клиенту? a. формируется на стороне брокера и пересылается целиком в виде нескольких массивов. б. формируется на стороне брокера и пересылается только изменения в стакане, а на клиенте идёт обновление предыдущих значений стакана. в. формируется на клиенте, от брокера пересылаются только изменения заявок. 2. Ждать изменений какого ПО? Серверного или клиентского?
DronGO пишет: 1. Как передаётся стакан от сервера брокера к клиенту? a. формируется на стороне брокера и пересылается целиком в виде нескольких массивов. б. формируется на стороне брокера и пересылается только изменения в стакане, а на клиенте идёт обновление предыдущих значений стакана. в. формируется на клиенте, от брокера пересылаются только изменения заявок.
Используется внутренний протокол QUIK который не подлежит разглашению
Цитата
DronGO пишет: 2. Ждать изменений какого ПО? Серверного или клиентского?
После устранения проблемы в данном топике обязательно будет написано в каком именно продукте она была устранена.
Старатель пишет: Что-то мне подсказывает, что разбор ситуации проведён не тщательно, и действительные причины проблемы не найдены (свои мысли по этому поводу и возможным причинам я направил по e-mail). Одна из причин - изменения строк не в хронологическом порядке, т.е., не в том порядке, в каком они изменялись в действительности. И, как следствие, мы видим большее (меньшее) количество строк в "стакане" и пересечения цен спроса и предложения ( #1 , #2 ).
Отсюда у меня есть опасения, что будет устранена не действительная причина проблемы, а произведены, например, "косметические" правки, типа убраны "лишние" строки. Соответственно, есть опасения и за качество данных после таких исправлений.
Склонен согласится с Вами. По моему мнению, ошибки с таким неконтролируемым увеличением строк в стакане, возникают при ошибках синхронизации многопоточных приложений работающих с одной критической секцией. Т.е. один поток(reader) начинает считывать значения(в критической секции), а в это время другой поток(writer) начинает запись обновлений(в эту же секцию).Поток (reader) только сейчас заканчивает считывание и как результат, считал старые значения+несколько обновлений. Если в этот момент в стакане было быстрое движение цен, то получаем проблемы. нет движения цены в стакане, никто ничего не заметит. Так как клиентский терминал работает в одном основном потоке, то проблемы синхронизации тут не может быть вообще(за отсутствием второго потока) -> значит ошибки синхронизации на серверной стороне. Таким образом если получим обновление клиентского терминала, значит получим заплатку, с простым фильтром(''косметические правки"). Если же получим обновления серверной части, тогда скорее всего вопрос будет закрыт раз и навсегда. Спасибо.
Sergey Gorokhov пишет: Мы провели разбор полученной информации и обнаружили причины описанной Вами проблемы. Временное "увеличение строк в стакане котировок" объясняется итеративностью в обновлении стакана котировок, когда обновляются ценовые уровни, один за другим. В связи с этим, при частом обновлении большого количества ценовых уровней, возникает возможность временно наблюдать окно котировок в состоянии, когда обновлена только часть ценовых уровней, а вторая часть ещё не обновлена и соответствует предыдущему состоянию. В этот момент в стакане могут появляться "лишние строки".
Вы здесь всё достаточно подробно описали, чтобы понимать суть происходящего процесса. Плюс схожие(аналогичные) проблемы синхронизации были выявлены и рассмотрены в конструкции (table.insert table.remove). В результате проблему решили создав дополнительные методы (table.sinsert table.sremove).
DronGO пишет: Кстати table. s insert table. s remove, работают очень медленно, в сотни раз медленнее, чем lock-free системы. И в своей работе их использовать не стал.
DronGO пишет: Кстати table. s insert table. s remove, работают очень медленно, в сотни раз медленнее, чем lock-free системы. И в своей работе их использовать не стал.
Michael Bulychev пишет: Я имел ввиду подробности про "сотни раз медленнее", если не сложно.
Попробуйте, в конце для удалить alltrade.dat и пере зайти в терминал. Запустите скрипт сохранения всех сделок с использованием конструкции sinsert и sremove. В терминал будут поступать по несколько десятков тысяч новых сделок в сек. И терминал встанет на 100% загрузку цп + появятся тормоза в основном потоке терминала и процесс этот затянется на долго. А если использовать lock-free никаких проблем, загрузка не долее 10%, за несколько минут всё(1 000 000 сделок, к примеру) сохранится успешно. У меня в данном случае в базу.
Пользователям был нужен такой инструмент и они его получили. Как и всяким инструментом, им нужно пользоваться правильно и использовать к месту. Скорее всего в OnAllTrade Вы в конец добавляете сделки в конец массива, а при выгрузке в базу удаляете элемент с индексом 1. Ничего удивительного что все тормозит. Ваши тормоза не связаны не столько с синхронностью выполнения, сколько с особенностью реализации этих функций. Я уже на старом форуме и на этом рассказывал как устроены функции insert/remove. Также дважды приводил пример кода для неблокирующей очереди. Мне кажется, что если вы избавитесь от remove и просто будете запоминать последний обработанный индекс, пробивая обработанные элементы значением nil, то скорость будет гораздо выше.
Я Вам привёл пример теста на обрыв соединения, когда на определённое время пропадает связь с сервером брокера. После восстановления связи, в терминал начинают поступать все пропущенные сделки и поступают они все сразу. Создаётся большой поток событий. И их все нужно принять и обработать. Информации о том как устроены и какие ограничения Ваших потокобезопасных функции практически нет. По запросу в гугле: " sinsert site:forum.quik.ru " Всего 4 ссылки, но и они не проясняют ситуацию. В документации не слова об ограничениях. примеров правильного использования нет. Другие потокобезопасные функции решил даже не смотреть и не использовать, терять время не хочется...
Вопрос не в ситуации когда это происходит, а в разумности применения тех или иных функций. Что бы было понятнее - тутначало этой истории. На последней странице как раз есть пример очереди без блокировок.
Еще раз: дело не в нашей реализации, а в том как устроены оригинальные функции. При удалении первого элемента из массива, остальные элементы сдвигаются на индекс -1. Это значит что чем больше у вас исходная таблица, тем больше нужно времени на удаление первого элемента. Вот простой тест:
Код
local item = { 1, 2, 3, 4}
local _ins = table.insert
local _rem = table.remove
function remove_first(t)
return _rem(t, 1)
end
function prepare(t, item, size)
t={}
for i=1, size do
t[i] = item
end
return t
end
for s=500, 10000, 100 do
T = prepare(T, item, s)
_start = os.clock()
while remove_first(T) do end
_end = os.clock()
print(string.format("%d\t%.3f", s, (_end - _start)))
end
Все это выполняется не в терминале, а в обычном lua.exe. Результаты для наглядности в картинке:
Скрытый текст
Видно, что зависимость времени обработки от размера массива далеко не линейная.
DronGO пишет: Кстати table. s insert table. s remove, работают очень медленно, в сотни раз медленнее, чем lock-free системы. И в своей работе их использовать не стал.
Самый быстрый способ удалить элемент таблицы - присвоить ему nil.
DronGO пишет: Сравнил количество сохранённый сделок/в секунду первым способом и вторым.
Видимо, идут накладные расходы на заморозку/разморозку параллельного потока. Кроме того, параллельный поток при использовании потокобезопасных функций просто простаивает.
Ваш тест показывает, что создание большой очереди в колбеке для её последующей обработки в main нецелесообразно, т.к. изымание элементов из большой очереди может занять больше времени, чем обработка колбеков сразу по факту их прихода. А в случае использования потокобезопасных функций в main основной поток терминала будет "заморожен", в результате мы не получим того, для чего собственно и использовали эту очередь: освобождение основного потока.
Надо делать так, как надо. А как не надо - делать не надо.
Пример показывает, что insert/remove не оптимальное решение. Для подобных задач есть более оптимальные алгоритмы, одних из них был приведен на нашем форуме.
Michael Bulychev пишет: Еще раз: дело не в нашей реализации, а в том как устроены оригинальные функции. При удалении первого элемента из массива, остальные элементы сдвигаются на индекс -1. Это значит что чем больше у вас исходная таблица, тем больше нужно времени на удаление первого элемента. Вот простой тест:
Хороший пример. Думаю будет полезно для всех, кто будет разбираться в этой теме в будущем. Пожалуйста добавьте в документацию, что при использовании Ваших потокобезопастых функции есть ограничения на размер очереди(к примеру не более 5000 элементов), а также добавьте, что для реализации потокобезопасного накопительного буфера FIFO, целесообразно использовать другую конструкцию. Пример в документации, тоже желательно иметь, а то через год форум снова переедет и важные примеры потеряются. Спасибо.
Если надо работать с очередями с 5000 элементов, то надо просто написать спец модуль такой очереди для луа на СИ. ------------------------------------------------- Я делаю именно так для обработки больших массивов, очередей, списков, пулов, ну и т д --------------------------------- Полагаю, что если чел смело берется за потоки с очередями в 5000 элементов, то создать спец модуль очереди для него - раз плюнуть.
Николай Камынин пишет: Если надо работать с очередями с 5000 элементов, то надо просто написать спец модуль такой очереди для луа на СИ. ------------------------------------------------- Я делаю именно так для обработки больших массивов, очередей, списков, пулов, ну и т д --------------------------------- Полагаю, что если чел смело берется за потоки с очередями в 5000 элементов, то создать спец модуль очереди для него - раз плюнуть.
Тоже пришел к такому выводу. Минимум на луа, остальное всё во внешней dll.