Lean  $LEAN_TAG$
FutureFillModel.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using QuantConnect.Util;
18 using QuantConnect.Data;
21 
23 {
24  /// <summary>
25  /// Represents the fill model used to simulate order fills for futures
26  /// </summary>
28  {
29  /// <summary>
30  /// Default market fill model for the base security class. Fills at the last traded price.
31  /// </summary>
32  /// <param name="asset">Security asset we're filling</param>
33  /// <param name="order">Order packet to model</param>
34  /// <returns>Order fill information detailing the average price and quantity filled.</returns>
35  public override OrderEvent MarketFill(Security asset, MarketOrder order)
36  {
37  //Default order event to return.
38  var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
39  var fill = new OrderEvent(order, utcTime, OrderFee.Zero);
40 
41  if (order.Status == OrderStatus.Canceled) return fill;
42 
43  // make sure the exchange is open on regular/extended market hours before filling
44  if (!IsExchangeOpen(asset, true)) return fill;
45 
46  var prices = GetPricesCheckingPythonWrapper(asset, order.Direction);
47  var pricesEndTimeUtc = prices.EndTime.ConvertToUtc(asset.Exchange.TimeZone);
48 
49  // if the order is filled on stale (fill-forward) data, set a warning message on the order event
50  if (pricesEndTimeUtc.Add(Parameters.StalePriceTimeSpan) < order.Time)
51  {
52  fill.Message = Messages.FillModel.FilledAtStalePrice(asset, prices);
53  }
54 
55  //Order [fill]price for a market order model is the current security price
56  fill.FillPrice = prices.Current;
57  fill.Status = OrderStatus.Filled;
58 
59  //Calculate the model slippage: e.g. 0.01c
60  var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);
61 
62  //Apply slippage
63  switch (order.Direction)
64  {
65  case OrderDirection.Buy:
66  fill.FillPrice += slip;
67  break;
68  case OrderDirection.Sell:
69  fill.FillPrice -= slip;
70  break;
71  }
72 
73  // assume the order completely filled
74  fill.FillQuantity = order.Quantity;
75 
76  return fill;
77  }
78 
79  /// <summary>
80  /// Stop fill model implementation for Future.
81  /// </summary>
82  /// <param name="asset">Security asset we're filling</param>
83  /// <param name="order">Order packet to model</param>
84  /// <returns>Order fill information detailing the average price and quantity filled.</returns>
85  /// <remarks>
86  /// A Stop order is an instruction to submit a buy or sell market order
87  /// if and when the user-specified stop trigger price is attained or penetrated.
88  ///
89  /// A Sell Stop order is always placed below the current market price.
90  /// We assume a fluid/continuous, high volume market. Therefore, it is filled at the stop trigger price
91  /// if the current low price of trades is less than or equal to this price.
92  ///
93  /// A Buy Stop order is always placed above the current market price.
94  /// We assume a fluid, high volume market. Therefore, it is filled at the stop trigger price
95  /// if the current high price of trades is greater or equal than this price.
96  ///
97  /// The continuous market assumption is not valid if the market opens with an unfavorable gap.
98  /// In this case, a new bar opens below/above the stop trigger price, and the order is filled with the opening price.
99  /// <seealso cref="MarketFill(Security, MarketOrder)"/></remarks>
100  public override OrderEvent StopMarketFill(Security asset, StopMarketOrder order)
101  {
102  //Default order event to return.
103  var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
104  var fill = new OrderEvent(order, utcTime, OrderFee.Zero);
105 
106  //If its cancelled don't need anymore checks:
107  if (order.Status == OrderStatus.Canceled) return fill;
108 
109  // Fill only if open or extended
110  // even though data from internal configurations are not sent to the algorithm.OnData they still drive security cache and data
111  // this is specially relevant for the continuous contract underlying mapped contracts which are internal configurations
112  if (!IsExchangeOpen(asset, Parameters.ConfigProvider.GetSubscriptionDataConfigs(asset.Symbol, includeInternalConfigs: true).IsExtendedMarketHours()))
113  {
114  return fill;
115  }
116 
117  //Get the range of prices in the last bar:
118  var prices = GetPricesCheckingPythonWrapper(asset, order.Direction);
119  var pricesEndTime = prices.EndTime.ConvertToUtc(asset.Exchange.TimeZone);
120 
121  // do not fill on stale data
122  if (pricesEndTime <= order.Time) return fill;
123 
124  //Calculate the model slippage: e.g. 0.01c
125  var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);
126 
127  //Check if the Stop Order was filled: opposite to a limit order
128  switch (order.Direction)
129  {
130  case OrderDirection.Sell:
131  //-> 1.1 Sell Stop: If Price below setpoint, Sell:
132  if (prices.Low < order.StopPrice)
133  {
134  fill.Status = OrderStatus.Filled;
135  // Assuming worse case scenario fill - fill at lowest of the stop & asset price.
136  fill.FillPrice = Math.Min(order.StopPrice, prices.Current - slip);
137  // assume the order completely filled
138  fill.FillQuantity = order.Quantity;
139  }
140  break;
141 
142  case OrderDirection.Buy:
143  //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
144  if (prices.High > order.StopPrice)
145  {
146  fill.Status = OrderStatus.Filled;
147  // Assuming worse case scenario fill - fill at highest of the stop & asset price.
148  fill.FillPrice = Math.Max(order.StopPrice, prices.Current + slip);
149  // assume the order completely filled
150  fill.FillQuantity = order.Quantity;
151  }
152  break;
153  }
154 
155  return fill;
156  }
157  }
158 }