private OrderFilled GenerateOrderFilledEvent(ExecutionReport message) { var orderId = this.GetOrderId(message); var executionId = new ExecutionId(message.GetField(Tags.ExecID)); var positionIdBroker = new PositionIdBroker(message.GetField(FxcmTags.PosID)); var symbol = this.GetSymbol(message.GetString(Tags.Symbol)); var orderSide = FxcmMessageHelper.GetOrderSide(message.GetField(Tags.Side)); var filledQuantity = Quantity.Create(message.GetDecimal(Tags.CumQty)); var averagePrice = Price.Create(message.GetDecimal(Tags.AvgPx)); var quoteCurrency = this.GetQuoteCurrency(symbol, message.GetField(Tags.Currency)); var executionTime = FxcmMessageHelper.ParseTimestamp(message.GetField(Tags.TransactTime)); return(new OrderFilled( this.accountId, orderId, executionId, positionIdBroker, symbol, orderSide, filledQuantity, averagePrice, quoteCurrency, executionTime, this.NewGuid(), this.TimeNow())); }
public override object GetField(Fields field) { if (ExecutionReport == null) { return(ExecutionReportFields.NULL); } if (field == Fields.KEY) { return(Key); } else { ExecutionReportFields xrField = (ExecutionReportFields)field; if (xrField == ExecutionReportFields.OrderID) { return(GetOrdId(ExecutionReport, QuickFix.Fields.Tags.OrderID)); } else if (xrField == ExecutionReportFields.ClOrdID) { return(GetOrdId(ExecutionReport, QuickFix.Fields.Tags.ClOrdID)); } else if (xrField == ExecutionReportFields.OrigClOrdID) { return(GetOrdId(ExecutionReport, QuickFix.Fields.Tags.OrigClOrdID)); } else if (xrField == ExecutionReportFields.ExecType) { return(GetExecType(ExecutionReport.GetChar(QuickFix.Fields.Tags.ExecType))); } else if (xrField == ExecutionReportFields.ExecID) { return(ExecutionReport.GetString(QuickFix.Fields.Tags.ExecID)); } else if (xrField == ExecutionReportFields.OrdStatus) { return(GetOrdStatus(ExecutionReport.GetChar(QuickFix.Fields.Tags.OrdStatus))); } else if (xrField == ExecutionReportFields.OrdRejReason) { return(FixHelper.GetNullIntFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.OrdRejReason)); } else if (xrField == ExecutionReportFields.LeavesQty) { return(ExecutionReport.GetInt(QuickFix.Fields.Tags.LeavesQty)); } else if (xrField == ExecutionReportFields.CumQty) { return(ExecutionReport.GetInt(QuickFix.Fields.Tags.CumQty)); } else if (xrField == ExecutionReportFields.AvgPx) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.AvgPx)); } else if (xrField == ExecutionReportFields.Commission) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.Commission)); } else if (xrField == ExecutionReportFields.Text) { return(ExecutionReport.GetField(QuickFix.Fields.Tags.Text)); } else if (xrField == ExecutionReportFields.TransactTime) { return(DateTime.Now); } else if (xrField == ExecutionReportFields.LastQty) { return(FixHelper.GetNullIntFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.LastQty)); } else if (xrField == ExecutionReportFields.LastPx) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.LastPx)); } else if (xrField == ExecutionReportFields.LastMkt) { return(FixHelper.GetNullFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.LastMkt)); } else if (xrField == ExecutionReportFields.Symbol) { return(FixHelper.GetNullFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.Symbol)); } else if (xrField == ExecutionReportFields.OrderQty) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.OrderQty)); } else if (xrField == ExecutionReportFields.CashOrderQty) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.CashOrderQty)); } else if (xrField == ExecutionReportFields.OrdType) { return(GetOrdType(ExecutionReport.GetChar(QuickFix.Fields.Tags.OrdType))); } else if (xrField == ExecutionReportFields.Price) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.Price)); } else if (xrField == ExecutionReportFields.StopPx) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.StopPx)); } else if (xrField == ExecutionReportFields.Currency) { return(FixHelper.GetNullFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.Currency)); } else if (xrField == ExecutionReportFields.ExpireDate) { return(FixHelper.GetDateTimeFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.ExpireDate)); } else if (xrField == ExecutionReportFields.MinQty) { return(FixHelper.GetNullDoubleFieldIfSet(ExecutionReport, QuickFix.Fields.Tags.MinQty)); } else if (xrField == ExecutionReportFields.Side) { GetSide(ExecutionReport.GetChar(QuickFix.Fields.Tags.Side)); } else if (xrField == ExecutionReportFields.QuantityType) { return(QuantityType.SHARES); } else if (xrField == ExecutionReportFields.PriceType) { return(PriceType.FixedAmount); } else if (xrField == ExecutionReportFields.Account) { return(ExecutionReport.GetField(QuickFix.Fields.Tags.Account)); } else if (xrField == ExecutionReportFields.ExecInst) { return(ExecutionReport.GetField(QuickFix.Fields.Tags.ExecInst)); } } return(ExecutionReportFields.NULL); }
private async void Handle(ExecutionReport msg) { var clOrderId = msg.ClOrdID.Obj; string origClOrderId = null; if (msg.IsSetOrigClOrdID()) { origClOrderId = msg.OrigClOrdID.Obj; } var state = msg.IsSetOrdStatus() ? ConvertOrderState(msg.OrdStatus) : null; var price = msg.IsSetPrice() ? msg.Price.Obj : (decimal?)null; price = price != 0M ? price : null; var qty = msg.IsSetOrderQty() ? (uint)msg.OrderQty.Obj : (uint?)null; var filledQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null; var activeQty = msg.IsSetLeavesQty() ? (uint)msg.LeavesQty.Obj : (uint?)null; var time = msg.IsSetTransactTime() ? ParseTransactTime() : DateTime.Now; var orderExchangeId = msg.IsSetOrderID() ? msg.OrderID.Obj : null; var transactionId = _orders.GetOrCreateOrderTransactionId(origClOrderId ?? clOrderId); var oscm = new OrderStateChangeMessage { TransactionId = transactionId, State = state, Price = price, Quantity = qty, FilledQuantity = filledQty, ActiveQuantity = activeQty, ChangeTime = time, OrderExchangeId = orderExchangeId }; switch (msg.ExecType.Obj) { case ExecType.NEW: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); break; case ExecType.TRADE: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); if (oscm.State == OrderState.Filled) { _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); } break; case ExecType.FILL: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); if (oscm.State == OrderState.Filled) { _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); } break; case ExecType.PARTIAL_FILL: _newOrderTransactions.Accept(clOrderId); _orders.SaveOrderExchangeId(transactionId, orderExchangeId); SendMessage(oscm); await EmitFillAsync(); break; case ExecType.REJECTED: string rejectReason; switch (msg.OrdRejReason.Obj) { case OrdRejReason.UNKNOWN_SYMBOL: rejectReason = "Unknown symbol"; break; case OrdRejReason.EXCHANGE_CLOSED: rejectReason = "Exchange closed"; break; case OrdRejReason.ORDER_EXCEEDS_LIMIT: rejectReason = "Order exceeds limit"; break; case OrdRejReason.DUPLICATE_ORDER: rejectReason = "Duplicate order"; break; default: rejectReason = $"#{msg.OrdRejReason.Obj}"; break; } if (!string.IsNullOrEmpty(msg.Text?.Obj)) { rejectReason = $"{rejectReason}. {msg.Text?.Obj}"; } _newOrderTransactions.Reject(clOrderId, rejectReason); _orders.ForgetOrder(transactionId); break; case ExecType.PENDING_CANCEL: _killOrderTransactions.Accept(msg.ClOrdID.Obj); SendMessage(oscm); break; case ExecType.CANCELED: _killOrderTransactions.Accept(msg.ClOrdID.Obj); _newOrderTransactions.Forget(transactionId); _killOrderTransactions.Forget(msg.ClOrdID.Obj); _orders.ForgetOrder(transactionId); SendMessage(oscm); break; case ExecType.PENDING_REPLACE: _modifyOrderTransactions.Accept(clOrderId); break; case ExecType.REPLACED: _newOrderTransactions.Forget(origClOrderId); _killOrderTransactions.Forget(clOrderId); _orders.UpdateOrderParams( orderExchangeId: orderExchangeId, origClOrderId: origClOrderId, clOrderId: clOrderId, symbol: msg.Symbol.Obj, qty: msg.OrderQty.Obj, side: msg.Side.Obj); SendMessage(oscm); break; default: _Log.Warn().PrintFormat("Unknown ExecType: {0}", msg.ExecType.Obj); break; } OrderState?ConvertOrderState(OrdStatus field) { switch (field.Obj) { case OrdStatus.PENDING_NEW: return(OrderState.New); case OrdStatus.NEW: return(OrderState.Active); case OrdStatus.CANCELED: return(OrderState.Cancelled); case OrdStatus.FILLED: return(OrderState.Filled); case OrdStatus.PARTIALLY_FILLED: return(OrderState.PartiallyFilled); case OrdStatus.REJECTED: return(OrderState.Error); case OrdStatus.PENDING_CANCEL: return(null); case OrdStatus.PENDING_REPLACE: return(null); default: _Log.Warn().PrintFormat("Unknown OrdStatus: {0}", field.Obj); return(null); } } DateTime ParseTransactTime() { var maxLen = "20170912-09:39:57.2761221".Length; var str = msg.GetString(60 /*TransactTime*/); if (str.Length > maxLen) { str = str.Substring(0, maxLen); } var t = DateTime.ParseExact(str, "yyyyMMdd-HH:mm:ss.fffffff", null, DateTimeStyles.AssumeUniversal); return(t); } async Task EmitFillAsync() { if (!msg.IsSetSecondaryExecID()) { return; } var fillExchangeId = msg.SecondaryExecID.Obj; var fillPrice = msg.IsSetLastPx() ? msg.LastPx.Obj : (decimal?)null; price = price != 0M ? price : null; var fillQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null; if (fillPrice == null || fillQty == null) { return; } Instrument instrument; try { instrument = await _settings.InstrumentConverter.ResolveSymbolAsync(this, msg.Symbol.Obj); } catch (Exception e) { _Log.Error().Print(e, $"Failed to resolve instrument {msg.Symbol.Obj}"); return; } var fill = new FillMessage { Price = fillPrice.Value, Quantity = fillQty.Value, DateTime = time, Instrument = instrument, Account = msg.Account.Obj, Operation = msg.Side.Obj == Side.BUY ? OrderOperation.Buy : OrderOperation.Sell, ExchangeId = fillExchangeId, ExchangeOrderId = orderExchangeId }; SendMessage(fill); } }