В своем приложении для автоматизации мне нужно получать объект TransactionReply ответа на транзакцию выставления нового стоп ордера, с ее статусом, и id только что выставленного ордера.
Сейчас я делаю это через вот такую странную конструкцию, потому что способа лучше пока не нашел:
Подписываюсь на событие OnTransReply и складываю в конкарент очередь все приходящие ответы на транзакцию:
Дальше, при создании ордера, в цикле с таймаутом жду, пока в этой очереди появится реплай с нужным id транзакции. Именно сам реплай мне нужен, чтобы проверять у него статус и сообщение, по которым можно понять, что ордер, например, не выставился, потому что был превышен лимит на кредитование и т.п.:
var createOrderRes = _quik.StopOrders.CreateStopOrder(order).Result;
//await for transaction response
var transId = Math.Abs(createOrderRes);
var getTransRespTimeoutMs = 400;
var getTransRespIterations = 40;
TransactionReply transResp = null;
for (var i = 0; i < getTransRespIterations; ++i)
{
if (_transResponses.ContainsKey(transId))
{
_transResponses.TryRemove(transId, out TransactionReply res);
transResp = res;
break;
}
Thread.Sleep(getTransRespTimeoutMs);
}
Тут встречается первая проблема:
Как видно, таймаут и число попыток достаточно больше, но все равно, в редких случаях я встречаю ситуации, когда transResp остается нулевым - а это значит что, похоже, до этого в очередь в коллбэке события не положили ответ на транзакцию с id == Math.Abs(createOrderRes)
Вторая проблема более странная и встречается тоже внезапно, и тоже раз в пару дней (по ощущениям - когда выставляешь несколько ордеров последовательно, с небольшим таймаутом между ними): в получаемом по transId ордере неверный secCode инструмента!
Как я это обнаруживаю:
Если transactionResponse пришел с хорошим кодом и без ошибок, я дальше получаю по нему ордер таким образом:
var newOrder = this.GetNewStopOrderByTransactionId(transId).Result;
Где:
private async Task<QuikSharp.DataStructures.StopOrder> GetNewStopOrderByTransactionId(long transId)
{
var attemptsCount = 20;
Thread.Sleep(100);
var stopOrder = await GetStopOrderByTransactionId(transId);
if (stopOrder != null)
return stopOrder;
//if stop order wasn't found
for (var i = 2; i <= attemptsCount; ++i)
{
Thread.Sleep(500);
Log($"Attempt {i}/{attemptsCount} to retrieve new stop order for transaction {transId}...");
stopOrder = await GetStopOrderByTransactionId(transId);
if (stopOrder != null)
return stopOrder;
}
return null;
}
И, соответственно:
private async Task<QuikSharp.DataStructures.StopOrder> GetStopOrderByTransactionId(long transId)
{
var stopOrders = await _quik.StopOrders.GetStopOrders();
if (stopOrders != null)
{
var stopOrder = stopOrders.FirstOrDefault(x => x.TransId == transId);
if (stopOrder != null)
return stopOrder;
}
return null;
}
И вот тут начинается проблема: я начал ловить ситуации, когда SecCode инструмента в ордере, объект которого я отправил на выставление в метод _quik.StopOrders.CreateStopOrder(order).Result; либы не совпадает с secCode ордера, который я получил по this.GetNewStopOrderByTransactionId(transId) (!!!)
То есть периодически выполняется return в этой проверке:
if (newOrder.SecCode != newStopOrder.Ticker)
{
var msg = $"Placed order secCode {newOrder.SecCode} is not equal to requested ticker {newStopOrder.Ticker}. Check by transaction ids: awaited to createdOrderRes {createOrderRes} transaction id {transId} but obtained new order with trans id {newOrder.TransId}";
Log($"ERROR! {msg}");
return new PlaceNewOrderResult
{
IsError = true,
State = PlaceNewOrderResult.ResultState.GeneralError,
Message = msg
};
}
Как будто бы, если последовательно выставляются несколько ордеров по разным инструментам, то транзакции по ним могут перепутаться. Проверяя свой код, я пока не нашел в нем ошибку, которая могла бы приводить к такому поведению.
Хотел бы услышать, сталкивался ли кто-то еще с таким поведением? И буду благодарен, если сможете подсказать более простой и надежный способ получать выставленный ордер и данные TransactionReply по id транзакции.
В своем приложении для автоматизации мне нужно получать объект TransactionReply ответа на транзакцию выставления нового стоп ордера, с ее статусом, и id только что выставленного ордера. Сейчас я делаю это через вот такую странную конструкцию, потому что способа лучше пока не нашел:
Подписываюсь на событие OnTransReply и складываю в конкарент очередь все приходящие ответы на транзакцию:
Дальше, при создании ордера, в цикле с таймаутом жду, пока в этой очереди появится реплай с нужным id транзакции. Именно сам реплай мне нужен, чтобы проверять у него статус и сообщение, по которым можно понять, что ордер, например, не выставился, потому что был превышен лимит на кредитование и т.п.:
Тут встречается первая проблема: Как видно, таймаут и число попыток достаточно больше, но все равно, в редких случаях я встречаю ситуации, когда transResp остается нулевым - а это значит что, похоже, до этого в очередь в коллбэке события не положили ответ на транзакцию с id == Math.Abs(createOrderRes)
Вторая проблема более странная и встречается тоже внезапно, и тоже раз в пару дней (по ощущениям - когда выставляешь несколько ордеров последовательно, с небольшим таймаутом между ними): в получаемом по transId ордере неверный secCode инструмента!
Как я это обнаруживаю: Если transactionResponse пришел с хорошим кодом и без ошибок, я дальше получаю по нему ордер таким образом:
Где:
И, соответственно:
И вот тут начинается проблема: я начал ловить ситуации, когда SecCode инструмента в ордере, объект которого я отправил на выставление в метод _quik.StopOrders.CreateStopOrder(order).Result; либы не совпадает с secCode ордера, который я получил по this.GetNewStopOrderByTransactionId(transId) (!!!) То есть периодически выполняется return в этой проверке:
Как будто бы, если последовательно выставляются несколько ордеров по разным инструментам, то транзакции по ним могут перепутаться. Проверяя свой код, я пока не нашел в нем ошибку, которая могла бы приводить к такому поведению. Хотел бы услышать, сталкивался ли кто-то еще с таким поведением? И буду благодарен, если сможете подсказать более простой и надежный способ получать выставленный ордер и данные TransactionReply по id транзакции.