Example #1
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, 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/normal market hours before filling
            if (!IsExchangeOpen(asset, false))
            {
                return(fill);
            }

            fill.FillPrice = GetPricesCheckingPythonWrapper(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;
                // 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);
        }
Example #2
0
 /// <summary>
 /// Wrapper for <see cref = "IFillModel.MarketOnOpenFill(Security, MarketOnOpenOrder)" /> 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 MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
 {
     using (Py.GIL())
     {
         return(_model.MarketOnOpenFill(asset, order));
     }
 }
Example #3
0
        public void PerformsMarketOnOpenUsingOpenPrice()
        {
            var reference = DateTime.Today.AddHours(9);// before market open
            var model     = new SecurityTransactionModel();
            var order     = new MarketOnOpenOrder(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.MarketOnOpenFill(security, order);

            Assert.AreEqual(0, fill.FillQuantity);

            // market opens after 30min, so this is just before market open
            time = reference.AddMinutes(29);
            security.SetMarketPrice(time, new TradeBar(time, Symbol, 1.33m, 2.75m, 1.15m, 1.45m, 100));

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

            // market opens after 30min
            time = reference.AddMinutes(30);
            security.SetMarketPrice(time, new TradeBar(time, Symbol, 1.45m, 2.0m, 1.1m, 1.40m, 100));

            fill = model.MarketOnOpenFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Open, fill.FillPrice);
        }
Example #4
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 override OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
 {
     using (Py.GIL())
     {
         return((_model.MarketOnOpenFill(asset, order) as PyObject).GetAndDispose <OrderEvent>());
     }
 }
Example #5
0
        public void PerformsMarketOnOpenUsingOpenPrice()
        {
            var reference = new DateTime(2015, 06, 05, 9, 0, 0); // before market open
            var model     = new SecurityTransactionModel();
            var order     = new MarketOnOpenOrder(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.MarketOnOpenFill(security, order);

            Assert.AreEqual(0, fill.FillQuantity);

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

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

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

            fill = model.MarketOnOpenFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Open, fill.FillPrice);
        }
        /// <summary>
        /// Market on Open 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 MarketOnOpenFill(Security security, MarketOnOpenOrder order)
        {
            var fill = new OrderEvent(order);

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

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

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

                order.Price  = security.Open;
                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);
        }
Example #7
0
        public void PerformsMarketOnOpenUsingOpenPrice()
        {
            var reference = new DateTime(2015, 06, 05, 9, 0, 0); // before market open
            var model     = new ImmediateFillModel();
            var order     = new MarketOnOpenOrder(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, Symbols.SPY, 1m, 2m, 0.5m, 1.33m, 100));

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

            Assert.AreEqual(0, fill.FillQuantity);

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

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

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

            fill = model.MarketOnOpenFill(security, order);
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(security.Open, fill.FillPrice);
        }
Example #8
0
        /// <summary>
        /// Market on open order implementation: Send a market order when the exchange opens
        /// </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 MarketOnOpen(string symbol, int quantity, string tag = "")
        {
            var error = PreOrderChecks(symbol, quantity, OrderType.MarketOnOpen);

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

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

            return(Transactions.AddOrder(order));
        }
        public void DeserializesMarketOnOpenOrder(Symbols.SymbolsKey key)
        {
            var expected = new MarketOnOpenOrder(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);
        }
Example #10
0
        public void DeserializesMarketOnOpenOrder()
        {
            var expected = new MarketOnOpenOrder(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);
        }
Example #11
0
        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);
            }
            var currentBar     = asset.GetLastData();
            var localOrderTime = order.Time.ConvertFromUtc(asset.Exchange.TimeZone);

            if (currentBar == null || localOrderTime >= currentBar.EndTime)
            {
                return(fill);
            }
            if (asset.Exchange.DateTimeIsOpen(localOrderTime) && localOrderTime.Date == asset.LocalTime.Date)
            {
                return(fill);
            }
            if (!IsExchangeOpen(asset))
            {
                return(fill);
            }
            fill.FillPrice = GetPrices(asset, order.Direction).Open;
            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);
        }
