QUIKSharp icon indicating copy to clipboard operation
QUIKSharp copied to clipboard

Ошибка Сбой подтверждения

Open cia76 opened this issue 4 years ago • 15 comments

При постановке заявок время от времени получаю сообщение:

Сбой подтверждения

После нажатия "Пропустить" программа продолжает работать в штатном порядке. Заявки в Квик ставятся корректно.

cia76 avatar Aug 04 '20 16:08 cia76

А как это по английски? Это Debug.Assert где-то ругается похоже? Что будет если нажать Прервать - где ошибка?

buybackoff avatar Aug 04 '20 16:08 buybackoff

Если не изменяет память, то будет Assertion Failed: Abort=Quit, Retry=Debug, Ignore=Continue

cia76 avatar Aug 04 '20 16:08 cia76

Вот код, где выдается сообщение:

                    case EventNames.OnTransReply:
                        Trace.Assert(message is Message<TransactionReply>); // Здесь выдается сообщение
                        var trReply = ((Message<TransactionReply>) message).Data;
                        trReply.LuaTimeStamp = message.CreatedTime;
                        Events.OnTransReplyCall(trReply);
                        break;

cia76 avatar Aug 05 '20 03:08 cia76

Полагаю что эта та же тема. https://github.com/finsight/QUIKSharp/issues/264 Если вы каким то образом используете поля Comment или CLIENT_CODE - далее он плавно превращается в TRANS_ID становится не уникальным и если заявки ставить одну за другой сразу происходит такой сбой.

IFetisov avatar Aug 05 '20 15:08 IFetisov

Полагаю что эта та же тема. #264 Если вы каким то образом используете поля Comment или CLIENT_CODE - далее он плавно превращается в TRANS_ID становится не уникальным и если заявки ставить одну за другой сразу происходит такой сбой.

Да, сразу ставится 2-6 заявок.

Есть подозрение на стоп заявки. Как я понимаю логику QuikSharp, после подачи заявки и до постановки заявки на рынок нам приходит код ответа. Заявка еще не поставлена, этот код попадает в поле Comment. Ждем прихода стоп заявки. Она приходит уже с другим кодом в поле TransId, но по полю Comment мы можем понять что за заявка пришла.

По этому пониманию написал код, несколько лет он нормально работал. Сейчас стал выдавать сообщение.

cia76 avatar Aug 05 '20 15:08 cia76

У меня этот код не работал корректно с самого начала. SendTransaction выставляет транзакцию и сразу же автоматически получает TRANS_ID Функция CreateOrder его возвращает. Зачем это шаманство с Comment и Client_Code не понятно совсем.

IFetisov avatar Aug 07 '20 06:08 IFetisov

Зачем это шаманство с Comment и Client_Code не понятно совсем.

Понимание шаманства такое. Создаем сразу несколько одинаковых заявок. По каждой заявке сразу получаем номер транзакции. Затем эти заявки будут или не будут размещены на бирже. После постановки этих заявок им присвоятся уже другие номера. Как узнать, если подали 3 заявки, а в ответ пришли 2 заявки, какие выставились, а какие нет? Потому при постановке заявки в поле комментария выставляется номер транзакции. Тогда по нему сможем однозначно определить какие заявки прошли, какие нет.

cia76 avatar Aug 10 '20 05:08 cia76

public class TransactionReply : IWithLuaTimeStamp [JsonProperty("order_num")] public long? OrderNum { get; set; } Тут возвращается OrderNum. Номер заявки. Вполне достаточно чтобы сопоставить транзакцию с заявкой. И портить поля предназначенные совсем для других целей не требуется.

IFetisov avatar Aug 10 '20 07:08 IFetisov

