/********************************************************
        * CLASS PROPERTIES
        *********************************************************/
        /********************************************************
        * CLASS METHODS
        *********************************************************/
        /// <summary>
        /// Perform neccessary check to see if the model has been filled, appoximate the best we can.
        /// </summary>
        /// <param name="vehicle">Asset we're working with</param>
        /// <param name="order">Order class to check if filled.</param>
        public virtual OrderEvent Fill(Security vehicle, Order order)
        {
            //Default order event to return.
            var fill = new OrderEvent(order);

            try
            {
                switch (order.Type)
                {
                    case OrderType.Limit:
                        fill = LimitFill(vehicle, order);
                        break;
                    case OrderType.StopMarket:
                        fill = StopFill(vehicle, order);
                        break;
                    case OrderType.Market:
                        fill = MarketFill(vehicle, order);
                        break;
                }
            } catch (Exception err) {
                Log.Error("SecurityTransactionModel.TransOrderDirection.Fill(): " + err.Message);
            }

            return fill;
        }
        /// <summary>
        /// Default stop fill model implementation in base class security. (Stop Market Order Type)
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        /// <seealso cref="SecurityTransactionModel.LimitFill"/>
        public virtual OrderEvent StopMarketFill(Security asset, StopMarketOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset)) return fill;

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled) return fill;

            //Get the range of prices in the last bar:
            decimal minimumPrice;
            decimal maximumPrice;
            DataMinMaxPrices(asset, out minimumPrice, out maximumPrice, order.Direction);

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Check if the Stop Order was filled: opposite to a limit order
            switch (order.Direction)
            {
                case OrderDirection.Sell:
                    //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                    if (minimumPrice < order.StopPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        // Assuming worse case scenario fill - fill at lowest of the stop & asset price.
                        fill.FillPrice = Math.Min(order.StopPrice, asset.Price - slip); 
                    }
                    break;

                case OrderDirection.Buy:
                    //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                    if (maximumPrice > order.StopPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        // Assuming worse case scenario fill - fill at highest of the stop & asset price.
                        fill.FillPrice = Math.Max(order.StopPrice, asset.Price + slip);
                    }
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
        /// <summary>
        /// Default market fill model for the base security class. Fills at the last traded price.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="SecurityTransactionModel.StopMarketFill"/>
        /// <seealso cref="SecurityTransactionModel.LimitFill"/>
        public virtual OrderEvent MarketFill(Security asset, MarketOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            if (order.Status == OrderStatus.Canceled) return fill;

            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset)) return fill;

            //Order [fill]price for a market order model is the current security price
            fill.FillPrice = asset.Price;
            fill.Status = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Apply slippage
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    fill.FillPrice += slip;
                    break;
                case OrderDirection.Sell:
                    fill.FillPrice -= slip;
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
Exemple #4
0
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     if (orderEvent.Status == OrderStatus.Filled && orderEvent.FillQuantity < 0)
     {
         SecurityHolding s = Securities [orderEvent.Symbol].Holdings;
         var profit_pct = s.LastTradeProfit / Portfolio.TotalPortfolioValue;
         _tradeReturns.Add (profit_pct);
         if (_tradeReturns.Count > MAXRETURNS)
             _tradeReturns.RemoveAt (0);
     }
 }
Exemple #5
0
        private void EmitFillOrder(string[] entries)
        {
            try
            {
                var brokerId = entries[4];
                var order    = CachedOrderIDs
                               .FirstOrDefault(o => o.Value.BrokerId.Contains(brokerId))
                               .Value;
                if (order == null)
                {
                    order = _algorithm.Transactions.GetOrderByBrokerageId(brokerId);
                    if (order == null)
                    {
                        // not our order, nothing else to do here
                        return;
                    }
                }

                var symbol       = _symbolMapper.GetLeanSymbol(entries[2]);
                var fillPrice    = decimal.Parse(entries[6], NumberStyles.Float, CultureInfo.InvariantCulture);
                var fillQuantity = decimal.Parse(entries[5], NumberStyles.Float, CultureInfo.InvariantCulture);
                var direction    = fillQuantity < 0 ? OrderDirection.Sell : OrderDirection.Buy;
                var updTime      = Time.UnixTimeStampToDateTime(double.Parse(entries[3], NumberStyles.Float, CultureInfo.InvariantCulture));
                var orderFee     = new OrderFee(new CashAmount(
                                                    Math.Abs(decimal.Parse(entries[9], NumberStyles.Float, CultureInfo.InvariantCulture)),
                                                    entries[10]
                                                    ));

                var status = OrderStatus.Filled;
                if (fillQuantity != order.Quantity)
                {
                    decimal totalFillQuantity;
                    _fills.TryGetValue(order.Id, out totalFillQuantity);
                    totalFillQuantity += fillQuantity;
                    _fills[order.Id]   = totalFillQuantity;

                    status = totalFillQuantity == order.Quantity
                        ? OrderStatus.Filled
                        : OrderStatus.PartiallyFilled;
                }

                var orderEvent = new OrderEvent
                                 (
                    order.Id, symbol, updTime, status,
                    direction, fillPrice, fillQuantity,
                    orderFee, $"Bitfinex Order Event {direction}"
                                 );

                // if the order is closed, we no longer need it in the active order list
                if (status == OrderStatus.Filled)
                {
                    Order outOrder;
                    CachedOrderIDs.TryRemove(order.Id, out outOrder);
                    decimal ignored;
                    _fills.TryRemove(order.Id, out ignored);
                }

                OnOrderEvent(orderEvent);
            }
            catch (Exception e)
            {
                Log.Error(e);
                throw;
            }
        }
        /// <summary>
        /// Check if the model has stopped out our position yet:
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Stop Order to Check, return filled if true</param>
        public virtual OrderEvent StopFill(Security security, Order order)
        {
            var fill = new OrderEvent(order);
            try
            {
                //If its cancelled don't need anymore checks:
                if (order.Status == OrderStatus.Canceled) return fill;

                //Check if the Stop Order was filled: opposite to a limit order
                if (order.Direction == OrderDirection.Sell)
                {
                    //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                    if (security.Price < order.Price)
                    {
                        //Set the order and slippage on the order, update the fill price:
                        order.Status = OrderStatus.Filled;
                        order.Price = security.Price;   //Fill at the security price, sometimes gap down skip past stop.
                    }
                }
                else if (order.Direction == OrderDirection.Buy)
                {
                    //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                    if (security.Price > order.Price)
                    {
                        order.Status = OrderStatus.Filled;
                        order.Price = security.Price;   //Fill at the security price, sometimes gap down skip past stop.
                    }
                }

                //Set the fill properties when order filled.
                if (order.Status == OrderStatus.Filled || order.Status == OrderStatus.PartiallyFilled)
                {
                    fill.FillQuantity = order.Quantity;
                    fill.FillPrice = security.Price;
                    fill.Status = order.Status;
                }
            }
            catch (Exception err)
            {
                Log.Error("ForexTransactionModel.TransOrderDirection.StopFill(): " + err.Message);
            }
            return fill;
        }
Exemple #7
0
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     OrderEvents.Add(orderEvent);
 }
Exemple #8
0
 public void OrderEvent(OrderEvent newEvent)
 {
 }
Exemple #9
0
 public virtual void OnAssignmentOrderEvent(OrderEvent assignmentEvent)
 {
     //Algo.OnAssignmentOrderEvent(assignmentEvent);
 }
Exemple #10
0
 private void OnEvent(OrderEvent @event)
 {
     TotalEvents++;
     OrderIds.Add(@event.Id);
     AllSeenOrderIds.Add(@event.Id);
 }
