finsight / QUIKSharp

QUIK# (QUIK Sharp) is the QUIK Lua interface ported to .NET.
Other
231 stars 135 forks source link

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

Open cia76 opened 4 years ago

cia76 commented 4 years ago

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

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

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

buybackoff commented 4 years ago

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

cia76 commented 4 years ago

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

cia76 commented 4 years ago

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

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

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

cia76 commented 4 years ago

Полагаю что эта та же тема.

264

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

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

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

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

IFetisov commented 4 years ago

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

cia76 commented 4 years ago

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

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

IFetisov commented 4 years ago

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

avently commented 4 years ago

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

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

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

cia76 commented 4 years ago

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

                    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 и более заявки.

IFetisov commented 4 years ago

Про корректно установленные заявки вообще спора нет. Главный вопрос - это быстро и корректно получить правильный ответ по выставленной транзакции и отписаться об этом. Вообще колбэк 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_

Neznakomec commented 1 year ago

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

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


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

@buybackoff @Pr0phet1c

Pr0phet1c commented 1 year ago

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

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

Neznakomec commented 1 year ago

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

pmrb1 commented 10 months ago

Согласен, не понятно для чего используется 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>