Lean  $LEAN_TAG$
PortfolioTarget.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;
19 using System.Collections.Generic;
21 
23 {
24  /// <summary>
25  /// Provides an implementation of <see cref="IPortfolioTarget"/> that specifies a
26  /// specified quantity of a security to be held by the algorithm
27  /// </summary>
29  {
30 
31  /// <summary>
32  /// Flag to determine if the minimum order margin portfolio percentage warning should or has already been sent to the user algorithm
33  /// <see cref="IAlgorithmSettings.MinimumOrderMarginPortfolioPercentage"/>
34  /// </summary>
35  public static bool? MinimumOrderMarginPercentageWarningSent { get; set; }
36 
37  /// <summary>
38  /// Gets the symbol of this target
39  /// </summary>
40  public Symbol Symbol { get; }
41 
42  /// <summary>
43  /// Gets the target quantity for the symbol
44  /// </summary>
45  public decimal Quantity { get; }
46 
47  /// <summary>
48  /// Portfolio target tag with additional information
49  /// </summary>
50  public string Tag { get; }
51 
52  /// <summary>
53  /// Initializes a new instance of the <see cref="PortfolioTarget"/> class
54  /// </summary>
55  /// <param name="symbol">The symbol this target is for</param>
56  /// <param name="quantity">The target quantity</param>
57  /// <param name="tag">The target tag with additional information</param>
58  public PortfolioTarget(Symbol symbol, decimal quantity, string tag = "")
59  {
60  Symbol = symbol;
61  Quantity = quantity;
62  Tag = tag;
63  }
64 
65  /// <summary>
66  /// Creates a new target for the specified percent
67  /// </summary>
68  /// <param name="algorithm">The algorithm instance, used for getting total portfolio value and current security price</param>
69  /// <param name="symbol">The symbol the target is for</param>
70  /// <param name="percent">The requested target percent of total portfolio value</param>
71  /// <returns>A portfolio target for the specified symbol/percent</returns>
72  public static IPortfolioTarget Percent(IAlgorithm algorithm, Symbol symbol, double percent)
73  {
74  return Percent(algorithm, symbol, percent.SafeDecimalCast());
75  }
76 
77  /// <summary>
78  /// Creates a new target for the specified percent
79  /// </summary>
80  /// <param name="algorithm">The algorithm instance, used for getting total portfolio value and current security price</param>
81  /// <param name="symbol">The symbol the target is for</param>
82  /// <param name="percent">The requested target percent of total portfolio value</param>
83  /// <param name="tag">The target tag with additional information</param>
84  /// <returns>A portfolio target for the specified symbol/percent</returns>
85  public static IPortfolioTarget Percent(IAlgorithm algorithm, Symbol symbol, double percent, string tag)
86  {
87  return Percent(algorithm, symbol, percent.SafeDecimalCast(), tag: tag);
88  }
89 
90  /// <summary>
91  /// Creates a new target for the specified percent
92  /// </summary>
93  /// <param name="algorithm">The algorithm instance, used for getting total portfolio value and current security price</param>
94  /// <param name="symbol">The symbol the target is for</param>
95  /// <param name="percent">The requested target percent of total portfolio value</param>
96  /// <param name="returnDeltaQuantity">True, result quantity will be the Delta required to reach target percent.
97  /// False, the result quantity will be the Total quantity to reach the target percent, including current holdings</param>
98  /// <param name="tag">The target tag with additional information</param>
99  /// <returns>A portfolio target for the specified symbol/percent</returns>
100  public static IPortfolioTarget Percent(IAlgorithm algorithm, Symbol symbol, decimal percent, bool returnDeltaQuantity = false, string tag = "")
101  {
102  var absolutePercentage = Math.Abs(percent);
103  if (absolutePercentage > algorithm.Settings.MaxAbsolutePortfolioTargetPercentage
104  || absolutePercentage != 0 && absolutePercentage < algorithm.Settings.MinAbsolutePortfolioTargetPercentage)
105  {
106  algorithm.Error(Messages.PortfolioTarget.InvalidTargetPercent(algorithm, percent));
107  return null;
108  }
109 
110  Security security;
111  try
112  {
113  security = algorithm.Securities[symbol];
114  }
115  catch (KeyNotFoundException)
116  {
117  algorithm.Error(Messages.PortfolioTarget.SymbolNotFound(symbol));
118  return null;
119  }
120 
121  if (security.Price == 0)
122  {
123  algorithm.Error(symbol.GetZeroPriceMessage());
124  return null;
125  }
126 
127  // Factoring in FreePortfolioValuePercentage.
128  var adjustedPercent = percent * algorithm.Portfolio.TotalPortfolioValueLessFreeBuffer / algorithm.Portfolio.TotalPortfolioValue;
129 
130  // we normalize the target buying power by the leverage so we work in the land of margin
131  var targetFinalMarginPercentage = adjustedPercent / security.BuyingPowerModel.GetLeverage(security);
132 
133  var positionGroup = algorithm.Portfolio.Positions.GetOrCreateDefaultGroup(security);
134  var result = positionGroup.BuyingPowerModel.GetMaximumLotsForTargetBuyingPower(
135  new GetMaximumLotsForTargetBuyingPowerParameters(algorithm.Portfolio, positionGroup,
136  targetFinalMarginPercentage, algorithm.Settings.MinimumOrderMarginPortfolioPercentage));
137 
138  if (result.IsError)
139  {
140  algorithm.Error(Messages.PortfolioTarget.UnableToComputeOrderQuantityDueToNullResult(symbol, result));
141 
142  return null;
143  }
144 
146  {
147  // we send the warning once
149  algorithm.Debug(Messages.BuyingPowerModel.TargetOrderMarginNotAboveMinimum());
150  }
151 
152  // be sure to back out existing holdings quantity since the buying power model yields
153  // the required delta quantity to reach a final target portfolio value for a symbol
154  var lotSize = security.SymbolProperties.LotSize;
155  var quantity = result.NumberOfLots * lotSize + (returnDeltaQuantity ? 0 : security.Holdings.Quantity);
156 
157  return new PortfolioTarget(symbol, quantity, tag);
158  }
159 
160  /// <summary>Returns a string that represents the current object.</summary>
161  /// <returns>A string that represents the current object.</returns>
162  /// <filterpriority>2</filterpriority>
163  public override string ToString()
164  {
165  return Messages.PortfolioTarget.ToString(this);
166  }
167  }
168 }