← 返回

Проблемы в клиринг

Раньше вроде нормально клиринг проходили, вернее мы там код меняли, чтобы куча ошибок не вылетала на клиринге, а сейчас вот опять то же самое? (см. картинку)

本主题对您有帮助吗?

分享主题

评论 (47)

登录创建账户, 登录或注册以发表评论

Alexander
Alexander

frontman как раз прохождением клиринга и занимается сейчас фактически. можете ему помочь в этом

и надо не заглушки чтоб ошибки не лезли вставлять, а ошибки лучше исправлять :)

FiNick
FiNick 作者

Помогу, конечно)

frontman
frontman

)))) Урааа))) FiNich если что у меня есть отложенные изменения frontman_cp)) Велком)))

Alexander
Alexander

frontman: )))) Урааа))) FiNich если что у меня есть отложенные изменения frontman_cp)) Велком)))

Так вроде вы уже всё сделали и вам оставалось лишь протестировать изменения. Что-то изменилось?

frontman
frontman

Нет. Так и есть. Просто если человек хочет помочь почему бы и нет... Может он придумает способ сделать то же самое проще...

FiNick
FiNick 作者

Протестировал, на клиринге вылетают те же ошибки. (Может я не на то смотрю и ошибки вообще не связаны с тем что frontman менял?) Первая ошибка это "P2ERR_SERV_NO_SERVICE". На сколько я помню она вылетает потому что на клиринге потоки закрываются, и мы тогда решили что это нормальния ситуация и надо эту ошибку просто игнорить, написали соответствующий код. Что изменилось с тех пор, почему решили вернуть её обратно?

Вторая ошибка: "Инструменты GAZR28@RTS и GASP@RTS имеют одинаковый идентификатор инструмента 167736 торговой системы (тот самый IsinID??)". Странная ошибка, что за инструмент GAZR28, или USDRUB23?

Далее вопрос frontman'y по коду:

private void OnSessionContentsDerivativeStreamInserted(PlazaRecord record, PlazaSessionContentsDerivativeColumns metadata, Action<Security> initHandler, Action<Security> updateHandler)
		{
			ProcessEvents(() =>
			{
				var isinId = record.Get<int>(metadata.IsinId);
				var secCode = record.Get<string>(metadata.ShortIsin);

				GetSecurity(CreateSecurityId(secCode, "RTS"), security =>
				{
					if (_secCodeAndIsinIds.TryAdd(secCode, isinId))
					{
						InitSecurityInfo(security, record, metadata);

						security.Code = secCode;
						initHandler(security);
					}
					else
					{
						_newAndOldIsinIds.TryAdd(isinId, _secCodeAndIsinIds[secCode]);
					}

					UpdateSecurityInfo(security, record, metadata);
					updateHandler(security);
				}, isinId.ToString());
			});
		}

Я так понял это событие обрабатывает приход новых инструментов. Сначала мы сохраняем в словарь пары ShortIsin-IsinId, а затем если инструмент с такимже ShortIsin пришел второй раз сохраняем пару "новый IsinId-старый IsinId"?

private void ProcessPlazaStream(PlazaRecord record, PlazaColumn isinIdColumn, bool ignoreIfNotExist, Action<Security> action)
		{
			var newIsinId = record.Get<int>(isinIdColumn);
			var oldIsinId = _newAndOldIsinIds.TryGetValue(newIsinId);
			var isinId = (oldIsinId == 0 ? newIsinId : oldIsinId).ToString();
			ProcessEvents(() => ProcessSecurityAction(isinId, action, ignoreIfNotExist));
		}

Здесь в ProcessSecurityAction мы пытаемся подсунуть тот isinId который был до клиринга, ищем его в словаре _newAndOldIsinIds. Я так понимаю метод ProcessPlazaStream вызывается очень часто, и такая вот конструкция с поиском в словаре будет сильно все замедлять. Но вопрос оптимизации это уже второй вопрос, главное сейчас чтоб хоть как-то заработало=)