Example #12
0
 public OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
 {
     MarketOnOpenFillWasCalled = true;
     return(orderEvent);
 }
        public void DeserializesNullLastFillTimeAndLastUpdateTime()
        {
            const string json = @"{
    'Type': 4,
    'Id': 1,
    'ContingentId': 0,
    'BrokerId': [
        '1'
    ],
    'Symbol': {
        'Value': 'SPY',
        'ID': 'SPY R735QTJ8XC9X',
        'Permtick': 'SPY'
    },
    'Price': 321.66,
    'PriceCurrency': 'USD',
    'Time': '2019-12-24T14:31:00Z',
    'CreatedTime': '2019-12-24T14:31:00Z',
    'LastUpdateTime': '2019-12-25T14:31:00Z',
    'LastFillTime': null,
    'Quantity': 1.0,
    'Status': 3,
    'TimeInForce': {},
    'Tag': '',
    'Properties': {
        'TimeInForce': {}
    },
    'SecurityType': 1,
    'Direction': 0,
    'AbsoluteQuantity': 1.0,
    'Value': 321.66,
    'OrderSubmissionData': {
        'BidPrice': 321.4700,
        'AskPrice': 321.4700,
        'LastPrice': 321.4700
    },
    'IsMarketable': false
}";

            const string json2 = @"{
    'Type': 4,
    'Id': 1,
    'ContingentId': 0,
    'BrokerId': [
        '1'
    ],
    'Symbol': {
        'Value': 'SPY',
        'ID': 'SPY R735QTJ8XC9X',
        'Permtick': 'SPY'
    },
    'Price': 321.66,
    'PriceCurrency': 'USD',
    'Time': '2019-12-24T14:31:00Z',
    'CreatedTime': '2019-12-24T14:31:00Z',
    'LastUpdateTime': null,
    'LastFillTime': '2019-12-26T14:31:00Z',
    'Quantity': 1.0,
    'Status': 3,
    'TimeInForce': {},
    'Tag': '',
    'Properties': {
        'TimeInForce': {}
    },
    'SecurityType': 1,
    'Direction': 0,
    'AbsoluteQuantity': 1.0,
    'Value': 321.66,
    'OrderSubmissionData': {
        'BidPrice': 321.4700,
        'AskPrice': 321.4700,
        'LastPrice': 321.4700
    },
    'IsMarketable': false
}";

            var time       = DateTime.SpecifyKind(new DateTime(2019, 12, 24, 14, 31, 0), DateTimeKind.Utc);
            var fillTime   = DateTime.SpecifyKind(new DateTime(2019, 12, 26, 14, 31, 0), DateTimeKind.Utc);
            var updateTime = DateTime.SpecifyKind(new DateTime(2019, 12, 25, 14, 31, 0), DateTimeKind.Utc);

            var expected1 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
            {
                Id           = 1,
                ContingentId = 0,
                BrokerId     = new List <string> {
                    "1"
                },
                Price               = 321.66m,
                PriceCurrency       = "USD",
                LastFillTime        = null,
                LastUpdateTime      = updateTime,
                Status              = OrderStatus.Filled,
                OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
            };

            var expected2 = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, time)
            {
                Id           = 1,
                ContingentId = 0,
                BrokerId     = new List <string> {
                    "1"
                },
                Price               = 321.66m,
                PriceCurrency       = "USD",
                LastFillTime        = updateTime,
                LastUpdateTime      = null,
                Status              = OrderStatus.Filled,
                OrderSubmissionData = new OrderSubmissionData(321.47m, 321.47m, 321.47m),
            };


            var actual1 = (MarketOnOpenOrder)DeserializeOrder <MarketOnOpenOrder>(json);
            var actual2 = (MarketOnOpenOrder)DeserializeOrder <MarketOnOpenOrder>(json2);

            TestOrderType(expected1);
            TestOrderType(expected2);
            TestOrderType(actual1);
            TestOrderType(actual2);
        }
