Lean  $LEAN_TAG$
CompositeRiskManagementModel.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.Collections.Generic;
18 using System.Linq;
19 using Python.Runtime;
22 using QuantConnect.Util;
23 
25 {
26  /// <summary>
27  /// Provides an implementation of <see cref="IRiskManagementModel"/> that combines multiple risk
28  /// models into a single risk management model and properly sets each insights 'SourceModel' property.
29  /// </summary>
31  {
32  private readonly List<IRiskManagementModel> _riskManagementModels = new List<IRiskManagementModel>();
33 
34  /// <summary>
35  /// Initializes a new instance of the <see cref="CompositeRiskManagementModel"/> class
36  /// </summary>
37  /// <param name="riskManagementModels">The individual risk management models defining this composite model</param>
38  public CompositeRiskManagementModel(params IRiskManagementModel[] riskManagementModels)
39  {
40  if (riskManagementModels.IsNullOrEmpty())
41  {
42  throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel");
43  }
44 
45  _riskManagementModels.AddRange(riskManagementModels);
46  }
47 
48  /// <summary>
49  /// Initializes a new instance of the <see cref="CompositeRiskManagementModel"/> class
50  /// </summary>
51  /// <param name="riskManagementModels">The individual risk management models defining this composite model</param>
52  public CompositeRiskManagementModel(IEnumerable<IRiskManagementModel>riskManagementModels)
53  {
54  foreach (var riskManagementModel in riskManagementModels)
55  {
56  AddRiskManagement(riskManagementModel);
57  }
58 
59  if (_riskManagementModels.IsNullOrEmpty())
60  {
61  throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel");
62  }
63  }
64 
65  /// <summary>
66  /// Initializes a new instance of the <see cref="CompositeRiskManagementModel"/> class
67  /// </summary>
68  /// <param name="riskManagementModels">The individual risk management models defining this composite model</param>
69  public CompositeRiskManagementModel(params PyObject[] riskManagementModels)
70  {
71  if (riskManagementModels.IsNullOrEmpty())
72  {
73  throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel");
74  }
75 
76  foreach (var pyRiskManagementModel in riskManagementModels)
77  {
78  AddRiskManagement(pyRiskManagementModel);
79  }
80  }
81 
82  /// <summary>
83  /// Initializes a new instance of the <see cref="CompositeRiskManagementModel"/> class
84  /// </summary>
85  /// <param name="riskManagementModel">The individual risk management model defining this composite model</param>
86  public CompositeRiskManagementModel(PyObject riskManagementModel)
87  : this(new[] { riskManagementModel} )
88  {
89 
90  }
91 
92  /// <summary>
93  /// Manages the algorithm's risk at each time step.
94  /// This method patches this call through the each of the wrapped models.
95  /// </summary>
96  /// <param name="algorithm">The algorithm instance</param>
97  /// <param name="targets">The current portfolio targets to be assessed for risk</param>
98  /// <returns>The new portfolio targets</returns>
99  public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
100  {
101  foreach (var model in _riskManagementModels)
102  {
103  // take into account the possibility of ManageRisk returning nothing
104  var riskAdjusted = model.ManageRisk(algorithm, targets);
105 
106  // produce a distinct set of new targets giving preference to newer targets
107  targets = riskAdjusted.Concat(targets).DistinctBy(t => t.Symbol).ToArray();
108  }
109 
110  return targets;
111  }
112 
113  /// <summary>
114  /// Event fired each time the we add/remove securities from the data feed.
115  /// This method patches this call through the each of the wrapped models.
116  /// </summary>
117  /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
118  /// <param name="changes">The security additions and removals from the algorithm</param>
119  public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
120  {
121  foreach (var model in _riskManagementModels)
122  {
123  model.OnSecuritiesChanged(algorithm, changes);
124  }
125  }
126 
127  /// <summary>
128  /// Adds a new <see cref="IRiskManagementModel"/> instance
129  /// </summary>
130  /// <param name="riskManagementModel">The risk management model to add</param>
131  public void AddRiskManagement(IRiskManagementModel riskManagementModel)
132  {
133  _riskManagementModels.Add(riskManagementModel);
134  }
135 
136  /// <summary>
137  /// Adds a new <see cref="IRiskManagementModel"/> instance
138  /// </summary>
139  /// <param name="pyRiskManagementModel">The risk management model to add</param>
140  public void AddRiskManagement(PyObject pyRiskManagementModel)
141  {
142  IRiskManagementModel riskManagementModel;
143  if (!pyRiskManagementModel.TryConvert(out riskManagementModel))
144  {
145  riskManagementModel = new RiskManagementModelPythonWrapper(pyRiskManagementModel);
146  }
147  _riskManagementModels.Add(riskManagementModel);
148  }
149  }
150 }