frontman
frontman

FiNick: Но вопрос оптимизации это уже второй вопрос, главное сейчас чтоб хоть как-то заработало=)

Рад что вы понимаете это) Честно скажу как это сделать по другому я пока не знаю... Подменять isinId надо, т.к. данные по инструменту закреплены за одним isinId(дневным как правило), а у нас их 2 одновременно существует... Словарь по моему это самая быстрая конструкция для поиска... Так что...

frontman
frontman

Так же тестил. Ошибка так же вылетела... Ничего не понял) Продолжу сегодня...

FiNick
FiNick 作者

frontman: Так же тестил. Ошибка так же вылетела... Ничего не понял) Продолжу сегодня... А какие у тебя ошибки вылетают? Такие же как у меня?

frontman
frontman

Первой не было. На второй все упало... Причем ранее я что то этого не наблюдал...

frontman
frontman

"что за инструмент GAZR28, или USDRUB23" - а что именно подозрительно?)

FiNick
FiNick 作者

frontman: "что за инструмент GAZR28, или USDRUB23" - а что именно подозрительно?) Ну для людей есть ShortIsin, он например "RIH2", "GAZR" он всегда одинаковый, каждый день, до и после клиринга. Для машин есть isinId, просто цыфры которые смысловой нагрузки не несут, на каждой торговой сессии они разные. Когда я вижу ShortIsin=="GAZR28" я вот и не понимаю что это за инструмент такой. Я так понимаю это какраз тот короткий код инструмента который является ключем в словаре _secCodeAndIsinIds. Т.е. в таблицу торгуемых инструментов на клиринге приходит новая запись с ShortIsin=="GAZR28", в словарь _secCodeAndIsinIds добавляется пара GAZR28 - 167735, в этом словаре уже есть пара GAZP - 167735, но ошибки это не вызывает. Ошибка вылетает потом то ли из initHandler, то ли из updateHandler, это я сегодня еще протестчу.

Alexander
Alexander

РТС Стандарт меняет названия инструментов у них дата дюрации ведь разная, постоянно меняется

frontman
frontman

Ну вы же видили письмо тех поддержки...

Вы можете сами обратить внимание, на то, по какому приницпу изменяются данные в fut_sess_contents.

Для фьючей и опционов все, кроме short_isin, isin, name, code_vcb, lot_volume, step_price, d_exp.

Для стандарта всё тоже самое, за исключением того, что инструменты станадрта могут жить всего 5 дней. При появлении нового инструмента ему присваивается новый isin_id. При изменении торговой сессии в инструментах Стандарта "сдвгиаются" isin_id, по принципу, обрисованому на скриншоте.

frontman
frontman

