示例#1
0
        public void PerformsMarketOnCloseUsingClosingPrice()
        {
            var reference = new DateTime(2015, 06, 05, 15, 0, 0); // before market close
            var model     = new SecurityTransactionModel();
            var order     = new MarketOnCloseOrder(Symbols.SPY, 100, reference);
            var config    = CreateTradeBarConfig(Symbols.SPY);
            var security  = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency));

            security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
            var time = reference;

            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time, Symbols.SPY, 1m, 2m, 0.5m, 1.33m, 100));

            var fill = model.MarketOnCloseFill(security, order);

            Assert.AreEqual(0, fill.FillQuantity);

            // market closes after 60min, so this is just before market Close
            time = reference.AddMinutes(59);
            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time, Symbols.SPY, 1.33m, 2.75m, 1.15m, 1.45m, 100));

            fill = model.MarketOnCloseFill(security, order);
            Assert.AreEqual(0, fill.FillQuantity);

            // market closes
            time = reference.AddMinutes(60);
            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time, Symbols.SPY, 1.45m, 2.0m, 1.1m, 1.40m, 100));

            fill = model.MarketOnCloseFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Close, fill.FillPrice);
        }
示例#2
0
 /// <summary>
 /// Wrapper for <see cref = "IFillModel.MarketOnCloseFill(Security, MarketOnCloseOrder)" /> in Python
 /// </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)
 {
     using (Py.GIL())
     {
         return(_model.MarketOnCloseFill(asset, order));
     }
 }
示例#3
0
        public void PerformsMarketOnCloseUsingClosingPrice()
        {
            var reference = DateTime.Today.AddHours(15);// before market close
            var model     = new SecurityTransactionModel();
            var order     = new MarketOnCloseOrder(Symbol, SecurityType.Equity, 100, reference, 1m);
            var config    = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, Symbol, Resolution.Minute, true, true, true, true, false, 0);
            var security  = new Security(config, 1)
            {
                Exchange = new EquityExchange()
            };
            var time = reference;

            security.SetMarketPrice(time, new TradeBar(time, Symbol, 1m, 2m, 0.5m, 1.33m, 100));

            var fill = model.MarketOnCloseFill(security, order);

            Assert.AreEqual(0, fill.FillQuantity);

            // market closes after 60min, so this is just before market Close
            time = reference.AddMinutes(59);
            security.SetMarketPrice(time, new TradeBar(time, Symbol, 1.33m, 2.75m, 1.15m, 1.45m, 100));

            fill = model.MarketOnCloseFill(security, order);
            Assert.AreEqual(0, fill.FillQuantity);

            // market closes
            time = reference.AddMinutes(60);
            security.SetMarketPrice(time, new TradeBar(time, Symbol, 1.45m, 2.0m, 1.1m, 1.40m, 100));

            fill = model.MarketOnCloseFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Close, fill.FillPrice);
        }
示例#4
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 override OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
 {
     using (Py.GIL())
     {
         return((_model.MarketOnCloseFill(asset, order) as PyObject).GetAndDispose <OrderEvent>());
     }
 }
示例#5
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 OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
        {
            var utcTime  = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var orderFee = GetOrderFee(asset, order);
            var fill     = new OrderEvent(order, utcTime, orderFee);

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

            try
            {
                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 = 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;
                }
            }
            catch (Exception err)
            {
                Log.Error(err);
            }

            return(fill);
        }
示例#6
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)
        {
            if (asset.Exchange.Hours.IsMarketAlwaysOpen)
            {
                throw new InvalidOperationException($"Market never closes for this symbol {asset.Symbol}, can no submit a {nameof(OrderType.MarketOnClose)} 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);
            }
            // make sure the exchange is open/normal market hours before filling
            if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }

            fill.FillPrice = GetPricesCheckingPythonWrapper(asset, order.Direction).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;
                // assume the order completely filled
                fill.FillQuantity = order.Quantity;
                break;

            case OrderDirection.Sell:
                fill.FillPrice -= slip;
                // assume the order completely filled
                fill.FillQuantity = order.Quantity;
                break;
            }

            return(fill);
        }