Exemple #11
0
        /// <summary>
        /// Default limit if touched fill model implementation in base class security.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <remarks>
        ///     There is no good way to model limit orders with OHLC because we never know whether the market has
        ///     gapped past our fill price. We have to make the assumption of a fluid, high volume market.
        ///
        ///     With Limit if Touched orders, whether or not a trigger is surpassed is determined by the high (low)
        ///     of the previous tradebar when making a sell (buy) request. Following the behaviour of
        ///     <see cref="StopLimitFill"/>, current quote information is used when determining fill parameters
        ///     (e.g., price, quantity) as the tradebar containing the incoming data is not yet consolidated.
        ///     This conservative approach, however, can lead to trades not occuring as would be expected when
        ///     compared to future consolidated data.
        /// </remarks>
        public virtual OrderEvent LimitIfTouchedFill(Security asset, LimitIfTouchedOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // Fill only if open or extended
            if (!IsExchangeOpen(asset,
                                Parameters.ConfigProvider
                                .GetSubscriptionDataConfigs(asset.Symbol)
                                .IsExtendedMarketHours()))
            {
                return(fill);
            }

            // Get the range of prices in the last bar:
            var tradeHigh  = 0m;
            var tradeLow   = 0m;
            var endTimeUtc = DateTime.MinValue;

            var subscribedTypes = GetSubscribedTypes(asset);

            if (subscribedTypes.Contains(typeof(Tick)))
            {
                var trade = asset.Cache.GetAll <Tick>().LastOrDefault(x => x.TickType == TickType.Trade && x.Price > 0);

                if (trade != null)
                {
                    tradeHigh  = trade.Price;
                    tradeLow   = trade.Price;
                    endTimeUtc = trade.EndTime.ConvertToUtc(asset.Exchange.TimeZone);
                }
            }
            else if (subscribedTypes.Contains(typeof(TradeBar)))
            {
                var tradeBar = asset.Cache.GetData <TradeBar>();

                if (tradeBar != null)
                {
                    tradeHigh  = tradeBar.High;
                    tradeLow   = tradeBar.Low;
                    endTimeUtc = tradeBar.EndTime.ConvertToUtc(asset.Exchange.TimeZone);
                }
            }

            // do not fill on stale data
            if (endTimeUtc <= order.Time)
            {
                return(fill);
            }

            //Check if the limit if touched order was filled:
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                //-> 1.2 Buy: If Price below Trigger, Buy:
                if (tradeLow <= order.TriggerPrice || order.TriggerTouched)
                {
                    order.TriggerTouched = true;
                    var askCurrent = GetBestEffortAskPrice(asset, order.Time, out var fillMessage);

                    if (askCurrent <= order.LimitPrice)
                    {
                        fill.Status       = OrderStatus.Filled;
                        fill.FillPrice    = Math.Min(askCurrent, order.LimitPrice);
                        fill.FillQuantity = order.Quantity;
                        fill.Message      = fillMessage;
                    }
                }

                break;

            case OrderDirection.Sell:
                //-> 1.2 Sell: If Price above Trigger, Sell:
                if (tradeHigh >= order.TriggerPrice || order.TriggerTouched)
                {
                    order.TriggerTouched = true;
                    var bidCurrent = GetBestEffortBidPrice(asset, order.Time, out var fillMessage);

                    if (bidCurrent >= order.LimitPrice)
                    {
                        fill.Status       = OrderStatus.Filled;
                        fill.FillPrice    = Math.Max(bidCurrent, order.LimitPrice);
                        fill.FillQuantity = order.Quantity;
                        fill.Message      = fillMessage;
                    }
                }

                break;
            }
            return(fill);
        }
Exemple #12
0
        /// <summary>
        /// Default stop fill model implementation in base class security. (Stop Market Order Type)
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        public virtual OrderEvent StopMarketFill(Security asset, StopMarketOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // make sure the exchange is open/normal market hours before filling
            if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }

            //Get the range of prices in the last bar:
            var prices        = GetPricesCheckingPythonWrapper(asset, order.Direction);
            var pricesEndTime = prices.EndTime.ConvertToUtc(asset.Exchange.TimeZone);

            // do not fill on stale data
            if (pricesEndTime <= order.Time)
            {
                return(fill);
            }

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Check if the Stop Order was filled: opposite to a limit order
            switch (order.Direction)
            {
            case OrderDirection.Sell:
                //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                if (prices.Low < order.StopPrice)
                {
                    fill.Status = OrderStatus.Filled;
                    // Assuming worse case scenario fill - fill at lowest of the stop & asset price.
                    fill.FillPrice = Math.Min(order.StopPrice, prices.Current - slip);
                    // assume the order completely filled
                    fill.FillQuantity = order.Quantity;
                }
                break;

            case OrderDirection.Buy:
                //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                if (prices.High > order.StopPrice)
                {
                    fill.Status = OrderStatus.Filled;
                    // Assuming worse case scenario fill - fill at highest of the stop & asset price.
                    fill.FillPrice = Math.Max(order.StopPrice, prices.Current + slip);
                    // assume the order completely filled
                    fill.FillQuantity = order.Quantity;
                }
                break;
            }

            return(fill);
        }
        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            if (orderEvent.Status == OrderStatus.Filled)
            {
                Log($"OnOrderEvent(): New filled order event: {orderEvent}");
                // leave 1 unit as error in expected value
                if (Math.Abs(orderEvent.FillQuantity - _expectedOrderQuantity) > 1)
                {
                    throw new Exception($"Unexpected order event fill quantity: {orderEvent.FillQuantity}. " +
                                        $"Expected {_expectedOrderQuantity}");
                }

                var orderFeeInAccountCurrency = Portfolio.CashBook.ConvertToAccountCurrency(orderEvent.OrderFee.Value).Amount;
                var expectedOrderFee          = _btcUsd.Holdings.TotalFees - _previousHoldingsFees;

                // just to verify let calculate the order fee using taker fee
                var calculatedOrderFee = Portfolio.CashBook.ConvertToAccountCurrency(
                    orderEvent.AbsoluteFillQuantity * 0.003m * orderEvent.FillPrice,
                    orderEvent.OrderFee.Value.Currency);

                if (orderEvent.OrderFee.Value.Currency == AccountCurrency
                    // leave 0.00001m as error in expected fee value
                    || Math.Abs(expectedOrderFee - orderFeeInAccountCurrency) > 0.00001m ||
                    Math.Abs(expectedOrderFee - calculatedOrderFee) > 0.00001m)
                {
                    throw new Exception($"Unexpected order fee: {orderFeeInAccountCurrency}. " +
                                        $"Expected {expectedOrderFee}. Calculated Order Fee {calculatedOrderFee}");
                }

                if (!TradeBuilder.HasOpenPosition(_btcUsd.Symbol))
                {
                    var lastTrade = TradeBuilder.ClosedTrades.Last();

                    var expectedProfitLoss = (lastTrade.ExitPrice - lastTrade.EntryPrice)
                                             * lastTrade.Quantity
                                             * _btcUsd.QuoteCurrency.ConversionRate
                                             * (lastTrade.Direction == TradeDirection.Long ? 1 : -1);

                    if (Math.Abs(expectedProfitLoss - lastTrade.ProfitLoss) > 1)
                    {
                        throw new Exception($"Unexpected last trade ProfitLoss: {lastTrade.ProfitLoss}. " +
                                            $"Expected {expectedProfitLoss}");
                    }

                    // There is a difference in what does Holdings and TradeBuilder consider LastTrade
                    if (TradeBuilder.ClosedTrades.Count - _previousClosedTradesCount > 1)
                    {
                        var trade = TradeBuilder.ClosedTrades[_previousClosedTradesCount];
                        expectedProfitLoss += trade.ProfitLoss;
                    }

                    if (Math.Abs(_btcUsd.Holdings.LastTradeProfit - expectedProfitLoss) > 1)
                    {
                        throw new Exception($"Unexpected Holdings.NetProfit: {_btcUsd.Holdings.LastTradeProfit}. " +
                                            $"Expected {expectedProfitLoss}");
                    }
                }

                _previousHoldingsFees      = _btcUsd.Holdings.TotalFees;
                _previousClosedTradesCount = TradeBuilder.ClosedTrades.Count;
            }
        }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     Debug(string.Format("OnOrderEvent(OrderEvent): {0}: {1}", Time, orderEvent));
 }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     Debug($"{orderEvent}");
 }