Вроде как short_isin не должен меняться((

frontman
frontman

А если меняется надо взять другое поле значит. Ток вот какое...

FiNick
FiNick 作者

Вот стэктрейс ошибки "Инструменты GAZR28@RTS и GASP@RTS имеют одинаковый идентификатор...": at StockSharp.Algo.BaseTrader.#=qRF_xqxANieD2egGg0vH$DyS9znTAcZf_D2rckeY$o9o=.#=qfEqfyH4VGXSOwDg5F7Jnwn3mDUB1ES48llbREdWjqoQ=.#=q14B6ZRU$RPtdRzxfmaRNQ8CoRwETJQ_mnmzCJkV$OMc=(SynchronizedDictionary2 #=qEUZtngTxeDs91jqGD7GENw==) at Ecng.Collections.CollectionHelper.SyncDo[TCollection](TCollection collection, Action1 action) at StockSharp.Algo.BaseTrader.#=qRF_xqxANieD2egGg0vH$DyS9znTAcZf_D2rckeY$o9o=.#=qtQpinW32NuP13jTk2ftde4STP6A6qcoCtYMw2TywzKw=(String #=qrq653$aXZYhOQ79Ye_NoVQ==) at Ecng.Collections.CollectionHelper.SafeAdd[TKey,TValue](IDictionary2 dictionary, TKey key, Func2 handler) at StockSharp.Algo.BaseTrader.GetSecurity(String id, Func2 createSecurity, Action1 changeSecurity, String nativeSecurityId) at StockSharp.Algo.BaseTrader.GetSecurity(String id, Action`1 changeSecurity, String nativeSecurityId) at StockSharp.Plaza.PlazaTrader.<>c__DisplayClass1d.<OnSessionContentsDerivativeStreamInserted>b__1b() in ...\PlazaTrader.cs:line 610 at StockSharp.Algo.BaseTrader.ProcessEvents(Action handler)

Честно говоря, я совершенно не понимаю что происходит и как сделать чтобы все заработало, перечитал всю тему по сертификации два раза, все равно не понятно

Mikhail Sukhov
Mikhail Sukhov

FiNick: Честно говоря, я совершенно не понимаю что происходит

Происходит обычное игнорирование собеседников.

frontman
frontman

Михаил! Да не кто вас не игнорит. Как я понял так я и сделал. И в каком месте я вас проигнорил то?! Вон FiNick то же прочитал и не чего не понял. В этом скорее виновата закрытая часть кода. Потому что не задав кучу вопросов вам невозможно понять механизмы...

Alexander
Alexander

frontman: Михаил! Да не кто вас не игнорит. Как я понял так я и сделал. И в каком месте я вас проигнорил то?! Вон FiNick то же прочитал и не чего не понял. В этом скорее виновата закрытая часть кода. Потому что не задав кучу вопросов вам невозможно понять механизмы...

Какая закрытая часть вам нужна для того чтобы во всём разобраться?

frontman
frontman

BaseTrader.

Alexander
Alexander

frontman: BaseTrader.

Зачем всего? 🤨 Может какой-то конкретный метод интересует?

frontman
frontman

Ну просто хотелось посмотреть как используется nativeId Потому что вроде бы подмену isin_id я делаю... И все норм... А вот что дальше происходит...

Alexander
Alexander

Отправил всё использование nativeId внутри BaseTrader. Теперь все данные для фикса есть?

frontman
frontman

)) Спасибо. Да. Надеюсь...

FiNick
FiNick 作者

Короче, в GetSecurity не надо подавать isinId в качестве параметра.

Mikhail Sukhov
Mikhail Sukhov

FiNick: Короче, в GetSecurity не надо подавать isinId в качестве параметра.

Во, надеюсь теперь вы найдете общий язык с фронтмэном. Я ему писал раз. Писал два. Писал три. Писал четыре. И что-то у меня есть сомнение, что фраза "не использовать маппинг BaseTrader" усвоена до конца.

frontman
frontman

Mikhail Sukhov:

FiNick: Короче, в GetSecurity не надо подавать isinId в качестве параметра.

Во, надеюсь теперь вы найдете общий язык с фронтмэном. Я ему писал раз. Писал два. Писал три. Писал четыре. И что-то у меня есть сомнение, что фраза "не использовать маппинг BaseTrader" усвоена до конца.

Я и сделал мапинг внутри PlazaTrader.

FiNick
FiNick 作者

frontman: Я и сделал мапинг внутри PlazaTrader. Да, но параллельно использовался мапинг BaseTrader, давай его уберем и все должно заработать

FiNick
FiNick 作者

Ну хорошо, убирем isinId из GetSecurity, в самом PlazaTrader'e будем хранить словарь "isinId - security". Далее, в ProcessPlazaStream есть метод BaseTrader.ProcessSecurityAction с параметром nativeSecurityId, который теперь работать не будет, значит его надо убрать, заменить на аналог для PlazaTrader. Я так понимаю этот метод по isinId искал соответствующий security, и, если находил, вызывал action(security)?

Mikhail Sukhov
Mikhail Sukhov

