/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using Python.Runtime; using QuantConnect.Algorithm.Framework.Portfolio; using QuantConnect.Data.UniverseSelection; using QuantConnect.Util; namespace QuantConnect.Algorithm.Framework.Risk { /// /// Provides an implementation of that combines multiple risk /// models into a single risk management model and properly sets each insights 'SourceModel' property. /// public class CompositeRiskManagementModel : RiskManagementModel { private readonly List _riskManagementModels = new List(); /// /// Initializes a new instance of the class /// /// The individual risk management models defining this composite model public CompositeRiskManagementModel(params IRiskManagementModel[] riskManagementModels) { if (riskManagementModels.IsNullOrEmpty()) { throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel"); } _riskManagementModels.AddRange(riskManagementModels); } /// /// Initializes a new instance of the class /// /// The individual risk management models defining this composite model public CompositeRiskManagementModel(IEnumerableriskManagementModels) { foreach (var riskManagementModel in riskManagementModels) { AddRiskManagement(riskManagementModel); } if (_riskManagementModels.IsNullOrEmpty()) { throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel"); } } /// /// Initializes a new instance of the class /// /// The individual risk management models defining this composite model public CompositeRiskManagementModel(params PyObject[] riskManagementModels) { if (riskManagementModels.IsNullOrEmpty()) { throw new ArgumentException("Must specify at least 1 risk management model for the CompositeRiskManagementModel"); } foreach (var pyRiskManagementModel in riskManagementModels) { AddRiskManagement(pyRiskManagementModel); } } /// /// Initializes a new instance of the class /// /// The individual risk management model defining this composite model public CompositeRiskManagementModel(PyObject riskManagementModel) : this(new[] { riskManagementModel} ) { } /// /// Manages the algorithm's risk at each time step. /// This method patches this call through the each of the wrapped models. /// /// The algorithm instance /// The current portfolio targets to be assessed for risk /// The new portfolio targets public override IEnumerable ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets) { foreach (var model in _riskManagementModels) { // take into account the possibility of ManageRisk returning nothing var riskAdjusted = model.ManageRisk(algorithm, targets); // produce a distinct set of new targets giving preference to newer targets targets = riskAdjusted.Concat(targets).DistinctBy(t => t.Symbol).ToArray(); } return targets; } /// /// Event fired each time the we add/remove securities from the data feed. /// This method patches this call through the each of the wrapped models. /// /// The algorithm instance that experienced the change in securities /// The security additions and removals from the algorithm public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { foreach (var model in _riskManagementModels) { model.OnSecuritiesChanged(algorithm, changes); } } /// /// Adds a new instance /// /// The risk management model to add public void AddRiskManagement(IRiskManagementModel riskManagementModel) { _riskManagementModels.Add(riskManagementModel); } /// /// Adds a new instance /// /// The risk management model to add public void AddRiskManagement(PyObject pyRiskManagementModel) { IRiskManagementModel riskManagementModel; if (!pyRiskManagementModel.TryConvert(out riskManagementModel)) { riskManagementModel = new RiskManagementModelPythonWrapper(pyRiskManagementModel); } _riskManagementModels.Add(riskManagementModel); } } }