private static void ProcessExecutionReport(FixMessage msg) { ExecutionReport execReport; try { // отчет об исполнении может относиться не к клиентскому ордеру, // а к инициированной брокером процедуре (в т.ч. - стопауту) if (!msg.fieldValues.ContainsKey(FixMessage.TAG_CLIENT_ORDER_ID)) { ProcessBrokerInitiatedExecutionReport(msg); } // промежуточный отчет по исполнению ордера, не учитывается var ordStatusStr = msg[FixMessage.TAG_ORDER_STATUS]; if (ordStatusStr == FixMessage.VALUE_ORDER_NEW || ordStatusStr == FixMessage.VALUE_ORDER_PARTIALLY_FILLED || ordStatusStr == FixMessage.VALUE_ORDER_CALCULATED) { return; } // получить Id запроса var clientIdStr = msg[FixMessage.TAG_CLIENT_ORDER_ID]; int clientId; if (!int.TryParse(clientIdStr, out clientId)) { loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, LogMagicIncorrectId, 1000 * 60 * 15, "Отчет брокера: поле ClientOrderId не представлено целым [{0}]", clientIdStr); return; } execReport = new ExecutionReport { brokerResponse = { RequestId = clientId, ValueDate = DateTime.Now } }; if (ordStatusStr == FixMessage.VALUE_ORDER_FILLED) { execReport.brokerResponse.Status = OrderStatus.Исполнен; } else if (ordStatusStr == FixMessage.VALUE_ORDER_REJECTED) { execReport.brokerResponse.Status = OrderStatus.Отклонен; } else { // ордер может быть либо исполнен, либо не исполнен, третьего не дано loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, LogMagicIncorrectStatus, 1000 * 60 * 15, "Отчет брокера по запросу [{0}]: статус ({1}) не поддерживается", clientId, ordStatusStr); return; } var price = (decimal?)null; if (msg.fieldValues.ContainsKey(FixMessage.TAG_ARG_PX)) { price = msg.GetValueDecimal(FixMessage.TAG_ARG_PX); } else if (msg.fieldValues.ContainsKey(FixMessage.TAG_PRICE)) { price = msg.GetValueDecimal(FixMessage.TAG_PRICE); } // нет цены в положительной квитанции if (!price.HasValue && execReport.brokerResponse.Status == OrderStatus.Исполнен) { loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, LogMagicNoQuoteInPositiveReport, 1000 * 60 * 15, "Отчет брокера по запросу [{0}]: статус \"Исполнен\", нет цены", clientId); return; } execReport.brokerResponse.Price = price ?? 0; // сообщение об ошибке execReport.brokerResponse.RejectReason = OrderRejectReason.None; if (execReport.brokerResponse.Status != OrderStatus.Исполнен) { if (msg.fieldValues.ContainsKey(FixMessage.TAG_ORD_REJECT_REASON)) { var rejectReasonStr = msg[FixMessage.TAG_ORD_REJECT_REASON]; execReport.brokerResponse.RejectReason = rejectReasonStr == FixMessage.VALUE_ORDER_REJECT_BROKER_EXCHANGE_OPT ? OrderRejectReason.BrokerExchangeOption : rejectReasonStr == FixMessage.VALUE_ORDER_REJECT_DUPLICATE_ORDER ? OrderRejectReason.DuplicateClOrdID : rejectReasonStr == FixMessage.VALUE_ORDER_REJECT_UNKNOWN_ORDER ? OrderRejectReason.UnknownOrder : OrderRejectReason.None; execReport.brokerResponse.RejectReasonString = rejectReasonStr; } } } catch (Exception ex) { loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, LogMagicCommonReportParseError, 1000 * 60 * 15, "Общая ошибка обработки ответа провайдера: {0}", ex); return; } // отправить отчет FIX-дилеру try { execReport.SendToQueue(false); } catch (Exception ex) { loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Debug, LogMagicSendReportError, 1000 * 60 * 15, "Ошибка отправки сообщения в очередь: {0}", ex); } }