FiNick: Ну хорошо, убирем isinId из GetSecurity, в самом PlazaTrader'e будем хранить словарь "isinId - security". Далее, в ProcessPlazaStream есть метод BaseTrader.ProcessSecurityAction с параметром nativeSecurityId, который теперь работать не будет, значит его надо убрать, заменить на аналог для PlazaTrader. Я так понимаю этот метод по isinId искал соответствующий security, и, если находил, вызывал action(security)?

protected void ProcessSecurityAction(string nativeSecurityId, Action<Security> action, bool ignoreIfNotExist)
		{
			if (nativeSecurityId.IsEmpty())
				throw new ArgumentNullException("nativeSecurityId");

			if (action == null)
				throw new ArgumentNullException("action");

			var security = _nativeIdSecurities.TryGetValue(nativeSecurityId);

			if (security == null)
			{
				if (!ignoreIfNotExist)
					_suspendedSecurityEvents.Add(nativeSecurityId, action);
			}
			else
				action(security);
		}
frontman
frontman

По моему все помешались... Если не передавать isinId, то как будет происходить поиск инструмента в BaseTrader?!?! Как вот эта строчка будет работать то : var security = _nativeIdSecurities.TryGetValue(nativeSecurityId);?!?!?

frontman
frontman

А как тогда быть с ProcessSecurityAction? Чем его заменить? Таким образом просто получается мы нарушаем единообразие реализаций коннекторов так сказать... Если задуман ProcessSecurityAction через который во всех коннекторах совершаются действия над инструментами, то и в PlazaTrader все должно быть так... Я во всяком случае себе это так представляю...

По мне так просто вся проблема в поиске поля не изменяемого при смене сессий... Т.е. ShortIsin - не подходит...

FiNick
FiNick 作者

frontman: А как тогда быть с ProcessSecurityAction? Просто в PlazaTradere замещаем его своим методом. Можно даже попросить, чтобы в BaseTradere его сделали virtual, тогда "единообразие реализаций коннекторов" не нарушится я думаю)

frontman
frontman

Ну смотрите сами... Если это проще... В любом случае соответствие между isinId и инструментов надо сохранить... Т.е. добавиться еще один словарик. Зачем если он уже есть в BaseTrader? Я не понимаю... Попробуйте сделайте... В принципе важен результат, а не то насколько он прост))

frontman
frontman

Я все равно сделаю так как вижу это сам)) Потом решим как лучше...

Mikhail Sukhov
Mikhail Sukhov

frontman: Я все равно сделаю так как вижу это сам)) Потом решим как лучше...

Да там работы на 2 часа (1 - создать маппинг по разным исин_ид, 2 - сделать свой ProcessSecurityAction). А обсуждение ведем пол месяца. Но все равно интересно наблюдать.

frontman
frontman

Да кто ж мешает то? Проект открытый... Милости просим. В этом же основная идея...

Mikhail Sukhov
Mikhail Sukhov

frontman: Да кто ж мешает то? Проект открытый... Милости просим. В этом же основная идея...

Как только с этой странички исчезнет мой аккаунт, сразу возьмусь за Плазу.

frontman
frontman

Михаил. Глупо по моему пытаться выставить кого то глупым и недалеким... Вы основатель данного проекта и конечно же лучше вас и быстрее вас врятли кто то сделает, но если вы хотете что бы проект стал действительно открытым, то надо быть готовым к тому, что кто то будет делать что то не так и задавать вопросы... Мне кажется вы немного пренебрежительно относитесь к любой попытке инакомыслия...

Alexander
Alexander

Вступлю, пожалуй, в разговор.

Можно конкретики больше - где кто-то был выставлен глупым и недалёким, где пренебрежительное отношение было продемонстрировано? И где не были даны ответы на заданные вопросы?

Даже запрошенные исходники отправил я в личку.

frontman
frontman

Alexander Mukhanchikov: Вступлю, пожалуй, в разговор.