Exemple #16
0
 public override void OnOrderEvent(OrderEvent fill)
 {
     Log($"OnOrderEvent({UtcTime:o}):: {fill}");
 }
Exemple #17
0
        /// <summary>
        /// Market on Open Fill Model. Return an order event with the fill details
        /// </summary>
        /// <param name="asset">Asset we're trading with this order</param>
        /// <param name="order">Order to be filled</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        public OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
        {
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, 0);

            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // MOO should never fill on the same bar or on stale data
            // Imagine the case where we have a thinly traded equity, ASUR, and another liquid
            // equity, say SPY, SPY gets data every minute but ASUR, if not on fill forward, maybe
            // have large gaps, in which case the currentBar.EndTime will be in the past
            // ASUR  | | |      [order]        | | | | | | |
            //  SPY  | | | | | | | | | | | | | | | | | | | |
            var currentBar     = asset.GetLastData();
            var localOrderTime = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);

            if (currentBar == null || localOrderTime >= currentBar.EndTime)
            {
                return(fill);
            }

            // if the MOO was submitted during market the previous day, wait for a day to turn over
            if (asset.Exchange.DateTimeIsOpen(localOrderTime) && localOrderTime.Date == asset.LocalTime.Date)
            {
                return(fill);
            }

            // wait until market open
            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset))
            {
                return(fill);
            }

            fill.FillPrice = GetPrices(asset, order.Direction).Open;
            fill.Status    = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Apply slippage
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                fill.FillPrice += slip;
                break;

            case OrderDirection.Sell:
                fill.FillPrice -= slip;
                break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee     = asset.FeeModel.GetOrderFee(asset, order);
            }

            return(fill);
        }
        /// <summary>
        /// Default limit order fill model in the base security class.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        public virtual OrderEvent LimitFill(Security asset, LimitOrder order)
        {
            //Initialise;
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled) return fill;

            //Get the range of prices in the last bar:
            decimal minimumPrice;
            decimal maximumPrice;
            DataMinMaxPrices(asset, out minimumPrice, out maximumPrice, order.Direction);

            //-> Valid Live/Model Order: 
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    //Buy limit seeks lowest price
                    if (minimumPrice < order.LimitPrice)
                    {
                        //Set order fill:
                        fill.Status = OrderStatus.Filled;
                        // fill at the worse price this bar or the limit price, this allows far out of the money limits
                        // to be executed properly
                        fill.FillPrice = Math.Min(maximumPrice, order.LimitPrice);
                    }
                    break;
                case OrderDirection.Sell:
                    //Sell limit seeks highest price possible
                    if (maximumPrice > order.LimitPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        // fill at the worse price this bar or the limit price, this allows far out of the money limits
                        // to be executed properly
                        fill.FillPrice = Math.Max(minimumPrice, order.LimitPrice);
                    }
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
Exemple #19
0
        /// <summary>
        /// Default stop limit fill model implementation in base class security. (Stop Limit Order Type)
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
        /// <remarks>
        ///     There is no good way to model limit orders with OHLC because we never know whether the market has
        ///     gapped past our fill price. We have to make the assumption of a fluid, high volume market.
        ///
        ///     Stop limit orders we also can't be sure of the order of the H - L values for the limit fill. The assumption
        ///     was made the limit fill will be done with closing price of the bar after the stop has been triggered..
        /// </remarks>
        public virtual OrderEvent StopLimitFill(Security asset, StopLimitOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // make sure the exchange is open before filling -- allow pre/post market fills to occur
            if (!IsExchangeOpen(
                    asset,
                    Parameters.ConfigProvider
                    .GetSubscriptionDataConfigs(asset.Symbol)
                    .IsExtendedMarketHours()))
            {
                return(fill);
            }

            //Get the range of prices in the last bar:
            var prices        = GetPricesCheckingPythonWrapper(asset, order.Direction);
            var pricesEndTime = prices.EndTime.ConvertToUtc(asset.Exchange.TimeZone);

            // do not fill on stale data
            if (pricesEndTime <= order.Time)
            {
                return(fill);
            }

            //Check if the Stop Order was filled: opposite to a limit order
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                if (prices.High > order.StopPrice || order.StopTriggered)
                {
                    order.StopTriggered = true;

                    // Fill the limit order, using closing price of bar:
                    // Note > Can't use minimum price, because no way to be sure minimum wasn't before the stop triggered.
                    if (prices.Current < order.LimitPrice)
                    {
                        fill.Status    = OrderStatus.Filled;
                        fill.FillPrice = Math.Min(prices.High, order.LimitPrice);
                        // assume the order completely filled
                        fill.FillQuantity = order.Quantity;
                    }
                }
                break;

            case OrderDirection.Sell:
                //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                if (prices.Low < order.StopPrice || order.StopTriggered)
                {
                    order.StopTriggered = true;

                    // Fill the limit order, using minimum price of the bar
                    // Note > Can't use minimum price, because no way to be sure minimum wasn't before the stop triggered.
                    if (prices.Current > order.LimitPrice)
                    {
                        fill.Status    = OrderStatus.Filled;
                        fill.FillPrice = Math.Max(prices.Low, order.LimitPrice);
                        // assume the order completely filled
                        fill.FillQuantity = order.Quantity;
                    }
                }
                break;
            }

            return(fill);
        }
        /// <summary>
        /// Market on Close Fill Model. Return an order event with the fill details
        /// </summary>
        /// <param name="asset">Asset we're trading with this order</param>
        /// <param name="order">Order to be filled</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        public OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
        {
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            if (order.Status == OrderStatus.Canceled) return fill;

            var localOrderTime = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);
            var nextMarketClose = asset.Exchange.Hours.GetNextMarketClose(localOrderTime, false);
                
            // wait until market closes after the order time 
            if (asset.LocalTime < nextMarketClose)
            {
                return fill;
            }

            fill.FillPrice = asset.Close;
            fill.Status = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Apply slippage
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    fill.FillPrice += slip;
                    break;
                case OrderDirection.Sell:
                    fill.FillPrice -= slip;
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
Exemple #21
0
        /// <summary>
        /// Default limit order fill model in the base security class.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        public virtual OrderEvent LimitFill(Security asset, LimitOrder order)
        {
            //Initialise;
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // make sure the exchange is open before filling -- allow pre/post market fills to occur
            if (!IsExchangeOpen(asset,
                                Parameters.ConfigProvider
                                .GetSubscriptionDataConfigs(asset.Symbol)
                                .IsExtendedMarketHours()))
            {
                return(fill);
            }
            //Get the range of prices in the last bar:
            var prices        = GetPricesCheckingPythonWrapper(asset, order.Direction);
            var pricesEndTime = prices.EndTime.ConvertToUtc(asset.Exchange.TimeZone);

            // do not fill on stale data
            if (pricesEndTime <= order.Time)
            {
                return(fill);
            }

            //-> Valid Live/Model Order:
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                //Buy limit seeks lowest price
                if (prices.Low < order.LimitPrice)
                {
                    //Set order fill:
                    fill.Status = OrderStatus.Filled;
                    // fill at the worse price this bar or the limit price, this allows far out of the money limits
                    // to be executed properly
                    fill.FillPrice = Math.Min(prices.High, order.LimitPrice);
                    // assume the order completely filled
                    fill.FillQuantity = order.Quantity;
                }
                break;

            case OrderDirection.Sell:
                //Sell limit seeks highest price possible
                if (prices.High > order.LimitPrice)
                {
                    fill.Status = OrderStatus.Filled;
                    // fill at the worse price this bar or the limit price, this allows far out of the money limits
                    // to be executed properly
                    fill.FillPrice = Math.Max(prices.Low, order.LimitPrice);
                    // assume the order completely filled
                    fill.FillQuantity = order.Quantity;
                }
                break;
            }

            return(fill);
        }
        /// <summary>
        /// Check if the model has stopped out our position yet:
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Stop Order to Check, return filled if true</param>
        public virtual OrderEvent StopFill(Security security, Order order)
        {
            //Default order event to return.
            var fill = new OrderEvent(order);

            try
            {
                //If its cancelled don't need anymore checks:
                if (fill.Status == OrderStatus.Canceled) return fill;

                //Check if the Stop Order was filled: opposite to a limit order
                switch (order.Direction)
                {
                    case OrderDirection.Sell:
                        //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                        if (security.Price < order.Price)
                        {
                            order.Status = OrderStatus.Filled;
                            order.Price = security.Price;
                        }
                        break;
                    case OrderDirection.Buy:
                        //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                        if (security.Price > order.Price)
                        {
                            order.Status = OrderStatus.Filled;
                            order.Price = security.Price;
                        }
                        break;
                }

                if (order.Status == OrderStatus.Filled || order.Status == OrderStatus.PartiallyFilled)
                {
                    fill.FillQuantity = order.Quantity;
                    fill.FillPrice = security.Price;        //Stop price as security price because can gap past stop price.
                    fill.Status = order.Status;
                }
            }
            catch (Exception err)
            {
                Log.Error("SecurityTransactionModel.TransOrderDirection.StopFill(): " + err.Message);
            }

            return fill;
        }