Example #14
0
        public void RoundTripUsingJsonConverter(string timeInForceStr)
        {
            TimeInForce timeInForce = null;

            switch (timeInForceStr)
            {
            case "Day":
                timeInForce = TimeInForce.Day;
                break;

            case "GoodTilCanceled":
                timeInForce = TimeInForce.GoodTilCanceled;
                break;

            case "GoodTilDate":
                timeInForce = TimeInForce.GoodTilDate(DateTime.UtcNow);
                break;
            }
            var expected = new MarketOnOpenOrder(Symbol.Create("SPY", SecurityType.Equity, Market.USA), 1m, DateTime.UtcNow)
            {
                Id           = 1,
                ContingentId = 0,
                BrokerId     = new List <string> {
                    "1"
                },
                Price               = 321.66m,
                PriceCurrency       = "USD",
                LastFillTime        = DateTime.UtcNow,
                LastUpdateTime      = DateTime.UtcNow,
                CanceledTime        = DateTime.UtcNow,
                Status              = OrderStatus.Filled,
                OrderSubmissionData = new OrderSubmissionData(321.47m, 321.48m, 321.49m),
                Properties          = { TimeInForce = timeInForce }
            };

            var converter  = new OrderJsonConverter();
            var serialized = JsonConvert.SerializeObject(expected, converter);
            var actual     = JsonConvert.DeserializeObject <Order>(serialized, converter);

            CollectionAssert.AreEqual(expected.BrokerId, actual.BrokerId);
            Assert.AreEqual(expected.ContingentId, actual.ContingentId);
            Assert.AreEqual(expected.Direction, actual.Direction);
            Assert.AreEqual(expected.TimeInForce.GetType(), actual.TimeInForce.GetType());
            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.Price, actual.Price);
            Assert.AreEqual(expected.PriceCurrency, actual.PriceCurrency);
            Assert.AreEqual(expected.SecurityType, actual.SecurityType);
            Assert.AreEqual(expected.Status, actual.Status);
            Assert.AreEqual(expected.Symbol, actual.Symbol);
            Assert.AreEqual(expected.Tag, actual.Tag);
            Assert.AreEqual(expected.Time, actual.Time);
            Assert.AreEqual(expected.CreatedTime, actual.CreatedTime);
            Assert.AreEqual(expected.LastFillTime, actual.LastFillTime);
            Assert.AreEqual(expected.LastUpdateTime, actual.LastUpdateTime);
            Assert.AreEqual(expected.CanceledTime, actual.CanceledTime);
            Assert.AreEqual(expected.Type, actual.Type);
            Assert.AreEqual(expected.Value, actual.Value);
            Assert.AreEqual(expected.Quantity, actual.Quantity);
            Assert.AreEqual(expected.TimeInForce.GetType(), actual.TimeInForce.GetType());
            Assert.AreEqual(expected.Symbol.ID.Market, actual.Symbol.ID.Market);
            Assert.AreEqual(expected.OrderSubmissionData.AskPrice, actual.OrderSubmissionData.AskPrice);
            Assert.AreEqual(expected.OrderSubmissionData.BidPrice, actual.OrderSubmissionData.BidPrice);
            Assert.AreEqual(expected.OrderSubmissionData.LastPrice, actual.OrderSubmissionData.LastPrice);
        }
Example #15
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));
        }
        /// <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 informaton detailing the average price and quantity filled.</returns>
        public OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
        {
            var fill = new OrderEvent(order);

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

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

                order.Price  = asset.Open;
                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);
        }
Example #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 = 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;
        }
Example #18
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 primaryExchange = (byte)((Equity)asset).PrimaryExchange;
                var officialOpen    = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.OfficialOpen);
                var openingPrints   = (uint)(TradeConditionFlags.Regular | TradeConditionFlags.OpeningPrints);

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

                if (trade != null)
                {
                    endTime        = trade.EndTime;
                    fill.FillPrice = trade.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;
                }
            }

            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);

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

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

            return(fill);
        }
Example #19
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)
 {
     return(_fillModel.MarketOnOpenFill(asset, order));
 }
Example #20
0
 public override OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder order)
 {
     MarketOnOpenFillWasCalled = true;
     return(base.MarketOnOpenFill(asset, order));
 }
Example #21
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);
        }