/// <summary> /// Handle order events from IB /// </summary> private void HandleOrderStatusUpdates(object sender, IB.OrderStatusEventArgs update) { try { if (update.Status == IB.OrderStatus.PreSubmitted || update.Status == IB.OrderStatus.PendingSubmit) { return; } var status = ConvertOrderStatus(update.Status); if (status != OrderStatus.PartiallyFilled && status != OrderStatus.Filled && status != OrderStatus.Canceled && status != OrderStatus.Submitted && status != OrderStatus.Invalid) { Log.Trace("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Status: " + status); return; } if (status == OrderStatus.Invalid) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): ERROR -- " + update.OrderId); } var order = _orderProvider.GetOrderByBrokerageId(update.OrderId); if (order == null) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to locate order with BrokerageID " + update.OrderId); return; } // mark sells as negative quantities var fillQuantity = order.Direction == OrderDirection.Buy ? update.Filled : -update.Filled; var orderEvent = new OrderEvent(order, "Interactive Brokers Fill Event") { Status = status, FillPrice = update.AverageFillPrice, FillQuantity = fillQuantity }; if (update.Remaining != 0) { orderEvent.Message += " - " + update.Remaining + " remaining"; } // if we're able to add to our fixed length, unique queue then send the event // otherwise it is a duplicate, so skip it if (_recentOrderEvents.Add(orderEvent.ToString() + update.Remaining)) { OnOrderEvent(orderEvent); } } catch(InvalidOperationException err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to resolve executions for BrokerageID: " + update.OrderId + " - " + err.Message); } catch (Exception err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): " + err.Message); } }
/// <summary> /// Handle order events from IB /// </summary> private void HandleOrderStatusUpdates(object sender, IB.OrderStatusEventArgs update) { try { var order = _orderProvider.GetOrderByBrokerageId(update.OrderId); if (order == null) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to locate order with BrokerageID " + update.OrderId); return; } var status = ConvertOrderStatus(update.Status); if (order.Status == OrderStatus.Filled && update.Filled == 0 && update.Remaining == 0) { // we're done with this order, remove from our state int value; _orderFills.TryRemove(order.Id, out value); } var orderFee = 0m; int filledThisTime; lock (_orderFillsLock) { // lock since we're getting and updating in multiple operations var currentFilled = _orderFills.GetOrAdd(order.Id, 0); if (currentFilled == 0) { // apply order fees on the first fill event TODO: What about partial filled orders that get cancelled? var security = _securityProvider.GetSecurity(order.Symbol); orderFee = security.FeeModel.GetOrderFee(security, order); } filledThisTime = update.Filled - currentFilled; _orderFills.AddOrUpdate(order.Id, currentFilled, (sym, filled) => update.Filled); } if (status == OrderStatus.Invalid) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): ERROR -- " + update.OrderId); } // set status based on filled this time if (filledThisTime != 0) { status = update.Remaining != 0 ? OrderStatus.PartiallyFilled : OrderStatus.Filled; } // don't send empty fill events else if (status == OrderStatus.PartiallyFilled || status == OrderStatus.Filled) { Log.Trace("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Ignored zero fill event: OrderId: " + update.OrderId + " Remaining: " + update.Remaining); return; } // mark sells as negative quantities var fillQuantity = order.Direction == OrderDirection.Buy ? filledThisTime : -filledThisTime; order.PriceCurrency = _securityProvider.GetSecurity(order.Symbol).SymbolProperties.QuoteCurrency; var orderEvent = new OrderEvent(order, DateTime.UtcNow, orderFee, "Interactive Brokers Fill Event") { Status = status, FillPrice = update.LastFillPrice, FillQuantity = fillQuantity }; if (update.Remaining != 0) { orderEvent.Message += " - " + update.Remaining + " remaining"; } // if we're able to add to our fixed length, unique queue then send the event // otherwise it is a duplicate, so skip it if (_recentOrderEvents.Add(orderEvent.ToString() + update.Remaining)) { OnOrderEvent(orderEvent); } } catch(InvalidOperationException err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to resolve executions for BrokerageID: " + update.OrderId + " - " + err); } catch (Exception err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): " + err); } }
/// <summary> /// Handle order events from IB /// </summary> private void HandleOrderStatusUpdates(object sender, IB.OrderStatusEventArgs update) { try { if (update.Status == IB.OrderStatus.PreSubmitted || update.Status == IB.OrderStatus.PendingSubmit) { return; } var status = ConvertOrderStatus(update.Status); if (status != OrderStatus.PartiallyFilled && status != OrderStatus.Filled && status != OrderStatus.Canceled && status != OrderStatus.Submitted && status != OrderStatus.Invalid) { Log.Trace("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Status: " + status); return; } if (status == OrderStatus.Invalid) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): ERROR -- " + update.OrderId); } var order = _orderProvider.GetOrderByBrokerageId(update.OrderId); if (order == null) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to locate order with BrokerageID " + update.OrderId); return; } int filledThisTime; lock (_orderFillsLock) { // lock since we're getting and updating in multiple operations var currentFilled = _orderFills.GetOrAdd(order.Symbol, 0); filledThisTime = update.Filled - currentFilled; _orderFills.AddOrUpdate(order.Symbol, currentFilled, (sym, filled) => update.Filled); } // don't send empty fill events if (filledThisTime == 0 && (status == OrderStatus.PartiallyFilled || status == OrderStatus.Filled)) { Log.Trace("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Ignored zero fill event: OrderId: " + update.OrderId + " Remaining: " + update.Remaining); return; } // mark sells as negative quantities var fillQuantity = order.Direction == OrderDirection.Buy ? filledThisTime : -filledThisTime; const int orderFee = 0; var orderEvent = new OrderEvent(order, DateTime.UtcNow, orderFee, "Interactive Brokers Fill Event") { Status = status, FillPrice = update.LastFillPrice, FillQuantity = fillQuantity }; if (update.Remaining != 0) { orderEvent.Message += " - " + update.Remaining + " remaining"; } // if we're able to add to our fixed length, unique queue then send the event // otherwise it is a duplicate, so skip it if (_recentOrderEvents.Add(orderEvent.ToString() + update.Remaining)) { OnOrderEvent(orderEvent); } } catch(InvalidOperationException err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): Unable to resolve executions for BrokerageID: " + update.OrderId + " - " + err); } catch (Exception err) { Log.Error("InteractiveBrokersBrokerage.HandleOrderStatusUpdates(): " + err); } }
/// <summary> /// Order fill event handler. On an order fill update the resulting information is passed to this method. /// </summary> /// <param name="orderEvent">Order event details containing details of the evemts</param> /// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks> public override void OnOrderEvent(OrderEvent orderEvent) { Log(orderEvent.ToString()); }
public override void OnOrderEvent(OrderEvent orderEvent) { if (orderEvent.Status == OrderStatus.Filled) { Log("FILLED:: " + Transactions.GetOrderById(orderEvent.OrderId) + " FILL PRICE:: " + orderEvent.FillPrice.SmartRounding()); } else { Log(orderEvent.ToString()); Log("TICKET:: " + _tickets.Last()); } }
public override void OnOrderEvent(OrderEvent orderEvent) { if (_immediateCancellations.Contains(orderEvent.OrderId)) { _immediateCancellations.Remove(orderEvent.OrderId); Transactions.CancelOrder(orderEvent.OrderId); } if (orderEvent.Status == OrderStatus.Filled) { Log("FILLED:: " + Transactions.GetOrderById(orderEvent.OrderId) + " FILL PRICE:: " + orderEvent.FillPrice.SmartRounding()); } else { Log(orderEvent.ToString()); } }
public override void OnOrderEvent(Orders.OrderEvent orderEvent) { Log(orderEvent.ToString()); }