示例#7
0
        public void PerformsMarketOnCloseUsingClosingPrice()
        {
            var reference = new DateTime(2015, 06, 05, 15, 0, 0); // before market close
            var model     = new ImmediateFillModel();
            var order     = new MarketOnCloseOrder(Symbols.SPY, 100, reference);
            var config    = CreateTradeBarConfig(Symbols.SPY);
            var security  = new Security(
                SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(),
                config,
                new Cash(Currencies.USD, 0, 1m),
                SymbolProperties.GetDefault(Currencies.USD),
                ErrorCurrencyConverter.Instance,
                RegisteredSecurityDataTypesProvider.Null,
                new SecurityCache()
                );

            security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
            var time = reference;

            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time - config.Increment, Symbols.SPY, 1m, 2m, 0.5m, 1.33m, 100, config.Increment));

            var fill = model.Fill(new FillModelParameters(
                                      security,
                                      order,
                                      new MockSubscriptionDataConfigProvider(config),
                                      Time.OneHour)).OrderEvent;

            Assert.AreEqual(0, fill.FillQuantity);

            // market closes after 60min, so this is just before market Close
            time = reference.AddMinutes(59);
            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time - config.Increment, Symbols.SPY, 1.33m, 2.75m, 1.15m, 1.45m, 100, config.Increment));

            fill = model.Fill(new FillModelParameters(
                                  security,
                                  order,
                                  new MockSubscriptionDataConfigProvider(config),
                                  Time.OneHour)).OrderEvent;
            Assert.AreEqual(0, fill.FillQuantity);

            // market closes
            time = reference.AddMinutes(60);
            TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(time - config.Increment, Symbols.SPY, 1.45m, 2.0m, 1.1m, 1.40m, 100, config.Increment));

            fill = model.MarketOnCloseFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Close, fill.FillPrice);
        }
示例#8
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 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);
            }
            // make sure the exchange is open/normal market hours before filling
            if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }

            fill.FillPrice = GetPrices(asset, order.Direction).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);
        }
示例#9
0
        /// <summary>
        /// Market on close order implementation: Send a market order when the exchange closes
        /// </summary>
        /// <param name="symbol">The symbol to be ordered</param>
        /// <param name="quantity">The number of shares to required</param>
        /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
        /// <returns>The order ID</returns>
        public int MarketOnClose(string symbol, int quantity, string tag = "")
        {
            var error = PreOrderChecks(symbol, quantity, OrderType.MarketOnClose);

            if (error < 0)
            {
                return(error);
            }

            var security = Securities[symbol];
            var order    = new MarketOnCloseOrder(symbol, security.Type, quantity, Time, security.Price, tag);

            return(Transactions.AddOrder(order));
        }
        public void DeserializesMarketOnCloseOrder(Symbols.SymbolsKey key)
        {
            var expected = new MarketOnCloseOrder(Symbols.Lookup(key), 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
            {
                Id           = 12345,
                Price        = 209.03m,
                ContingentId = 123456,
                BrokerId     = new List <string> {
                    "727", "54970"
                }
            };

            TestOrderType(expected);
        }
示例#11
0
        public void DeserializesMarketOnCloseOrder()
        {
            var expected = new MarketOnCloseOrder(Symbols.SPY, SecurityType.Equity, 100, new DateTime(2015, 11, 23, 17, 15, 37), "now")
            {
                Id           = 12345,
                Price        = 209.03m,
                ContingentId = 123456,
                BrokerId     = new List <long> {
                    727, 54970
                }
            };

            TestOrderType(expected);
        }
示例#12
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 informaton detailing the average price and quantity filled.</returns>
        public OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
        {
            var fill = new OrderEvent(order);

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

            try
            {
                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);
                }

                order.Price  = asset.Close;
                order.Status = OrderStatus.Filled;

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

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

                case OrderDirection.Sell:
                    order.Price -= slip;
                    break;
                }

                //For backtesting, we assuming the order is 100% filled on first attempt.
                fill.FillPrice    = order.Price;
                fill.FillQuantity = order.Quantity;
                fill.Status       = order.Status;
            }
            catch (Exception err)
            {
                Log.Error(err);
            }

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

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

            try
            {
                // wait until market closes
                if (security.Exchange.ExchangeOpen)
                {
                    return(fill);
                }

                order.Price  = security.Close;
                order.Status = OrderStatus.Filled;

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

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

                case OrderDirection.Sell:
                    order.Price -= slip;
                    break;
                }

                //For backtesting, we assuming the order is 100% filled on first attempt.
                fill.FillPrice    = order.Price;
                fill.FillQuantity = order.Quantity;
                fill.Status       = order.Status;
            }
            catch (Exception err)
            {
                Log.Error(err);
            }

            return(fill);
        }