Можно конкретики больше - где кто-то был выставлен глупым и недалёким, где пренебрежительное отношение было продемонстрировано? И где не были даны ответы на заданные вопросы?

Даже запрошенные исходники отправил я в личку.

Ну если вы перечитаете переписку то все поймете думаю... Я бы не хотел на этом акцентировать внимание...

FiNick
FiNick 作者

Написал вот так:

private void ProcessPlazaStream(PlazaRecord record, PlazaColumn isinIdColumn, bool ignoreIfNotExist, Action<Security> action)
{
        var isinId = record.Get<int>(isinIdColumn);
	ProcessEvents(() => ProcessSecurityAction(isinId, action, ignoreIfNotExist));
}

private void ProcessSecurityAction(int isinId, Action<Security> action, bool ignoreIfNotExist)
{
        if (isinId==0)
            throw new ArgumentNullException("isinId");

        if (action == null)
            throw new ArgumentNullException("action");

        Security security = _isinIdSecurities.TryGetValue<int, Security>(isinId);

        if (security == null)
        {
            if (!ignoreIfNotExist)
            {
                //_suspendedSecurityEvents.Add(isinId, action); что это?
            }
        }
        else
            action(security);
}

private void OnSessionContentsDerivativeStreamInserted(PlazaRecord record, PlazaSessionContentsDerivativeColumns metadata, Action<Security> initHandler, Action<Security> updateHandler)
{
	ProcessEvents(() =>
	{
		var isinId = record.Get<int>(metadata.IsinId);
		var secCode = record.Get<string>(metadata.ShortIsin);

                var sec = GetSecurity(CreateSecurityId(secCode, "RTS"), security =>
                {
                    _isinIdSecurities.TryAdd(isinId, security);
                    InitSecurityInfo(security, record, metadata);
                    security.Code = secCode;
                    initHandler(security);
                    
                    UpdateSecurityInfo(security, record, metadata);
                    updateHandler(security);
                });
        });
}

До клиринга все вроде норм работало, на клиринге стали вылетать ошибки из PlazaDepthBuilder.FlushChanges, строка:

var newDepth = dict[oldDepth.Security].PendingDepth;

Говорит что в dict нет таких-то ключей, ключем тут является security. Есть идеи?)

frontman
frontman

Погодите... а вы что именно исправляли? Потому что если просто создать в PlazaTrader словарь с _isinIdSecurities это не поможет. Проблема в том что в вечернюю сессию у всех инструментов существует по 2 issin_id(Дневной и вечерний) Я создавал несколько словарей для замены... У вас в _isinIdSecurities хранятся пары где issin_id - различный , а Security один и тот же? Или как?

FiNick
FiNick 作者

frontman: У вас в _isinIdSecurities хранятся пары где issin_id - различный , а Security один и тот же? Или как? Да, именно так, после клиринга у нас будут записи с разными isin_id и одинаковыми Security, в этом ничего плохого нет. А возможна ли ситуация, когда после клиринга приходит некоторая security2 у которой точно такой isin_id как и у некоторой security1 которая еще до клиринга была? врядли... но если так надо будет к ключу добавить еще какой-нибудь session_id.

Ну и вообще, логика вроде верная: приходит новый инструмент, GetSecurity находит или создает соответствующий экземпляр Security, а я с этим экземпляром ассоциирую isin_id, если таких isin_id несколько это не страшно. если понадобится различать какой из них старый, какой новый, то добавим session_id

frontman
frontman

Ну да. Все норм.

FiNick
FiNick 作者

Поставил заглушку в PlazaDepthBuilder.FlushChanges:

if (!dict.ContainsKey(oldDepth.Security)) //Заглушка, удалить
    continue;
var newDepth = dict[oldDepth.Security].PendingDepth;

Вроде через клиринг нормально перешел, только повылетали "P2ERR_SERV_NO_SERVICE". После клиринга заявки ставятся, торговля идет, стакан работает. Изменения в шелве, ник FiNick_cp, буду еще тестить как работает