public void SendFill(MessageFIX4_2 packetFIX) { var clientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out clientOrderId); var originalClientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out originalClientOrderId); if (debug) { log.Debug("SendFill( " + packetFIX.ClientOrderId + ")"); } var symbolInfo = Factory.Symbol.LookupSymbol(packetFIX.Symbol); var timeZone = new SymbolTimeZone(symbolInfo); SymbolAlgorithm algorithm; if (!TryGetAlgorithm(symbolInfo.BinaryIdentifier, out algorithm)) { log.Info("Fill received but OrderAlgorithm not found for " + symbolInfo + ". Ignoring."); return; } var fillPosition = packetFIX.LastQuantity * SideToSign(packetFIX.Side); if (GetSymbolStatus(symbolInfo)) { CreateOrChangeOrder order; if (OrderStore.TryGetOrderById(clientOrderId, out order)) { TimeStamp executionTime; if (UseLocalFillTime) { executionTime = TimeStamp.UtcNow; } else { executionTime = new TimeStamp(packetFIX.TransactionTime); } var configTime = executionTime; configTime.AddSeconds(timeZone.UtcOffset(executionTime)); var fill = Factory.Utility.PhysicalFill(fillPosition, packetFIX.LastPrice, configTime, executionTime, order.BrokerOrder, false, packetFIX.OrderQuantity, packetFIX.CumulativeQuantity, packetFIX.LeavesQuantity, IsRecovered, true); if (debug) { log.Debug("Sending physical fill: " + fill); } algorithm.OrderAlgorithm.ProcessFill(fill); algorithm.OrderAlgorithm.ProcessOrders(); TrySendStartBroker(symbolInfo, "position sync on fill"); } else { algorithm.OrderAlgorithm.IncreaseActualPosition(fillPosition); log.Notice("Fill id " + packetFIX.ClientOrderId + " not found. Must have been a manual trade."); if (SyncTicks.Enabled) { var tickSync = SyncTicks.GetTickSync(symbolInfo.BinaryIdentifier); tickSync.RemovePhysicalFill(packetFIX.ClientOrderId); } } } }
private void ExecutionReport(MessageFIX4_2 packetFIX) { var clientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out clientOrderId); var originalClientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out originalClientOrderId); if (packetFIX.Text == "END") { throw new ApplicationException("Unexpected END in FIX Text field. Never sent a 35=AF message."); } SymbolAlgorithm algorithm = null; SymbolInfo symbolInfo = packetFIX.Symbol != null?Factory.Symbol.LookupSymbol(packetFIX.Symbol) : null; if (symbolInfo != null) { TryGetAlgorithm(symbolInfo.BinaryIdentifier, out algorithm); } string orderStatus = packetFIX.OrderStatus; switch (orderStatus) { case "0": // New if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport New: " + packetFIX); } if (algorithm == null) { log.Info("New order but OrderAlgorithm not found for " + symbolInfo + ". Ignoring."); break; } CreateOrChangeOrder order = null; OrderStore.TryGetOrderById(clientOrderId, out order); if (order != null && symbolInfo.FixSimulationType == FIXSimulationType.BrokerHeldStopOrder) // Stop Order { if (order.Type == OrderType.BuyStop || order.Type == OrderType.SellStop) { if (debug) { log.Debug("New order message for Forex Stop: " + packetFIX); } break; } } algorithm.OrderAlgorithm.ConfirmCreate(clientOrderId, IsRecovered); TrySendStartBroker(symbolInfo, "sync on confirm cancel"); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "1": // Partial if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Partial: " + packetFIX); } //UpdateOrder(packetFIX, OrderState.Active, null); SendFill(packetFIX); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "2": // Filled if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Filled: " + packetFIX); } if (packetFIX.CumulativeQuantity < packetFIX.LastQuantity) { log.Warn("Ignoring message due to CumQty " + packetFIX.CumulativeQuantity + " less than " + packetFIX.LastQuantity + ". This is a workaround for a MBT FIX server which sends an extra invalid fill message on occasion."); break; } SendFill(packetFIX); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "5": // Replaced if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Replaced: " + packetFIX); } if (algorithm == null) { log.Info("ConfirmChange but OrderAlgorithm not found for " + symbolInfo + ". Ignoring."); break; } algorithm.OrderAlgorithm.ConfirmChange(clientOrderId, IsRecovered); TrySendStartBroker(symbolInfo, "sync on confirm change"); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "4": // Canceled if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Canceled: " + packetFIX); } if (algorithm == null) { log.Info("Order Canceled but OrderAlgorithm not found for " + symbolInfo + ". Ignoring."); break; } if (clientOrderId != 0) { algorithm.OrderAlgorithm.ConfirmCancel(clientOrderId, IsRecovered); TrySendStartBroker(symbolInfo, "sync on confirm cancel"); } else if (originalClientOrderId != 0) { algorithm.OrderAlgorithm.ConfirmCancel(originalClientOrderId, IsRecovered); TrySendStartBroker(symbolInfo, "sync on confirm cancel orig order"); } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "6": // Pending Cancel if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Pending Cancel: " + packetFIX); } if (!string.IsNullOrEmpty(packetFIX.Text) && packetFIX.Text.Contains("multifunction order")) { if (debug && (LogRecovery || IsRecovered)) { log.Debug("Pending cancel of multifunction order, so removing " + packetFIX.ClientOrderId + " and " + packetFIX.OriginalClientOrderId); } if (clientOrderId != 0L) { OrderStore.RemoveOrder(clientOrderId); } if (originalClientOrderId != 0L) { OrderStore.RemoveOrder(originalClientOrderId); } break; } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); TryHandlePiggyBackFill(packetFIX); break; case "8": // Rejected if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Reject: " + packetFIX); } RejectOrder(packetFIX); break; case "9": // Suspended if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Suspended: " + packetFIX); } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "A": // PendingNew if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Pending New: " + packetFIX); } if (algorithm == null) { log.Info("PendingNew but OrderAlgorithm not found for " + symbolInfo + ". Ignoring."); break; } OrderStore.TryGetOrderById(clientOrderId, out order); if (order != null && symbolInfo.FixSimulationType == FIXSimulationType.BrokerHeldStopOrder && (order.Type == OrderType.BuyStop || order.Type == OrderType.SellStop)) { if (packetFIX.ExecutionType == "D") // Restated { if (debug) { log.Debug("Ignoring restated message 150=D for Forex stop execution report 39=A."); } } else { algorithm.OrderAlgorithm.ConfirmCreate(originalClientOrderId, IsRecovered); } } else { algorithm.OrderAlgorithm.ConfirmActive(originalClientOrderId, IsRecovered); } TrySendStartBroker(symbolInfo, "sync on confirm cancel orig order"); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); break; case "E": // Pending Replace if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Pending Replace: " + packetFIX); } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); TryHandlePiggyBackFill(packetFIX); break; case "R": // Resumed. if (debug && (LogRecovery || !IsRecovery)) { log.Debug("ExecutionReport Resumed: " + packetFIX); } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); //UpdateOrder(packetFIX, OrderState.Active, null); // Ignore break; default: throw new ApplicationException("Unknown order status: '" + orderStatus + "'"); } }
private void CancelRejected(MessageFIX4_2 packetFIX) { var clientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out clientOrderId); var originalClientOrderId = 0L; long.TryParse(packetFIX.ClientOrderId, out originalClientOrderId); if (debug && (LogRecovery || !IsRecovery)) { log.Debug("CancelRejected: " + packetFIX); } string orderStatus = packetFIX.OrderStatus; switch (orderStatus) { case "2": //Filled var rejectReason = false; if (packetFIX.Text.Contains("Unknown order") || packetFIX.Text.Contains("Order is completed")) { rejectReason = true; log.Warn("RemoveOriginal=FALSE for: " + packetFIX.Text); //removeOriginal = true; } else { log.Error("Unknown text meesage in CancelReject: " + packetFIX.Text); } CreateOrChangeOrder order; if (OrderStore.TryGetOrderById(clientOrderId, out order)) { var symbol = order.Symbol; SymbolAlgorithm algorithm; if (!TryGetAlgorithm(symbol.BinaryIdentifier, out algorithm)) { log.Info("Cancel rejected but OrderAlgorithm not found for " + symbol + ". Ignoring."); break; } var retryImmediately = true; algorithm.OrderAlgorithm.RejectOrder(clientOrderId, IsRecovered, retryImmediately); } else { if (debug) { log.Debug("Order not found for " + clientOrderId + ". Probably allready filled or canceled."); } } if (!rejectReason && IsRecovered) { var message = "Order Rejected: " + packetFIX.Text + "\n" + packetFIX; var stopping = "The cancel reject error message '" + packetFIX.Text + "' was unrecognized. "; log.Warn(message); log.Error(stopping); } else { if (LogRecovery || !IsRecovery) { log.Info("CancelReject(" + packetFIX.Text + ") Removed cancel order: " + packetFIX.ClientOrderId); } } break; default: throw new ApplicationException("Unknown cancel rejected order status: '" + orderStatus + "'"); } }
private void OnCreateOrChangeBrokerOrder(CreateOrChangeOrder order, bool resend) { var fixMsg = (FIXMessage4_2)(resend ? FixFactory.Create(order.Sequence) : FixFactory.Create()); order.Sequence = fixMsg.Sequence; OrderStore.SetOrder(order); OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); if (order.Size > order.Symbol.MaxOrderSize) { throw new ApplicationException("Order was greater than MaxOrderSize of " + order.Symbol.MaxPositionSize + " for:\n" + order); } var orderHandler = GetAlgorithm(order.Symbol.BinaryIdentifier); var orderSize = order.Type == OrderType.SellLimit || order.Type == OrderType.SellMarket || order.Type == OrderType.SellStop ? -order.Size : order.Size; if (Math.Abs(orderHandler.OrderAlgorithm.ActualPosition + orderSize) > order.Symbol.MaxPositionSize) { throw new ApplicationException("Order was greater than MaxPositionSize of " + order.Symbol.MaxPositionSize + " for:\n" + order); } if (debug) { log.Debug("Adding Order to open order list: " + order); } if (order.Action == OrderAction.Change) { var origBrokerOrder = order.OriginalOrder.BrokerOrder; fixMsg.SetClientOrderId(order.BrokerOrder.ToString()); fixMsg.SetOriginalClientOrderId(origBrokerOrder.ToString()); CreateOrChangeOrder origOrder; if (OrderStore.TryGetOrderById(origBrokerOrder, out origOrder)) { origOrder.ReplacedBy = order; if (debug) { log.Debug("Setting replace property of " + origBrokerOrder + " to " + order.BrokerOrder); } } } else { fixMsg.SetClientOrderId(order.BrokerOrder.ToString()); } if (order.Action == OrderAction.Change) { fixMsg.AddHeader("G"); } else { fixMsg.AddHeader("D"); if (order.Symbol.Destination.ToLower() == "default") { fixMsg.SetDestination(Destination); } else { fixMsg.SetDestination(order.Symbol.Destination); } } fixMsg.SetSymbol(order.Symbol.Symbol); fixMsg.SetSide(order.Side == OrderSide.Buy ? 1 : 5); switch (order.Type) { case OrderType.BuyLimit: fixMsg.SetOrderType(2); fixMsg.SetPrice(order.Price); switch (order.Symbol.TimeInForce) { case TimeInForce.Day: fixMsg.SetTimeInForce(0); break; case TimeInForce.GTC: throw new LimeException("Lime does not accept GTC Buy Lime Orders"); default: throw new ArgumentOutOfRangeException(); } break; case OrderType.BuyMarket: fixMsg.SetOrderType(1); //fixMsg.SetTimeInForce(0); break; case OrderType.BuyStop: // throw new LimeException("Lime does not accept Buy Stop Orders"); log.Error("Lime: Buy Stops not supproted"); break; case OrderType.SellLimit: fixMsg.SetOrderType(2); fixMsg.SetPrice(order.Price); switch (order.Symbol.TimeInForce) { case TimeInForce.Day: fixMsg.SetTimeInForce(0); break; case TimeInForce.GTC: throw new LimeException("Lime does not accept GTC Buy Lime Orders"); default: throw new ArgumentOutOfRangeException(); } break; case OrderType.SellMarket: fixMsg.SetOrderType(1); //fixMsg.SetTimeInForce(0); break; case OrderType.SellStop: //throw new LimeException("Lime does not accept Sell Stop Orders"); log.Error("Lime: Sell Stops not supproted"); break; default: throw new LimeException("Unknown OrderType"); } fixMsg.SetOrderQuantity((int)order.Size); if (order.Action == OrderAction.Change) { if (verbose) { log.Verbose("Change order: \n" + fixMsg); } } else { if (verbose) { log.Verbose("Create new order: \n" + fixMsg); } } if (resend) { fixMsg.SetDuplicate(true); } #if NOT_LIME fixMsg.SetAccount(AccountNumber); fixMsg.SetHandlingInstructions(1); fixMsg.SetLocateRequired("N"); fixMsg.SetTransactTime(order.UtcCreateTime); fixMsg.SetOrderCapacity("A"); fixMsg.SetUserName(); #endif fixMsg.SetSendTime(order.UtcCreateTime); SendMessage(fixMsg); }