Exemple #23
0
        /// <summary>
        /// Market on Open Fill Model. Return an order event with the fill details
        /// </summary>
        /// <param name="asset">Asset we're trading with this order</param>
        /// <param name="order">Order to be filled</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        public virtual OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
        {
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            // MOO should never fill on the same bar or on stale data
            // Imagine the case where we have a thinly traded equity, ASUR, and another liquid
            // equity, say SPY, SPY gets data every minute but ASUR, if not on fill forward, maybe
            // have large gaps, in which case the currentBar.EndTime will be in the past
            // ASUR  | | |      [order]        | | | | | | |
            //  SPY  | | | | | | | | | | | | | | | | | | | |
            var localOrderTime = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);
            var endTime        = DateTime.MinValue;

            var subscribedTypes = GetSubscribedTypes(asset);

            if (subscribedTypes.Contains(typeof(Tick)))
            {
                var primaryExchangeCode = ((Equity)asset).PrimaryExchange.Code;
                var officialOpen        = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.OfficialOpen);
                var openingPrints       = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.OpeningPrints);

                var trades = asset.Cache.GetAll <Tick>()
                             .Where(x => x.TickType == TickType.Trade && x.Price > 0 && asset.Exchange.DateTimeIsOpen(x.Time))
                             .OrderBy(x => x.EndTime).ToList();

                // Get the first valid (non-zero) tick of trade type from an open market
                var tick = trades
                           .Where(x => !string.IsNullOrWhiteSpace(x.SaleCondition))
                           .FirstOrDefault(x =>
                                           x.TickType == TickType.Trade && x.Price > 0 && x.ExchangeCode == primaryExchangeCode &&
                                           (x.ParsedSaleCondition == officialOpen || x.ParsedSaleCondition == openingPrints) &&
                                           asset.Exchange.DateTimeIsOpen(x.Time));

                // If there is no OfficialOpen or OpeningPrints in the current list of trades,
                // we will wait for the next up to 1 minute before accepting the last trade without flags
                // We will give priority to trade then use quote to get the timestamp
                // If there are only quotes, we will need to test for the tick type before we assign the fill price
                if (tick == null)
                {
                    var previousOpen = asset.Exchange.Hours
                                       .GetMarketHours(asset.LocalTime)
                                       .GetMarketOpen(TimeSpan.Zero, false);

                    fill.Message = "No trade with the OfficialOpen or OpeningPrints flag within the 1-minute timeout.";

                    tick = trades.LastOrDefault() ?? asset.Cache.GetAll <Tick>().LastOrDefault();
                    if ((tick?.EndTime.TimeOfDay - previousOpen)?.TotalMinutes < 1)
                    {
                        return(fill);
                    }

                    fill.Message += $" Fill with last {tick.TickType} data.";
                }

                endTime = tick?.EndTime ?? endTime;

                if (tick?.TickType == TickType.Trade)
                {
                    fill.FillPrice = tick.Price;
                }
            }
            else if (subscribedTypes.Contains(typeof(TradeBar)))
            {
                var tradeBar = asset.Cache.GetData <TradeBar>();
                if (tradeBar != null)
                {
                    // If the order was placed during the bar aggregation, we cannot use its open price
                    if (tradeBar.Time < localOrderTime)
                    {
                        return(fill);
                    }

                    // We need to verify whether the trade data is from the open market.
                    if (tradeBar.Period < Resolution.Hour.ToTimeSpan() && !asset.Exchange.DateTimeIsOpen(tradeBar.Time))
                    {
                        return(fill);
                    }

                    endTime        = tradeBar.EndTime;
                    fill.FillPrice = tradeBar.Open;
                }
            }
            else
            {
                fill.Message = $"Warning: No trade information available at {asset.LocalTime.ToStringInvariant()} {asset.Exchange.TimeZone}, order filled using Quote data";
            }

            if (localOrderTime >= endTime)
            {
                return(fill);
            }

            // if the MOO was submitted during market the previous day, wait for a day to turn over
            // The date of the order and the trade data end time cannot be the same.
            // Note that the security local time can be ahead of the data end time.
            if (asset.Exchange.DateTimeIsOpen(localOrderTime) && localOrderTime.Date == endTime.Date)
            {
                return(fill);
            }

            // wait until market open
            // make sure the exchange is open/normal market hours before filling
            if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }

            // assume the order completely filled
            fill.FillQuantity = order.Quantity;
            fill.Status       = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            var bestEffortMessage = "";

            // If there is no trade information, get the bid or ask, then apply the slippage
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                if (fill.FillPrice == 0)
                {
                    fill.FillPrice = GetBestEffortAskPrice(asset, order.Time, out bestEffortMessage);
                    fill.Message  += bestEffortMessage;
                }

                fill.FillPrice += slip;
                break;

            case OrderDirection.Sell:
                if (fill.FillPrice == 0)
                {
                    fill.FillPrice = GetBestEffortBidPrice(asset, order.Time, out bestEffortMessage);
                    fill.Message  += bestEffortMessage;
                }

                fill.FillPrice -= slip;
                break;
            }

            return(fill);
        }
 /// <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());
 }
