Lean  $LEAN_TAG$
OrderSizing.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 System.Linq;
21 
22 namespace QuantConnect.Orders
23 {
24  /// <summary>
25  /// Provides methods for computing a maximum order size.
26  /// </summary>
27  public static class OrderSizing
28  {
29  /// <summary>
30  /// Adjust the provided order size to respect maximum order size based on a percentage of current volume.
31  /// </summary>
32  /// <param name="security">The security object</param>
33  /// <param name="maximumPercentCurrentVolume">The maximum percentage of the current bar's volume</param>
34  /// <param name="desiredOrderSize">The desired order size to adjust</param>
35  /// <returns>The signed adjusted order size</returns>
36  public static decimal GetOrderSizeForPercentVolume(Security security, decimal maximumPercentCurrentVolume, decimal desiredOrderSize)
37  {
38  var maxOrderSize = maximumPercentCurrentVolume * security.Volume;
39  var orderSize = Math.Min(maxOrderSize, Math.Abs(desiredOrderSize));
40 
41  return Math.Sign(desiredOrderSize) * AdjustByLotSize(security, orderSize);
42  }
43 
44  /// <summary>
45  /// Adjust the provided order size to respect the maximum total order value
46  /// </summary>
47  /// <param name="security">The security object</param>
48  /// <param name="maximumOrderValueInAccountCurrency">The maximum order value in units of the account currency</param>
49  /// <param name="desiredOrderSize">The desired order size to adjust</param>
50  /// <returns>The signed adjusted order size</returns>
51  public static decimal GetOrderSizeForMaximumValue(Security security, decimal maximumOrderValueInAccountCurrency, decimal desiredOrderSize)
52  {
53  var priceInAccountCurrency = security.Price
54  * security.QuoteCurrency.ConversionRate
56 
57  if (priceInAccountCurrency == 0m)
58  {
59  return 0m;
60  }
61 
62  var maxOrderSize = maximumOrderValueInAccountCurrency / priceInAccountCurrency;
63  var orderSize = Math.Min(maxOrderSize, Math.Abs(desiredOrderSize));
64 
65  return Math.Sign(desiredOrderSize) * AdjustByLotSize(security, orderSize);
66  }
67 
68  /// <summary>
69  /// Gets the remaining quantity to be ordered to reach the specified target quantity.
70  /// </summary>
71  /// <param name="algorithm">The algorithm instance</param>
72  /// <param name="target">The portfolio target</param>
73  /// <returns>The signed remaining quantity to be ordered</returns>
74  public static decimal GetUnorderedQuantity(IAlgorithm algorithm, IPortfolioTarget target)
75  {
76  var security = algorithm.Securities[target.Symbol];
77 
78  return GetUnorderedQuantity(algorithm, target, security);
79  }
80 
81  /// <summary>
82  /// Gets the remaining quantity to be ordered to reach the specified target quantity.
83  /// </summary>
84  /// <param name="algorithm">The algorithm instance</param>
85  /// <param name="target">The portfolio target</param>
86  /// <param name="security">The target security</param>
87  /// <returns>The signed remaining quantity to be ordered</returns>
88  public static decimal GetUnorderedQuantity(IAlgorithm algorithm, IPortfolioTarget target, Security security)
89  {
90  var holdings = security.Holdings.Quantity;
91  var openOrderQuantity = algorithm.Transactions.GetOpenOrderTickets(target.Symbol)
92  .Aggregate(0m, (d, t) => d + t.Quantity - t.QuantityFilled);
93  var quantity = target.Quantity - holdings - openOrderQuantity;
94 
95  return AdjustByLotSize(security, quantity);
96  }
97 
98  /// <summary>
99  /// Adjusts the provided order quantity to respect the securities lot size.
100  /// If the quantity is missing 1M part of the lot size it will be rounded up
101  /// since we suppose it's due to floating point error, this is required to avoid diff
102  /// between Py and C#
103  /// </summary>
104  /// <param name="security">The security instance</param>
105  /// <param name="quantity">The desired quantity to adjust, can be signed</param>
106  /// <returns>The signed adjusted quantity</returns>
107  public static decimal AdjustByLotSize(Security security, decimal quantity)
108  {
109  var absQuantity = Math.Abs(quantity);
110  // if the amount we are missing for +1 lot size is 1M part of a lot size
111  // we suppose its due to floating point error and round up
112  // Note: this is required to avoid a diff between Py and C# equivalent
113  var remainder = absQuantity % security.SymbolProperties.LotSize;
114  var missingForLotSize = security.SymbolProperties.LotSize - remainder;
115  if (missingForLotSize < (security.SymbolProperties.LotSize / 1000000))
116  {
117  remainder -= security.SymbolProperties.LotSize;
118  }
119  absQuantity -= remainder;
120 
121  return absQuantity * Math.Sign(quantity);
122  }
123  }
124 }