/// <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());
            }
        }
Example #7
0
 public override void OnOrderEvent(Orders.OrderEvent orderEvent)
 {
     Log(orderEvent.ToString());
 }