@cia76 при постановке заявки вы сами (в вашем случае - c# библиотека) указываете trans_id. Поэтому хоть 100500 заявок делаете, лишь бы эти айдишники были уникальны. И еще до выставления вы будете знать, как этот ордер искать. Вам не нужны поля comment для этих задач. Как делаю лично я, чтобы понять, что с заявкой, если она через какое-то количество секунд не пришла в ontransreply:

  • сохраняю ордер в любом случае сразу после отправки транзакции, в ней указан trans_id
  • спустя какое-то время ontransreply не вызывается, срабатывает таймаут
  • делаю поиск ордера по trans_id
  • если ничего нету, значит либо ордер не выставился, либо на текущий момент информации ещё нет.

Вот самая проблема в том, чтобы экспериментальным путём подобрать этот таймаут, после которого искать ордер вручную. Потому что у меня такое бывало, что спустя только 20 секунд (!) ордер приходил в ontransreply. И важно тут не отказаться от ожидания раньше, чем квик завершит установку транзакции. Иначе ордер будет выставлен, а вы и не в курсе. Не помню такого, чтобы ontransreply не приходило (бывает, что долго идет, но приходит).

А почему библиотека использует эти поля - не знаю, не изучал - не интересно.

avently avatar Aug 10 '20 07:08 avently

Вот код, где выдается сообщение:

                    case EventNames.OnTransReply:
                        Trace.Assert(message is Message<TransactionReply>); // Здесь выдается сообщение
                        var trReply = ((Message<TransactionReply>) message).Data;
                        trReply.LuaTimeStamp = message.CreatedTime;
                        Events.OnTransReplyCall(trReply);
                        break;

Немного неточно указал код, где выдается сообщение. Оно выдается чуть позже в коде:

namespace QuikSharp.DataStructures.Transaction
{
    public class Transaction
    {
        internal void OnTransReplyCall(TransactionReply reply)
        {
            OnTransReply?.Invoke(reply);  
            // this should happen only once per transaction id
            Trace.Assert(TransactionReply == null); // Выскакивает при постановке нескольких заявок
            TransactionReply = reply;
        }
    }
}

Если закомментировать строку с Trace.Assert, то сообщение появляться не будет. При этом, все заявки будут установлены корректно. Еще раз напомню, что ситуация возникает тогда, когда последовательно в Квик подаем 2 и более заявки.

cia76 avatar Aug 25 '20 07:08 cia76

Про корректно установленные заявки вообще спора нет. Главный вопрос - это быстро и корректно получить правильный ответ по выставленной транзакции и отписаться об этом. Вообще колбэк TransReply по каждой транзакции приходит больше 10 раз (почему не знаю)

У меня это работает таким образом. public static readonly ConcurrentDictionary<long, TransactionReply> TransReplies = new ConcurrentDictionary<long, TransactionReply>();

    public static void OnTransReplyDo(TransactionReply transReply)
    {
        //Log(LogRecordType.Trace, "TRANSREPLY", $"{transReply.ToJson()}");
        TransReplies.AddOrUpdate(transReply.TransID, transReply, (key, oldValue) => transReply);
    }

Есть такой же словарь с отправленными транзакциями. дальше по Id транзакции получаю номер заявки когда он требуется.

Как у меня это выглядит в логе. Заявка N0 выставлена ID транзакции - 15122147 => MOEX|TQBR|117,620000|Sell40|1|L01+00000F00 Заявка N1 выставлена ID транзакции - 15122146 => MOEX|TQBR|108,570000|Buy40|1|L01+00000F00 #15122146 - Заявка № 20701155275 - (160) Buy order #20701155275 accepted #15122147 - Заявка № 20701155276 - (161) Sell order #20701155276 accepted Снимаем заявку #20701155275/MOEX/Buy40/Остаток40 Результат 15122148 Снимаем заявку #20701155276/MOEX/Buy40/Остаток40 Результат 15122149 Заявка N2 выставлена ID транзакции - 15122150 => MOEX|TQBR|112,820000|Buy40|1|L01+00000F00 Заявка N3 выставлена ID транзакции - 15122151 => MOEX|TQBR|122,230000|Sell40|1|L01+00000F00 #15122148 - Заявка № 20701155275 - Снята- (210) 1 order(s) with total balance 40 withdrawn, 0 order(s) not withdrawn #15122149 - Заявка № 20701155276 - Снята- (210) 1 order(s) with total balance 40 withdrawn, 0 order(s) not withdrawn_

IFetisov avatar Aug 25 '20 09:08 IFetisov

Добрый день. Если кто-то решил данную проблему (что практически в одно время посылается несколько ордеров, транзакций), и только потом прилетают сообщения onTransReply в библиотеку QUIKSharp: case EventNames.OnTransReply: и (возможно из-за этого) TransReply на некоторые транзакции множится...

то что делать, просто закомметировать Trace.Assert(TransactionReply == null); эту проверку на одноразовый вызов onTransReply? Если так сделать, то какие побочные эффекты могут быть?


Пока, по беглому анализу кода, я так понял, если в своей логике буду пользоваться quik.Events.OnTransReply событием, мне просто надо готовиться, что за одну и ту же транзакцию событие может быть вызвано несколько раз.

@buybackoff @Pr0phet1c

Neznakomec avatar Jun 14 '23 18:06 Neznakomec

за одну и ту же транзакцию событие может быть вызвано несколько раз.

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

Pr0phet1c avatar Jul 25 '23 09:07 Pr0phet1c

Тогда получается эту проверку нужно убрать проверка

Neznakomec avatar Aug 01 '23 18:08 Neznakomec

Согласен, не понятно для чего используется Trace.Assert вместо Debug.Assert, но выход есть, можно перенаправить вывод от Trace.Assert вместо всплывающего окна напр. в файл. Достаточно в файле конфигурации приложения (в app.config), согласно рекомендациям Майкрософт #https://learn.microsoft.com/ru-ru/dotnet/api/system.diagnostics.defaulttracelistener?view=net-7.0 прописать настройки трассировки

<configuration>  

<system.diagnostics>  
  <trace autoflush="false" indentsize="4">  
    <listeners>  
      <remove name="Default" />  
      <add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\myListener.log" />  
    </listeners>  
  </trace>  
</system.diagnostics> 

</configuration>

pmrb1 avatar Nov 17 '23 18:11 pmrb1