Exemple #25
0
        /// <summary>
        /// Market on Close Fill Model. Return an order event with the fill details
        /// </summary>
        /// <param name="asset">Asset we're trading with this order</param>
        /// <param name="order">Order to be filled</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        public virtual OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
        {
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill    = new OrderEvent(order, utcTime, OrderFee.Zero);

            if (order.Status == OrderStatus.Canceled)
            {
                return(fill);
            }

            var localOrderTime  = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);
            var nextMarketClose = asset.Exchange.Hours.GetNextMarketClose(localOrderTime, false);

            // wait until market closes after the order time
            if (asset.LocalTime < nextMarketClose)
            {
                return(fill);
            }

            var subscribedTypes = GetSubscribedTypes(asset);

            if (subscribedTypes.Contains(typeof(Tick)))
            {
                var primaryExchangeCode = ((Equity)asset).PrimaryExchange.Code;
                var officialClose       = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.OfficialClose);
                var closingPrints       = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.ClosingPrints);

                var trades = asset.Cache.GetAll <Tick>()
                             .Where(x => x.TickType == TickType.Trade && x.Price > 0)
                             .OrderBy(x => x.EndTime).ToList();

                // Get the last valid (non-zero) tick of trade type from an close market
                var tick = trades
                           .Where(x => !string.IsNullOrWhiteSpace(x.SaleCondition))
                           .LastOrDefault(x => x.ExchangeCode == primaryExchangeCode &&
                                          (x.ParsedSaleCondition == officialClose || x.ParsedSaleCondition == closingPrints));

                // If there is no OfficialClose or ClosingPrints in the current list of trades,
                // we will wait for the next up to 1 minute before accepting the last tick without flags
                // We will give priority to trade then use quote to get the timestamp
                // If there are only quotes, we will need to test for the tick type before we assign the fill price
                if (tick == null)
                {
                    tick = trades.LastOrDefault() ?? asset.Cache.GetAll <Tick>().LastOrDefault();
                    if (Parameters.ConfigProvider.GetSubscriptionDataConfigs(asset.Symbol).IsExtendedMarketHours())
                    {
                        fill.Message = "No trade with the OfficialClose or ClosingPrints flag within the 1-minute timeout.";

                        if ((tick?.EndTime - nextMarketClose)?.TotalMinutes < 1)
                        {
                            return(fill);
                        }
                    }
                    else
                    {
                        fill.Message = "No trade with the OfficialClose or ClosingPrints flag for data that does not include extended market hours.";
                    }

                    fill.Message += $" Fill with last {tick.TickType} data.";
                }

                if (tick?.TickType == TickType.Trade)
                {
                    fill.FillPrice = tick.Price;
                }
            }
            // make sure the exchange is open/normal market hours before filling
            // It will return true if the last bar opens before the market closes
            else if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }
            else if (subscribedTypes.Contains(typeof(TradeBar)))
            {
                fill.FillPrice = asset.Cache.GetData <TradeBar>()?.Close ?? 0;
            }
            else
            {
                fill.Message = $"Warning: No trade information available at {asset.LocalTime.ToStringInvariant()} {asset.Exchange.TimeZone}, order filled using Quote data";
            }

            // Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            var bestEffortMessage = "";

            // If there is no trade information, get the bid or ask, then apply the slippage
            switch (order.Direction)
            {
            case OrderDirection.Buy:
                if (fill.FillPrice == 0)
                {
                    fill.FillPrice = GetBestEffortAskPrice(asset, order.Time, out bestEffortMessage);
                    fill.Message  += bestEffortMessage;
                }

                fill.FillPrice += slip;
                break;

            case OrderDirection.Sell:
                if (fill.FillPrice == 0)
                {
                    fill.FillPrice = GetBestEffortBidPrice(asset, order.Time, out bestEffortMessage);
                    fill.Message  += bestEffortMessage;
                }

                fill.FillPrice -= slip;
                break;
            }

            // assume the order completely filled
            fill.FillQuantity = order.Quantity;
            fill.Status       = OrderStatus.Filled;

            return(fill);
        }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     Log($"{Time}: {orderEvent}");
 }
Exemple #27
0
        public void ComputeMarginProperlyAsSecurityPriceFluctuates()
        {
            const decimal leverage       = 1m;
            const int     quantity       = (int)(1000 * leverage);
            var           securities     = new SecurityManager(TimeKeeper);
            var           transactions   = new SecurityTransactionManager(securities);
            var           orderProcessor = new OrderProcessor();

            transactions.SetOrderProcessor(orderProcessor);
            var portfolio = new SecurityPortfolioManager(securities, transactions);

            portfolio.CashBook["USD"].SetAmount(quantity);

            var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL);

            securities.Add(new Security(SecurityExchangeHours, config));
            var security = securities[Symbols.AAPL];

            security.SetLeverage(leverage);

            var           time     = DateTime.Now;
            const decimal buyPrice = 1m;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1));

            var order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            var fill = new OrderEvent(order, DateTime.UtcNow, 0)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            orderProcessor.AddOrder(order);
            var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null);

            request.SetOrderId(0);
            orderProcessor.AddTicket(new OrderTicket(null, request));
            Assert.AreEqual(portfolio.CashBook["USD"].Amount, fill.FillPrice * fill.FillQuantity);

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = buyPrice
            };
            bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder);

            Assert.IsFalse(sufficientCapital);

            // now the stock doubles, so we should have margin remaining

            time = time.AddDays(1);
            const decimal highPrice = buyPrice * 2;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1));

            Assert.AreEqual(quantity, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue);

            // we shouldn't be able to place a trader
            var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1))
            {
                Price = highPrice
            };

            sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder);
            Assert.IsTrue(sufficientCapital);

            // now the stock plummets, so we should have negative margin remaining

            time = time.AddDays(1);
            const decimal lowPrice = buyPrice / 2;

            security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, lowPrice, lowPrice, lowPrice, lowPrice, 1));

            Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining);
            Assert.AreEqual(quantity, portfolio.TotalMarginUsed);
            Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue);


            // this would not cause a margin call due to leverage = 1
            bool issueMarginCallWarning;
            var  marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning);

            Assert.AreEqual(0, marginCallOrders.Count);

            // now change the leverage and buy more and we'll get a margin call
            security.SetLeverage(leverage * 2);

            order = new MarketOrder(Symbols.AAPL, quantity, time)
            {
                Price = buyPrice
            };
            fill = new OrderEvent(order, DateTime.UtcNow, 0)
            {
                FillPrice = buyPrice, FillQuantity = quantity
            };

            portfolio.ProcessFill(fill);

            Assert.AreEqual(0, portfolio.TotalPortfolioValue);

            marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning);
            Assert.AreNotEqual(0, marginCallOrders.Count);
            Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice
            Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity);
        }
 /// <summary>
 /// Handle order event
 /// </summary>
 /// <param name="newEvent">Event to process</param>
 public override void OrderEvent(OrderEvent newEvent)
 {
     _capacityEstimate?.OnOrderEvent(newEvent);
 }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     Console.WriteLine($"{Time}: {orderEvent}");
 }
        /// <summary>
        /// Model the slippage on a market order: fixed percentage of order price
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Order to update</param>
        public virtual OrderEvent MarketFill(Security security, Order order)
        {
            var fill = new OrderEvent(order);
            try
            {
                //Calculate the model slippage: e.g. 0.01c
                decimal slip = GetSlippageApproximation(security, order);

                switch (order.Direction)
                {
                    case OrderDirection.Buy:
                        //Set the order and slippage on the order, update the fill price:
                        order.Price = security.Price;
                        order.Price += slip;
                        break;

                    case OrderDirection.Sell:
                        //Set the order and slippage on the order, update the fill price:
                        order.Price = security.Price;
                        order.Price -= slip;
                        break;
                }

                //Market orders fill instantly.
                order.Status = OrderStatus.Filled;

                //Assume 100% fill for market & modelled orders.
                fill.FillQuantity = order.Quantity;
                fill.FillPrice = order.Price;
                fill.Status = order.Status;
            }
            catch (Exception err)
            {
                Log.Error("ForexTransactionModel.TransOrderDirection.MarketFill(): " + err.Message);
            }
            return fill;
        }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
     Debug($"OnOrderEvent(OrderEvent): {Time}: {orderEvent}");
 }
        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            string symbol = orderEvent.Symbol.Value;
            Strategy[symbol].Status = orderEvent.Status;
            switch (orderEvent.Status)
            {
                case OrderStatus.New:
                case OrderStatus.None:
                case OrderStatus.Submitted:
                    Strategy[orderEvent.Symbol.Value].orderFilled = false;
                    break;
                case OrderStatus.Invalid:
                    Strategy[symbol].TradeAttempts = 0;
                    Strategy[symbol].orderFilled = false;
                    break;
                case OrderStatus.PartiallyFilled:
                    if (Strategy[symbol] != null)
                    {
                        Strategy[symbol].orderFilled = true;
                        // Do not unlock the strategy
                        Strategy[symbol].nEntryPrice= Portfolio[orderEvent.Symbol].HoldStock ? Portfolio[orderEvent.Symbol].AveragePrice : 0;
                        Strategy[symbol].orderFilled = true;
                        Strategy[symbol].TradeAttempts++;
                        //Log(string.Format("Trade Attempts: {0} OrderId {1}", currentSignalInfo.TradeAttempts, orderEvent.OrderId));
                    }

                    break;
                case OrderStatus.Canceled:
                    if (Strategy[symbol] != null)
                    {
                        //Log(string.Format("Order {0} cancelled.", orderEvent.OrderId));
                        Strategy[symbol].IsActive = true;       // Unlock the strategy for the next bar 
                        Strategy[symbol].TradeAttempts = 0;     // Reset the number of trade attempts.
                        Strategy[symbol].orderFilled = false;
                    }
                    break;
                case OrderStatus.Filled:
                    if (Strategy[symbol] != null)
                    {
                        //Log(string.Format("Order Filled OrderId {0} on attempt {1}", orderEvent.OrderId, currentSignalInfo.TradeAttempts));
                        Strategy[symbol].IsActive = true;
                        Strategy[symbol].TradeAttempts = 0;
                        Strategy[symbol].nEntryPrice = Portfolio[orderEvent.Symbol].HoldStock ? Portfolio[orderEvent.Symbol].AveragePrice : 0;
                        Strategy[symbol].orderFilled = true;

                    }
                    #region "Report Transaction"
                    #endregion
                    break;
            }
        }
