Lean  $LEAN_TAG$
MaximumDrawdownPercentPortfolio.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 
17 using System;
18 using System.Collections.Generic;
20 
22 {
23  /// <summary>
24  /// Provides an implementation of <see cref="IRiskManagementModel"/> that limits the drawdown of the portfolio
25  /// to the specified percentage. Once this is triggered the algorithm will need to be manually restarted.
26  /// </summary>
28  {
29  private readonly decimal _maximumDrawdownPercent;
30  private decimal _portfolioHigh;
31  private bool _initialised = false;
32  private bool _isTrailing;
33 
34  /// <summary>
35  /// Initializes a new instance of the <see cref="MaximumDrawdownPercentPortfolio"/> class
36  /// </summary>
37  /// <param name="maximumDrawdownPercent">The maximum percentage drawdown allowed for algorithm portfolio
38  /// compared with starting value, defaults to 5% drawdown</param>
39  /// <param name="isTrailing">If "false", the drawdown will be relative to the starting value of the portfolio.
40  /// If "true", the drawdown will be relative the last maximum portfolio value</param>
41  public MaximumDrawdownPercentPortfolio(decimal maximumDrawdownPercent = 0.05m, bool isTrailing = false)
42  {
43  _maximumDrawdownPercent = -Math.Abs(maximumDrawdownPercent);
44  _isTrailing = isTrailing;
45  }
46 
47  /// <summary>
48  /// Manages the algorithm's risk at each time step
49  /// </summary>
50  /// <param name="algorithm">The algorithm instance</param>
51  /// <param name="targets">The current portfolio targets to be assessed for risk</param>
52  public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
53  {
54  var currentValue = algorithm.Portfolio.TotalPortfolioValue;
55 
56  if (!_initialised)
57  {
58  _portfolioHigh = currentValue; // Set initial portfolio value
59  _initialised = true;
60  }
61 
62  // Update trailing high value if in trailing mode
63  if (_isTrailing && (_portfolioHigh < currentValue))
64  {
65  _portfolioHigh = currentValue;
66  yield break; // return if new high reached
67  }
68 
69  var pnl = GetTotalDrawdownPercent(currentValue);
70  if (pnl < _maximumDrawdownPercent && targets.Length != 0)
71  {
72  // reset the trailing high value for restart investing on next rebalcing period
73  _initialised = false;
74  foreach (var target in targets)
75  {
76  var symbol = target.Symbol;
77 
78  // Cancel insights
79  algorithm.Insights.Cancel(new[] { symbol });
80 
81  // liquidate
82  yield return new PortfolioTarget(symbol, 0);
83  }
84  }
85  }
86 
87  private decimal GetTotalDrawdownPercent(decimal currentValue)
88  {
89  return (currentValue / _portfolioHigh) - 1.0m;
90  }
91  }
92 }