コード例 #1
0
 /// <summary>
 /// Limit if Touched Fill Model. Return an order event with the fill details.
 /// </summary>
 /// <param name="asset">Asset we're trading this order</param>
 /// <param name="order"><see cref="LimitIfTouchedOrder"/> Order to Check, return filled if true</param>
 /// <returns>Order fill information detailing the average price and quantity filled.</returns>
 public override OrderEvent LimitIfTouchedFill(Security asset, LimitIfTouchedOrder order)
 {
     using (Py.GIL())
     {
         return((_model.LimitIfTouchedFill(asset, order) as PyObject).GetAndDispose <OrderEvent>());
     }
 }
コード例 #2
0
        public void DeserializesLimitIfTouchedOrder(Symbols.SymbolsKey key)
        {
            var expected = new LimitIfTouchedOrder(Symbols.Lookup(key), 100, 210.10m, 200.23m, new DateTime(2015, 11, 23, 17, 15, 37), "now")
            {
                Id           = 12345,
                Price        = 209.03m,
                ContingentId = 123456,
                BrokerId     = new List <string> {
                    "727", "54970"
                }
            };

            var actual = TestOrderType(expected);

            Assert.AreEqual(expected.TriggerPrice, actual.TriggerPrice);
            Assert.AreEqual(expected.LimitPrice, actual.LimitPrice);
        }
コード例 #3
0
        public void PerformsLimitIfTouchedFillSell()
        {
            var model          = new ImmediateFillModel();
            var order          = new LimitIfTouchedOrder(Symbols.SPY, -100, 101.5m, 105m, Noon);
            var configTradeBar = CreateTradeBarConfig(Symbols.SPY);
            var configQuoteBar = new SubscriptionDataConfig(configTradeBar, typeof(QuoteBar));
            var configProvider = new MockSubscriptionDataConfigProvider(configQuoteBar);
            var security       = new Security(
                SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(),
                configTradeBar,
                new Cash(Currencies.USD, 0, 1m),
                SymbolProperties.GetDefault(Currencies.USD),
                ErrorCurrencyConverter.Instance,
                RegisteredSecurityDataTypesProvider.Null,
                new SecurityCache()
                );

            // Sets price at time zero
            security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
            security.SetMarketPrice(new TradeBar(Noon, Symbols.SPY, 100m, 100m, 90m, 90m, 100));
            configProvider.SubscriptionDataConfigs.Add(configTradeBar);

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

            Assert.AreEqual(0, fill.FillQuantity);
            Assert.AreEqual(0, fill.FillPrice);
            Assert.AreEqual(OrderStatus.None, fill.Status);

            // Time jump => trigger touched but not limit
            security.SetMarketPrice(new TradeBar(Noon, Symbols.SPY, 102m, 103m, 102m, 102m, 100));
            security.SetMarketPrice(new QuoteBar(Noon, Symbols.SPY,
                                                 new Bar(101m, 102m, 100m, 100m), 100, // Bid bar
                                                 new Bar(103m, 104m, 102m, 102m), 100) // Ask bar
                                    );

            Assert.AreEqual(0, fill.FillQuantity);
            Assert.AreEqual(0, fill.FillPrice);
            Assert.AreEqual(OrderStatus.None, fill.Status);

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

            Assert.AreEqual(0, fill.FillQuantity);
            Assert.AreEqual(0, fill.FillPrice);
            Assert.AreEqual(OrderStatus.None, fill.Status);

            // Time jump => limit reached, holdings sold
            security.SetMarketPrice(new TradeBar(Noon, Symbols.SPY, 103m, 108m, 103m, 105m, 100));
            security.SetMarketPrice(new QuoteBar(Noon, Symbols.SPY,
                                                 new Bar(103m, 106m, 103m, 105m), 100, // Bid bar
                                                 new Bar(103m, 108m, 103m, 105m), 100) // Ask bar
                                    );


            fill = model.LimitIfTouchedFill(security, order);

            // this fills worst case scenario
            Assert.AreEqual(order.Quantity, fill.FillQuantity);
            Assert.AreEqual(order.LimitPrice, fill.FillPrice);
            Assert.AreEqual(OrderStatus.Filled, fill.Status);
        }
コード例 #4
0
ファイル: EquityFillModel.cs プロジェクト: nika90426/Lean
        /// <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);
        }
コード例 #5
0
ファイル: OrderTests.cs プロジェクト: yzhao20/Lean
        public void LimitIfTouchedOrder_SetsDefaultTag(string tag)
        {
            var order = new LimitIfTouchedOrder(Symbols.SPY, 1m, 123.4567m, 122.4567m, DateTime.Today, tag);

            Assert.AreEqual(Invariant($"Trigger Price: {order.TriggerPrice:C} Limit Price: {order.LimitPrice:C}"), order.Tag);
        }
コード例 #6
0
ファイル: FillModel.cs プロジェクト: QuantConnect/Lean
        /// <summary>
        /// Default limit if touched fill model implementation in base class security. (Limit If Touched Order Type)
        /// </summary>
        /// <param name="asset"></param>
        /// <param name="order"></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 pricesEndTime = DateTime.MinValue;

            var subscribedTypes = GetSubscribedTypes(asset);

            if (subscribedTypes.Contains(typeof(Tick)))
            {
                var trade = GetPricesCheckingPythonWrapper(asset, order.Direction);

                if (trade != null)
                {
                    tradeHigh     = trade.Current;
                    tradeLow      = trade.Current;
                    pricesEndTime = 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;
                    pricesEndTime = tradeBar.EndTime.ConvertToUtc(asset.Exchange.TimeZone);
                }
            }

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

            switch (order.Direction)
            {
            case OrderDirection.Sell:
                if (tradeHigh >= order.TriggerPrice || order.TriggerTouched)
                {
                    order.TriggerTouched = true;

                    //-> 1.1 Limit surpassed: Sell.
                    if (GetAskPrice(asset, out pricesEndTime) >= order.LimitPrice)
                    {
                        fill.Status    = OrderStatus.Filled;
                        fill.FillPrice = order.LimitPrice;
                        // assume the order completely filled
                        fill.FillQuantity = order.Quantity;
                    }
                }
                break;

            case OrderDirection.Buy:
                if (tradeLow <= order.TriggerPrice || order.TriggerTouched)
                {
                    order.TriggerTouched = true;

                    //-> 1.2 Limit surpassed: Buy.
                    if (GetBidPrice(asset, out pricesEndTime) <= order.LimitPrice)
                    {
                        fill.Status    = OrderStatus.Filled;
                        fill.FillPrice = order.LimitPrice;
                        // assume the order completely filled
                        fill.FillQuantity = order.Quantity;
                    }
                }
                break;
            }

            return(fill);
        }
コード例 #7
0
 public override OrderEvent LimitIfTouchedFill(Security asset, LimitIfTouchedOrder order)
 {
     LimitIfTouchFillWasCalled = true;
     return(base.LimitIfTouchedFill(asset, order));
 }