Exemple #33
0
 /// <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 virtual void OnOrderEvent(OrderEvent orderEvent)
 {
 }
        /// <summary>
        /// Default stop limit fill model implementation in base class security. (Stop Limit Order Type)
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
        /// <seealso cref="SecurityTransactionModel.LimitFill"/>
        /// <remarks>
        ///     There is no good way to model limit orders with OHLC because we never know whether the market has 
        ///     gapped past our fill price. We have to make the assumption of a fluid, high volume market.
        /// 
        ///     Stop limit orders we also can't be sure of the order of the H - L values for the limit fill. The assumption
        ///     was made the limit fill will be done with closing price of the bar after the stop has been triggered..
        /// </remarks>
        public virtual OrderEvent StopLimitFill(Security asset, StopLimitOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled) return fill;

            //Get the range of prices in the last bar:
            decimal minimumPrice;
            decimal maximumPrice;
            DataMinMaxPrices(asset, out minimumPrice, out maximumPrice, order.Direction);

            //Check if the Stop Order was filled: opposite to a limit order
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                    if (maximumPrice > order.StopPrice || order.StopTriggered)
                    {
                        order.StopTriggered = true;

                        // Fill the limit order, using closing price of bar:
                        // Note > Can't use minimum price, because no way to be sure minimum wasn't before the stop triggered.
                        if (asset.Price < order.LimitPrice)
                        {
                            fill.Status = OrderStatus.Filled;
                            fill.FillPrice = order.LimitPrice;
                        }
                    }
                    break;

                case OrderDirection.Sell:
                    //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                    if (minimumPrice < order.StopPrice || order.StopTriggered)
                    {
                        order.StopTriggered = true;

                        // Fill the limit order, using minimum price of the bar
                        // Note > Can't use minimum price, because no way to be sure minimum wasn't before the stop triggered.
                        if (asset.Price > order.LimitPrice)
                        {
                            fill.Status = OrderStatus.Filled;
                            fill.FillPrice = order.LimitPrice; // Fill at limit price not asset price.
                        }
                    }
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
        /// <summary>
        /// Check if the model has stopped out our position yet:
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Stop Order to Check, return filled if true</param>
        public virtual OrderEvent StopFill(Security security, Order order)
        {
            var fill = new OrderEvent(order);
            try
            {
                //If its cancelled don't need anymore checks:
                if (order.Status == OrderStatus.Canceled) return fill;

                //Calculate the model slippage: e.g. 0.01c
                decimal slip = GetSlippageApproximation(security, order);

                //Check if the Stop Order was filled: opposite to a limit order
                switch (order.Direction)
                {
                    case OrderDirection.Sell:
                        //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                        if (security.Price < order.Price)
                        {
                            order.Status = OrderStatus.Filled;
                            order.Price = Math.Round(security.Price, 3);
                            order.Price -= slip;
                        }
                        break;
                    case OrderDirection.Buy:
                        //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                        if (security.Price > order.Price)
                        {
                            order.Status = OrderStatus.Filled;
                            order.Price = Math.Round(security.Price, 3);
                            order.Price += slip;
                        }
                        break;
                }

                if (order.Status == OrderStatus.Filled || order.Status == OrderStatus.PartiallyFilled)
                {
                    fill.FillQuantity = order.Quantity;
                    fill.FillPrice = order.Price;
                    fill.Status = order.Status;
                }
            }
            catch (Exception err)
            {
                Log.Error("Equity.TransOrderDirection.StopFill(): " + err.Message);
            }
            return fill;
        }
        /// <summary>
        /// Market on Open Fill Model. Return an order event with the fill details
        /// </summary>
        /// <param name="asset">Asset we're trading with this order</param>
        /// <param name="order">Order to be filled</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        public OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
        {
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            if (order.Status == OrderStatus.Canceled) return fill;

            // MOO should never fill on the same bar or on stale data
            // Imagine the case where we have a thinly traded equity, ASUR, and another liquid
            // equity, say SPY, SPY gets data every minute but ASUR, if not on fill forward, maybe
            // have large gaps, in which case the currentBar.EndTime will be in the past
            // ASUR  | | |      [order]        | | | | | | |
            //  SPY  | | | | | | | | | | | | | | | | | | | |
            var currentBar = asset.GetLastData();
            var localOrderTime = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);
            if (currentBar == null || localOrderTime >= currentBar.EndTime) return fill;

            // if the MOO was submitted during market the previous day, wait for a day to turn over
            if (asset.Exchange.DateTimeIsOpen(localOrderTime) && localOrderTime.Date == asset.LocalTime.Date)
            {
                return fill;
            }

            // wait until market open
            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset)) return fill;

            fill.FillPrice = asset.Open;
            fill.Status = OrderStatus.Filled;

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Apply slippage
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    fill.FillPrice += slip;
                    break;
                case OrderDirection.Sell:
                    fill.FillPrice -= slip;
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }
        /// <summary>
        /// Check if the price MarketDataed to our limit price yet:
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Limit order in market</param>
        public virtual OrderEvent LimitFill(Security security, Order order)
        {
            //Initialise;
            decimal marketDataMinPrice = 0;
            decimal marketDataMaxPrice = 0;
            var fill = new OrderEvent(order);

            try {
                //If its cancelled don't need anymore checks:
                if (fill.Status == OrderStatus.Canceled) return fill;

                //Depending on the resolution, return different data types:
                BaseData marketData = security.GetLastData();

                if (marketData.DataType == MarketDataType.TradeBar)
                {
                    marketDataMinPrice = ((TradeBar)marketData).Low;
                    marketDataMaxPrice = ((TradeBar)marketData).High;
                } else {
                    marketDataMinPrice = marketData.Value;
                    marketDataMaxPrice = marketData.Value;
                }

                //-> Valid Live/Model Order:
                switch (order.Direction)
                {
                    case OrderDirection.Buy:
                        //Buy limit seeks lowest price
                        if (marketDataMinPrice < order.Price)
                        {
                            //Set order fill:
                            order.Status = OrderStatus.Filled;
                            order.Price = security.Price;
                        }
                        break;
                    case OrderDirection.Sell:
                        //Sell limit seeks highest price possible
                        if (marketDataMaxPrice > order.Price)
                        {
                            order.Status = OrderStatus.Filled;
                            order.Price = security.Price;
                        }
                        break;
                }

                if (order.Status == OrderStatus.Filled || order.Status == OrderStatus.PartiallyFilled)
                {
                    fill.FillQuantity = order.Quantity;
                    fill.FillPrice = security.Price;
                    fill.Status = order.Status;
                }
            }
            catch (Exception err)
            {
                Log.Error("SecurityTransactionModel.TransOrderDirection.LimitFill(): " + err.Message);
            }
            return fill;
        }
        /// <summary>
        /// Scans all the outstanding orders and applies the algorithm model fills to generate the order events
        /// </summary>
        public void Scan()
        {
            lock (_needsScanLock)
            {
                // there's usually nothing in here
                if (!_needsScan)
                {
                    return;
                }

                var stillNeedsScan = false;

                // process each pending order to produce fills/fire events
                foreach (var kvp in _pending)
                {
                    var order = kvp.Value;

                    if (order.Status.IsClosed())
                    {
                        // this should never actually happen as we always remove closed orders as they happen
                        _pending.TryRemove(order.Id, out order);
                        continue;
                    }

                    // all order fills are processed on the next bar (except for market orders)
                    if (order.Time == Algorithm.UtcTime && order.Type != OrderType.Market)
                    {
                        stillNeedsScan = true;
                        continue;
                    }

                    var fill = new OrderEvent(order, Algorithm.UtcTime, 0);

                    Security security;
                    if (!Algorithm.Securities.TryGetValue(order.Symbol, out security))
                    {
                        Log.Error("BacktestingBrokerage.Scan(): Unable to process order: " + order.Id + ". The security no longer exists.");
                        // invalidate the order in the algorithm before removing
                        OnOrderEvent(new OrderEvent(order, Algorithm.UtcTime, 0m){Status = OrderStatus.Invalid});
                        _pending.TryRemove(order.Id, out order);
                        continue;
                    }

                    // check if we would actually be able to fill this
                    if (!Algorithm.BrokerageModel.CanExecuteOrder(security, order))
                    {
                        continue;
                    }

                    // verify sure we have enough cash to perform the fill
                    bool sufficientBuyingPower;
                    try
                    {
                        sufficientBuyingPower = Algorithm.Transactions.GetSufficientCapitalForOrder(Algorithm.Portfolio, order);
                    }
                    catch (Exception err)
                    {
                        // if we threw an error just mark it as invalid and remove the order from our pending list
                        Order pending;
                        _pending.TryRemove(order.Id, out pending);
                        order.Status = OrderStatus.Invalid;
                        OnOrderEvent(new OrderEvent(order, Algorithm.UtcTime, 0, "Error in GetSufficientCapitalForOrder"));

                        Log.Error(err);
                        Algorithm.Error(string.Format("Order Error: id: {0}, Error executing margin models: {1}", order.Id, err.Message));
                        continue;
                    }

                    //Before we check this queued order make sure we have buying power:
                    if (sufficientBuyingPower)
                    {
                        //Model:
                        var model = security.FillModel;

                        //Based on the order type: refresh its model to get fill price and quantity
                        try
                        {
                            switch (order.Type)
                            {
                                case OrderType.Limit:
                                    fill = model.LimitFill(security, order as LimitOrder);
                                    break;

                                case OrderType.StopMarket:
                                    fill = model.StopMarketFill(security, order as StopMarketOrder);
                                    break;

                                case OrderType.Market:
                                    fill = model.MarketFill(security, order as MarketOrder);
                                    break;

                                case OrderType.StopLimit:
                                    fill = model.StopLimitFill(security, order as StopLimitOrder);
                                    break;

                                case OrderType.MarketOnOpen:
                                    fill = model.MarketOnOpenFill(security, order as MarketOnOpenOrder);
                                    break;

                                case OrderType.MarketOnClose:
                                    fill = model.MarketOnCloseFill(security, order as MarketOnCloseOrder);
                                    break;
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error(err);
                            Algorithm.Error(string.Format("Order Error: id: {0}, Transaction model failed to fill for order type: {1} with error: {2}",
                                order.Id, order.Type, err.Message));
                        }
                    }
                    else
                    {
                        //Flag order as invalid and push off queue:
                        order.Status = OrderStatus.Invalid;
                        Algorithm.Error(string.Format("Order Error: id: {0}, Insufficient buying power to complete order (Value:{1}).", order.Id,
                            order.GetValue(security).SmartRounding()));
                    }

                    // change in status or a new fill
                    if (order.Status != fill.Status || fill.FillQuantity != 0)
                    {
                        //If the fill models come back suggesting filled, process the affects on portfolio
                        OnOrderEvent(fill);
                    }

                    if (fill.Status.IsClosed())
                    {
                        _pending.TryRemove(order.Id, out order);
                    }
                    else
                    {
                        stillNeedsScan = true;
                    }
                }
                
                // if we didn't fill then we need to continue to scan
                _needsScan = stillNeedsScan;
            }
        }
Exemple #39
0
 public virtual void OnOrderEvent(OrderEvent newEvent)
 {
     //Algo.OnOrderEvent(newEvent);
 }
        /// <summary>
        /// Model the slippage on a market order: fixed percentage of order price
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Order to update</param>
        public virtual OrderEvent MarketFill(Security security, Order order)
        {
            var fill = new OrderEvent(order);
            try
            {
                //Calculate the model slippage: e.g. 0.01c
                decimal slip = GetSlippageApproximation(security, order);

                switch (order.Direction)
                {
                    case OrderDirection.Buy:
                        order.Price = security.Price;
                        order.Price += slip;
                        break;
                    case OrderDirection.Sell:
                        order.Price = security.Price;
                        order.Price -= slip;
                        break;
                }

                //Market orders fill instantly.
                order.Status = OrderStatus.Filled;
                order.Price = Math.Round(order.Price, 3);

                //Fill Order:
                fill.Status = order.Status;
                fill.FillQuantity = order.Quantity;
                fill.FillPrice = order.Price;
            }
            catch (Exception err)
            {
                Log.Error("Equity.TransOrderDirection.MarketFill(): " + err.Message);
            }
            return fill;
        }
 /// <summary>
 /// Send a new order event to the browser.
 /// </summary>
 /// <remarks>In backtesting the order events are not sent because it would generate a high load of messaging.</remarks>
 /// <param name="newEvent">New order event details</param>
 public void OrderEvent(OrderEvent newEvent)
 {
     // NOP. Don't do any order event processing for results in backtest mode.
 }
Exemple #42
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="orderEvent"></param>
        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            decimal fees = 0m;
            decimal tradeprofit = 0m;
            decimal profit = 0m;
            base.OnOrderEvent(orderEvent);
            if (orderEvent.Status == OrderStatus.Filled)
            {
                var fillprice = orderEvent.FillPrice;
                var fillquantity = orderEvent.FillQuantity;
                var amount = orderEvent.FillPrice * orderEvent.FillQuantity;
                var direction = orderEvent.Direction;
                var orderid = Portfolio.Transactions.LastOrderId;

                var fpbuy = "";
                var fpsell = "";
                if (direction == OrderDirection.Buy)

                    fpbuy = fillprice.ToString(CultureInfo.InvariantCulture);
                else
                    fpsell = fillprice.ToString(CultureInfo.InvariantCulture);

                foreach (SecurityHolding holding in Portfolio.Values)
                {
                    fees = holding.TotalFees - _totalFees;
                    tradeprofit = holding.LastTradeProfit;
                    profit = holding.Profit;
                    _totalFees = holding.TotalFees;
                    holdingcost = holding.HoldingsCost;
                }
                var order = Transactions.GetOrderById(orderEvent.OrderId);
                var dt = order.Time;
                var quantity = Portfolio[_symbol].Quantity;

                if (direction.ToString() == "Buy")
                {
                    amount += fees;
                }
                else
                {
                    amount += fees;

                }

                //string transmsg = string.Format(
                //        "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}",
                //        _symbol,
                //        fillquantity,
                //        fillprice,
                //        direction.ToString(),
                //        dt,
                //        dt.AddDays(4),
                //        0,
                //        amount,
                //        fees,
                //        0,
                //        "60505104",
                //        actionNameUs + " share of " + _symbol + "at $" + fillprice.ToString(),
                //        actionid,
                //        orderEvent.OrderId,
                //        "Trade",
                //        "taxlot"
                //        );
                //mylog.Debug(transmsg);
                if (logtrade)
                {

                    mylog.Debug(tradeheader);

                    string logmsg =
                        string.Format(
                            "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}",
                            dt,
                            barcount,
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            "",
                            direction,
                            tradeprofit,
                            fpbuy,
                            fpsell,
                            profit,
                            holdingcost,
                            fillquantity,
                            fees,
                            profit - fees,
                            quantity
                            );
                    mylog.Debug(logmsg);
                }

            }
        }
 /// <summary>
 /// Send a new order event to the browser.
 /// </summary>
 /// <remarks>In backtesting the order events are not sent because it would generate a high load of messaging.</remarks>
 /// <param name="newEvent">New order event details</param>
 public void OrderEvent(OrderEvent newEvent)
 {
     DebugMessage("DesktopResultHandler.OrderEvent(): id:" + newEvent.OrderId + " >> Status:" + newEvent.Status + " >> Fill Price: " + newEvent.FillPrice.ToString("C") + " >> Fill Quantity: " + newEvent.FillQuantity);
 }
        /// <summary>
        /// Default market order model. Fill at last price
        /// </summary>
        /// <param name="security">Asset we're working with</param>
        /// <param name="order">Order to update</param>
        public virtual OrderEvent MarketFill(Security security, Order order)
        {
            //Default order event to return.
            var fill = new OrderEvent(order);
            try {

                //Set the order price
                order.Price = security.Price;
                order.Status = OrderStatus.Filled;

                //Set the order event fill: - Assuming 100% fill
                fill.FillPrice = security.Price;
                fill.FillQuantity = order.Quantity;
                fill.Status = order.Status;

            } catch (Exception err) {
                Log.Error("SecurityTransactionModel.TransOrderDirection.MarketFill(): " + err.Message);
            }
            return fill;
        }
