protected override void HandleUnexpectedLogout(MessageFIXT1_1 message) { bool handled = false; var message42 = (MessageFIX4_2)message; if (message42.Text != null) { // If our sequences numbers don't match, Lime sends a logout with a message // telling us what we should be at. So if we can, we just use that when we reconnect. if (message42.Text.StartsWith("MsgSeqNum too low")) { var match = Regex.Match(message42.Text, "expecting (\\d+)"); int newSequenceNumber = 0; if (match.Success && int.TryParse(match.Groups[1].Value, out newSequenceNumber) && newSequenceNumber >= OrderStore.LocalSequence) { log.Error(message42.Text); OrderStore.SetSequences(OrderStore.RemoteSequence, newSequenceNumber); Socket.Dispose(); handled = true; RetryStart = 2; ignoreRetryDelay = true; } } else { base.HandleUnexpectedLogout(message); throw new LimeException(string.Format("Lime logged out with error '{0}'", message42.Text)); } } if (!handled) { base.HandleUnexpectedLogout(message); } }
public override bool OnLogin() { if (debug) { log.Debug("LimeFIXProvider.Login()"); } if (OrderStore.Recover()) { // Reset the order algorithms lock (orderAlgorithmsLocker) { var symbolIds = new List <long>(); foreach (var kvp in orderAlgorithms) { symbolIds.Add(kvp.Key); } orderAlgorithms.Clear(); foreach (var symbolId in symbolIds) { CreateAlgorithm(symbolId); } } if (debug) { log.Debug("Recovered from snapshot Local Sequence " + OrderStore.LocalSequence + ", Remote Sequence " + OrderStore.RemoteSequence); } if (debug) { log.Debug("Recovered orders from snapshot: \n" + OrderStore.OrdersToString()); } if (debug) { log.Debug("Recovered symbol positions from snapshot:\n" + OrderStore.SymbolPositionsToString()); } if (debug) { log.Debug("Recovered strategy positions from snapshot:\n" + OrderStore.StrategyPositionsToString()); } RemoteSequence = OrderStore.RemoteSequence; SendLogin(OrderStore.LocalSequence); OrderStore.RequestSnapshot(); } else { if (debug) { log.Debug("Unable to recover from snapshot. Beginning full recovery."); } OrderStore.SetSequences(0, 0); OrderStore.ForceSnapshot(); SendLogin(OrderStore.LocalSequence); } return(true); }
public bool OnCancelBrokerOrder(CreateOrChangeOrder order) { if (!IsRecovered) { return(false); } if (debug) { log.Debug("OnCancelBrokerOrder " + order + ". Connection " + ConnectionStatus + ", IsOrderServerOnline " + isOrderServerOnline); } OrderStore.SetSequences(RemoteSequence, FixFactory.LastSequence); CreateOrChangeOrder createOrChangeOrder; try { createOrChangeOrder = OrderStore.GetOrderById(order.OriginalOrder.BrokerOrder); } catch (ApplicationException ex) { if (LogRecovery || !IsRecovery) { log.Info("Order probably already canceled. " + ex.Message); } if (SyncTicks.Enabled) { var tickSync = SyncTicks.GetTickSync(order.Symbol.BinaryIdentifier); tickSync.RemovePhysicalOrder(); } return(true); } createOrChangeOrder.ReplacedBy = order; if (!object.ReferenceEquals(order.OriginalOrder, createOrChangeOrder)) { throw new ApplicationException("Different objects!"); } SendCancelOrder(order, false); return(true); }
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 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); }