示例#14
0
        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);

            if (asset.LocalTime < nextMarketClose)
            {
                return(fill);
            }
            fill.FillPrice = GetPrices(asset, order.Direction).Close;
            fill.Status    = OrderStatus.Filled;
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

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

            case OrderDirection.Sell:
                fill.FillPrice -= slip;
                break;
            }
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee     = asset.FeeModel.GetOrderFee(asset, order);
            }
            return(fill);
        }
示例#15
0
 public override OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
 {
     MarketOnCloseFillWasCalled = true;
     return(base.MarketOnCloseFill(asset, order));
 }
示例#16
0
        /// <summary>
        /// Create pending order based on order ticket
        /// </summary>
        /// <param name="ticket"></param>
        /// <returns></returns>
        public PendingOrder CreateOrder(OrderTicket ticket)
        {
            //Get correct ticket information
            if (ticket.Type != OrderTicketType.Submit)
            {
                return(null);
            }

            //Get new order ticket
            if (!(ticket is SubmitOrderTicket norderticket))
            {
                ticket.SetResponse(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.ProcessingError, "Incorrect ticket type received"));
                return(null);
            }

            //Check order type based on input
            Order order;

            switch (norderticket.OrderType)
            {
            case OrderType.Limit:
                order = new LimitOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity, norderticket.LimitPrice,
                                       norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            case OrderType.Market:
                order = new MarketOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity,
                                        norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            case OrderType.StopMarket:
                order = new StopMarketOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity,
                                            norderticket.StopPrice, norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            case OrderType.StopLimit:
                order = new StopLimitOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity, norderticket.LimitPrice,
                                           norderticket.StopPrice, norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            case OrderType.MarketOnOpen:
                order = new MarketOnOpenOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity, norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            case OrderType.MarketOnClose:
                order = new MarketOnCloseOrder(norderticket.Security, norderticket.FundId, norderticket.Quantity, norderticket.CreatedUtc, norderticket.ExchangeName, norderticket.Comment)
                {
                    InternalId = _portfolio.OrderTicketHandler.GetNextInternalOrderId()
                };
                break;

            default:
                ticket.SetResponse(OrderTicketResponse.Error(ticket.OrderId, OrderTicketResponseErrorCode.ProcessingError, $"Unknown order type {norderticket.OrderType} supplied"));
                return(null);
            }

            //Check if order type is supported
            bool issupported;

            try
            {
                issupported = _brokerModel.IsOrderTypeSupported(order.Type);
            }
            catch (Exception exc)
            {
                _log.Error(exc, $"Could not execute brokermodel function IsOrderTypeSupported due to exception");
                throw exc;
            }

            //Create pending order
            return(new PendingOrder(_portfolio, ticket.FundId, order, norderticket.Comment,
                                    norderticket.Security.LastTickEventUtc, issupported));
        }
示例#17
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 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;
        }
示例#18
0
 public OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
 {
     MarketOnCloseFillWasCalled = true;
     return(orderEvent);
 }
示例#19
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);
        }
示例#20
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 OrderEvent MarketOnCloseFill(Security asset, MarketOnCloseOrder order)
 {
     return(_fillModel.MarketOnCloseFill(asset, order));
 }