Exemple #45
0
 /// <summary>
 /// New order event for the algorithm
 /// </summary>
 /// <param name="newEvent">New event details</param>
 public virtual void OrderEvent(OrderEvent newEvent)
 {
 }
        private void HandleOrderEvent(OrderEvent fill)
        {
            // update the order status
            var order = GetOrderByIdInternal(fill.OrderId);
            if (order == null)
            {
                Log.Error("BrokerageTransactionHandler.HandleOrderEvent(): Unable to locate Order with id " + fill.OrderId);
                return;
            }

            // set the status of our order object based on the fill event
            order.Status = fill.Status;

            // save that the order event took place, we're initializing the list with a capacity of 2 to reduce number of mallocs
            //these hog memory
            //List<OrderEvent> orderEvents = _orderEvents.GetOrAdd(orderEvent.OrderId, i => new List<OrderEvent>(2));
            //orderEvents.Add(orderEvent);

            //Apply the filled order to our portfolio:
            if (fill.Status == OrderStatus.Filled || fill.Status == OrderStatus.PartiallyFilled)
            {
                Interlocked.Exchange(ref _lastFillTimeTicks, DateTime.UtcNow.Ticks);
                
                // check if the fill currency and the order currency match the symbol currency
                var security = _algorithm.Securities[fill.Symbol];
                // Bug in FXCM API flipping the currencies -- disabling for now. 5/17/16 RFB
                //if (fill.FillPriceCurrency != security.SymbolProperties.QuoteCurrency)
                //{
                //    Log.Error(string.Format("Currency mismatch: Fill currency: {0}, Symbol currency: {1}", fill.FillPriceCurrency, security.SymbolProperties.QuoteCurrency));
                //}
                //if (order.PriceCurrency != security.SymbolProperties.QuoteCurrency)
                //{
                //    Log.Error(string.Format("Currency mismatch: Order currency: {0}, Symbol currency: {1}", order.PriceCurrency, security.SymbolProperties.QuoteCurrency));
                //}

                try
                {
                    _algorithm.Portfolio.ProcessFill(fill);

                    var conversionRate = security.QuoteCurrency.ConversionRate;
                    var multiplier = security.SymbolProperties.ContractMultiplier;

                    _algorithm.TradeBuilder.ProcessFill(fill, conversionRate, multiplier);
                }
                catch (Exception err)
                {
                    Log.Error(err);
                    _algorithm.Error(string.Format("Order Error: id: {0}, Error in Portfolio.ProcessFill: {1}", order.Id, err.Message));
                }
            }

            // update the ticket and order after we've processed the fill, but before the event, this way everything is ready for user code
            OrderTicket ticket;
            if (_orderTickets.TryGetValue(fill.OrderId, out ticket))
            {
                ticket.AddOrderEvent(fill);
                order.Price = ticket.AverageFillPrice;
            }
            else
            {
                Log.Error("BrokerageTransactionHandler.HandleOrderEvent(): Unable to resolve ticket: " + fill.OrderId);
            }

            //We have an event! :) Order filled, send it in to be handled by algorithm portfolio.
            if (fill.Status != OrderStatus.None) //order.Status != OrderStatus.Submitted
            {
                //Create new order event:
                _resultHandler.OrderEvent(fill);
                try
                {
                    //Trigger our order event handler
                    _algorithm.OnOrderEvent(fill);
                }
                catch (Exception err)
                {
                    _algorithm.Error("Order Event Handler Error: " + err.Message);
                    // kill the algorithm
                    _algorithm.RunTimeError = err;
                }
            }
        }
 public override void OnOrderEvent(OrderEvent orderEvent)
 {
 }