Lean  $LEAN_TAG$
VolumeShareSlippageModel.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 
17 using QuantConnect.Logging;
19 using System;
20 
22 {
23  /// <summary>
24  /// Represents a slippage model that is calculated by multiplying the price impact constant
25  /// by the square of the ratio of the order to the total volume.
26  /// </summary>
28  {
29  private readonly decimal _priceImpact;
30  private readonly decimal _volumeLimit;
31 
32  /// <summary>
33  /// Initializes a new instance of the <see cref="VolumeShareSlippageModel"/> class
34  /// </summary>
35  /// <param name="volumeLimit"></param>
36  /// <param name="priceImpact">Defines how large of an impact the order will have on the price calculation</param>
37  public VolumeShareSlippageModel(decimal volumeLimit = 0.025m, decimal priceImpact = 0.1m)
38  {
39  _priceImpact = priceImpact;
40  _volumeLimit = volumeLimit;
41  }
42 
43  /// <summary>
44  /// Slippage Model. Return a decimal cash slippage approximation on the order.
45  /// </summary>
46  public decimal GetSlippageApproximation(Security asset, Order order)
47  {
48  var lastData = asset.GetLastData();
49  if (lastData == null) return 0;
50 
51  var barVolume = 0m;
52  var slippagePercent = _volumeLimit * _volumeLimit * _priceImpact;
53 
54  switch (lastData.DataType)
55  {
56  case MarketDataType.TradeBar:
57  barVolume = ((TradeBar)lastData).Volume;
58  break;
59  case MarketDataType.QuoteBar:
60  barVolume = order.Direction == OrderDirection.Buy
61  ? ((QuoteBar)lastData).LastBidSize
62  : ((QuoteBar)lastData).LastAskSize;
63  break;
64  default:
65  throw new InvalidOperationException(Messages.VolumeShareSlippageModel.InvalidMarketDataType(lastData));
66  }
67 
68  // If volume is zero or negative, we use the maximum slippage percentage since the impact of any quantity is infinite
69  // In FX/CFD case, we issue a warning and return zero slippage
70  if (barVolume <= 0)
71  {
72  var securityType = asset.Symbol.ID.SecurityType;
73  if (securityType == SecurityType.Cfd || securityType == SecurityType.Forex || securityType == SecurityType.Crypto)
74  {
75  Log.Error(Messages.VolumeShareSlippageModel.VolumeNotReportedForMarketDataType(securityType));
76  return 0;
77  }
78 
79  Log.Error(Messages.VolumeShareSlippageModel.NegativeOrZeroBarVolume(barVolume, slippagePercent));
80  }
81  else
82  {
83  // Ratio of the order to the total volume
84  var volumeShare = Math.Min(order.AbsoluteQuantity / barVolume, _volumeLimit);
85 
86  slippagePercent = volumeShare * volumeShare * _priceImpact;
87  }
88 
89  return slippagePercent * lastData.Value;
90  }
91  }
92 }