diff --git a/Algorithm.Framework/Portfolio/AlphaStreamsPortfolioConstructionModel.cs b/Algorithm.Framework/Portfolio/AlphaStreamsPortfolioConstructionModel.cs
index 326e75037090..34b188409176 100644
--- a/Algorithm.Framework/Portfolio/AlphaStreamsPortfolioConstructionModel.cs
+++ b/Algorithm.Framework/Portfolio/AlphaStreamsPortfolioConstructionModel.cs
@@ -22,8 +22,13 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
///
/// Base alpha streams portfolio construction model
///
- public class AlphaStreamsPortfolioConstructionModel : IPortfolioConstructionModel
+ public class AlphaStreamsPortfolioConstructionModel : IPortfolioConstructionModel, INamedModel
{
+ ///
+ /// Defines a name for the framework model
+ ///
+ public virtual string Name { get; set; } = nameof(AlphaStreamsPortfolioConstructionModel);
+
///
/// Get's the weight for an alpha
///
diff --git a/Algorithm.Framework/Portfolio/MaximumSharpeRatioPortfolioOptimizer.cs b/Algorithm.Framework/Portfolio/MaximumSharpeRatioPortfolioOptimizer.cs
index abad946fdee4..871b6305211a 100644
--- a/Algorithm.Framework/Portfolio/MaximumSharpeRatioPortfolioOptimizer.cs
+++ b/Algorithm.Framework/Portfolio/MaximumSharpeRatioPortfolioOptimizer.cs
@@ -18,6 +18,8 @@
using Accord.Math;
using Accord.Math.Optimization;
using Accord.Statistics;
+using QuantConnect.Algorithm.Framework.Alphas;
+using static System.FormattableString;
namespace QuantConnect.Algorithm.Framework.Portfolio
{
@@ -26,12 +28,17 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
/// The interval of weights in optimization method can be changed based on the long-short algorithm.
/// The default model uses flat risk free rate and weight for an individual security range from -1 to 1.
///
- public class MaximumSharpeRatioPortfolioOptimizer : IPortfolioOptimizer
+ public class MaximumSharpeRatioPortfolioOptimizer : IPortfolioOptimizer, INamedModel
{
private double _lower;
private double _upper;
private double _riskFreeRate;
+ ///
+ /// Defines a name for the portfolio optimizer
+ ///
+ public string Name { get; }
+
///
/// Initialize a new instance of
///
@@ -43,6 +50,7 @@ public MaximumSharpeRatioPortfolioOptimizer(double lower = -1, double upper = 1,
_lower = lower;
_upper = upper;
_riskFreeRate = riskFreeRate;
+ Name = Invariant($"{nameof(MaximumSharpeRatioPortfolioOptimizer)}({lower},{upper},{riskFreeRate})");
}
///
@@ -137,4 +145,4 @@ public double[] Optimize(double[,] historicalReturns, double[] expectedReturns =
return sum > 0 ? y.Divide(sum) : equalWeights;
}
}
-}
\ No newline at end of file
+}
diff --git a/Algorithm.Framework/Portfolio/MinimumVariancePortfolioOptimizer.cs b/Algorithm.Framework/Portfolio/MinimumVariancePortfolioOptimizer.cs
index c986087a7e5b..32b013bc94f4 100644
--- a/Algorithm.Framework/Portfolio/MinimumVariancePortfolioOptimizer.cs
+++ b/Algorithm.Framework/Portfolio/MinimumVariancePortfolioOptimizer.cs
@@ -18,6 +18,8 @@
using Accord.Math;
using Accord.Math.Optimization;
using Accord.Statistics;
+using QuantConnect.Algorithm.Framework.Alphas;
+using static System.FormattableString;
namespace QuantConnect.Algorithm.Framework.Portfolio
{
@@ -26,12 +28,17 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
/// with the weight range from -1 to 1 and minimize the portfolio variance with a target return of 2%
///
/// The budged constrain is scaled down/up to ensure that the sum of the absolute value of the weights is 1.
- public class MinimumVariancePortfolioOptimizer : IPortfolioOptimizer
+ public class MinimumVariancePortfolioOptimizer : IPortfolioOptimizer, INamedModel
{
private double _lower;
private double _upper;
private double _targetReturn;
+ ///
+ /// Defines a name for the portfolio optimizer
+ ///
+ public string Name { get; }
+
///
/// Initialize a new instance of
///
@@ -43,6 +50,7 @@ public MinimumVariancePortfolioOptimizer(double lower = -1, double upper = 1, do
_lower = lower;
_upper = upper;
_targetReturn = targetReturn;
+ Name = Invariant($"{nameof(MinimumVariancePortfolioOptimizer)}({lower},{upper},{targetReturn})");
}
///
diff --git a/Algorithm.Framework/Portfolio/PortfolioOptimizerPythonWrapper.cs b/Algorithm.Framework/Portfolio/PortfolioOptimizerPythonWrapper.cs
index 5bb22c7ffd0e..8a9366a5edf3 100644
--- a/Algorithm.Framework/Portfolio/PortfolioOptimizerPythonWrapper.cs
+++ b/Algorithm.Framework/Portfolio/PortfolioOptimizerPythonWrapper.cs
@@ -15,6 +15,7 @@
*/
using Python.Runtime;
+using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Python;
namespace QuantConnect.Algorithm.Framework.Portfolio
@@ -22,8 +23,27 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
///
/// Python wrapper for custom portfolio optimizer
///
- public class PortfolioOptimizerPythonWrapper : BasePythonWrapper, IPortfolioOptimizer
+ public class PortfolioOptimizerPythonWrapper : BasePythonWrapper, IPortfolioOptimizer, INamedModel
{
+ ///
+ /// Defines a name for the portfolio optimizer
+ ///
+ public string Name
+ {
+ get
+ {
+ using (Py.GIL())
+ {
+ if (HasAttr(nameof(Name)))
+ {
+ return GetProperty(nameof(Name));
+ }
+
+ return GetProperty("__class__").GetAttr("__name__").GetAndDispose();
+ }
+ }
+ }
+
///
/// Creates a new instance
///
diff --git a/Algorithm.Framework/Portfolio/RiskParityPortfolioOptimizer.cs b/Algorithm.Framework/Portfolio/RiskParityPortfolioOptimizer.cs
index 64cad6f656ce..b77119e8aa63 100644
--- a/Algorithm.Framework/Portfolio/RiskParityPortfolioOptimizer.cs
+++ b/Algorithm.Framework/Portfolio/RiskParityPortfolioOptimizer.cs
@@ -17,6 +17,8 @@
using System.Linq;
using Accord.Math;
using Accord.Statistics;
+using QuantConnect.Algorithm.Framework.Alphas;
+using static System.FormattableString;
namespace QuantConnect.Algorithm.Framework.Portfolio
{
@@ -24,11 +26,16 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
/// Provides an implementation of a risk parity portfolio optimizer that calculate the optimal weights
/// with the weight range from 0 to 1 and equalize the risk carried by each asset
///
- public class RiskParityPortfolioOptimizer : IPortfolioOptimizer
+ public class RiskParityPortfolioOptimizer : IPortfolioOptimizer, INamedModel
{
private double _lower = 1e-05;
private double _upper = Double.MaxValue;
+ ///
+ /// Defines a name for the portfolio optimizer
+ ///
+ public string Name { get; }
+
///
/// Initialize a new instance of
///
@@ -38,6 +45,7 @@ public RiskParityPortfolioOptimizer(double? lower = null, double? upper = null)
{
_lower = lower ?? _lower; // has to be greater than or equal to 0
_upper = upper ?? _upper;
+ Name = Invariant($"{nameof(RiskParityPortfolioOptimizer)}({_lower},{_upper})");
}
///
diff --git a/Algorithm.Framework/Portfolio/UnconstrainedMeanVariancePortfolioOptimizer.cs b/Algorithm.Framework/Portfolio/UnconstrainedMeanVariancePortfolioOptimizer.cs
index edcb75c05084..ce04df774711 100644
--- a/Algorithm.Framework/Portfolio/UnconstrainedMeanVariancePortfolioOptimizer.cs
+++ b/Algorithm.Framework/Portfolio/UnconstrainedMeanVariancePortfolioOptimizer.cs
@@ -15,14 +15,20 @@
using Accord.Math;
using Accord.Statistics;
+using QuantConnect.Algorithm.Framework.Alphas;
namespace QuantConnect.Algorithm.Framework.Portfolio
{
///
/// Provides an implementation of a portfolio optimizer with unconstrained mean variance.
///
- public class UnconstrainedMeanVariancePortfolioOptimizer : IPortfolioOptimizer
+ public class UnconstrainedMeanVariancePortfolioOptimizer : IPortfolioOptimizer, INamedModel
{
+ ///
+ /// Defines a name for the portfolio optimizer
+ ///
+ public string Name { get; } = nameof(UnconstrainedMeanVariancePortfolioOptimizer);
+
///
/// Perform portfolio optimization for a provided matrix of historical returns and an array of expected returns
///
@@ -37,4 +43,4 @@ public double[] Optimize(double[,] historicalReturns, double[] expectedReturns =
return Π.Dot(Σ.Inverse());
}
}
-}
\ No newline at end of file
+}
diff --git a/Algorithm/Execution/ExecutionModel.cs b/Algorithm/Execution/ExecutionModel.cs
index 5407cd10876d..b451dc825611 100644
--- a/Algorithm/Execution/ExecutionModel.cs
+++ b/Algorithm/Execution/ExecutionModel.cs
@@ -14,6 +14,7 @@
*/
using QuantConnect.Algorithm.Framework.Portfolio;
+using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Orders;
using QuantConnect.Python;
@@ -23,8 +24,13 @@ namespace QuantConnect.Algorithm.Framework.Execution
///
/// Provides a base class for execution models
///
- public class ExecutionModel : BasePythonWrapper, IExecutionModel
+ public class ExecutionModel : BasePythonWrapper, IExecutionModel, INamedModel
{
+ ///
+ /// Defines a name for the framework model
+ ///
+ public virtual string Name { get; set; }
+
///
/// If true, orders should be submitted asynchronously.
///
@@ -36,6 +42,7 @@ public class ExecutionModel : BasePythonWrapper, IExecutionModel
/// If true, orders should be submitted asynchronously
public ExecutionModel(bool asynchronous = true)
{
+ Name = GetType().Name;
Asynchronous = asynchronous;
}
diff --git a/Algorithm/Execution/ExecutionModelPythonWrapper.cs b/Algorithm/Execution/ExecutionModelPythonWrapper.cs
index bfc7848ab390..8cd4160f445b 100644
--- a/Algorithm/Execution/ExecutionModelPythonWrapper.cs
+++ b/Algorithm/Execution/ExecutionModelPythonWrapper.cs
@@ -29,6 +29,25 @@ public class ExecutionModelPythonWrapper : ExecutionModel
{
private readonly bool _onOrderEventsDefined;
+ ///
+ /// Defines a name for the framework model
+ ///
+ public override string Name
+ {
+ get
+ {
+ using (Py.GIL())
+ {
+ if (HasAttr(nameof(Name)))
+ {
+ return GetProperty(nameof(Name));
+ }
+
+ return GetProperty("__class__").GetAttr("__name__").GetAndDispose();
+ }
+ }
+ }
+
///
/// Constructor for initialising the class with wrapped object
///
diff --git a/Algorithm/Portfolio/PortfolioConstructionModel.cs b/Algorithm/Portfolio/PortfolioConstructionModel.cs
index bd5a3b5b00fb..3b26da63a3a9 100644
--- a/Algorithm/Portfolio/PortfolioConstructionModel.cs
+++ b/Algorithm/Portfolio/PortfolioConstructionModel.cs
@@ -27,12 +27,17 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
///
/// Provides a base class for portfolio construction models
///
- public class PortfolioConstructionModel : IPortfolioConstructionModel
+ public class PortfolioConstructionModel : IPortfolioConstructionModel, INamedModel
{
private Func _rebalancingFunc;
private DateTime? _rebalancingTime;
private bool _securityChanges;
+ ///
+ /// Defines a name for the framework model
+ ///
+ public virtual string Name { get; set; }
+
///
/// True if should rebalance portfolio on security changes. True by default
///
@@ -63,6 +68,7 @@ public class PortfolioConstructionModel : IPortfolioConstructionModel
/// will trigger rebalance. If null will be ignored
public PortfolioConstructionModel(Func rebalancingFunc)
{
+ Name = GetType().Name;
_rebalancingFunc = rebalancingFunc;
}
diff --git a/Algorithm/Portfolio/PortfolioConstructionModelPythonWrapper.cs b/Algorithm/Portfolio/PortfolioConstructionModelPythonWrapper.cs
index d381df49c248..3e77e08cf096 100644
--- a/Algorithm/Portfolio/PortfolioConstructionModelPythonWrapper.cs
+++ b/Algorithm/Portfolio/PortfolioConstructionModelPythonWrapper.cs
@@ -30,6 +30,25 @@ public class PortfolioConstructionModelPythonWrapper : PortfolioConstructionMode
private readonly BasePythonWrapper _model;
private readonly bool _implementsDetermineTargetPercent;
+ ///
+ /// Defines a name for the framework model
+ ///
+ public override string Name
+ {
+ get
+ {
+ using (Py.GIL())
+ {
+ if (_model.HasAttr(nameof(Name)))
+ {
+ return _model.GetProperty(nameof(Name));
+ }
+
+ return _model.GetProperty("__class__").GetAttr("__name__").GetAndDispose();
+ }
+ }
+ }
+
///
/// True if should rebalance portfolio on security changes. True by default
///
diff --git a/Algorithm/Risk/RiskManagementModel.cs b/Algorithm/Risk/RiskManagementModel.cs
index 9e5c0b7f2999..54efb6a7aa16 100644
--- a/Algorithm/Risk/RiskManagementModel.cs
+++ b/Algorithm/Risk/RiskManagementModel.cs
@@ -14,6 +14,7 @@
*/
using System.Collections.Generic;
+using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Data.UniverseSelection;
@@ -22,8 +23,21 @@ namespace QuantConnect.Algorithm.Framework.Risk
///
/// Provides a base class for risk management models
///
- public class RiskManagementModel : IRiskManagementModel
+ public class RiskManagementModel : IRiskManagementModel, INamedModel
{
+ ///
+ /// Defines a name for the framework model
+ ///
+ public virtual string Name { get; set; }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ public RiskManagementModel()
+ {
+ Name = GetType().Name;
+ }
+
///
/// Manages the algorithm's risk at each time step
///
@@ -43,4 +57,4 @@ public virtual void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges c
{
}
}
-}
\ No newline at end of file
+}
diff --git a/Algorithm/Risk/RiskManagementModelPythonWrapper.cs b/Algorithm/Risk/RiskManagementModelPythonWrapper.cs
index bc7a2a6b243d..362dbb0945f0 100644
--- a/Algorithm/Risk/RiskManagementModelPythonWrapper.cs
+++ b/Algorithm/Risk/RiskManagementModelPythonWrapper.cs
@@ -28,6 +28,25 @@ public class RiskManagementModelPythonWrapper : RiskManagementModel
{
private readonly BasePythonWrapper _model;
+ ///
+ /// Defines a name for the framework model
+ ///
+ public override string Name
+ {
+ get
+ {
+ using (Py.GIL())
+ {
+ if (_model.HasAttr(nameof(Name)))
+ {
+ return _model.GetProperty(nameof(Name));
+ }
+
+ return _model.GetProperty("__class__").GetAttr("__name__").GetAndDispose();
+ }
+ }
+ }
+
///
/// Constructor for initialising the class with wrapped object
///
diff --git a/Algorithm/Selection/UniverseSelectionModel.cs b/Algorithm/Selection/UniverseSelectionModel.cs
index 68f070fcca9f..58bcbf46940f 100644
--- a/Algorithm/Selection/UniverseSelectionModel.cs
+++ b/Algorithm/Selection/UniverseSelectionModel.cs
@@ -15,6 +15,7 @@
using System;
using System.Collections.Generic;
+using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Python;
@@ -24,14 +25,19 @@ namespace QuantConnect.Algorithm.Framework.Selection
///
/// Provides a base class for universe selection models.
///
- public class UniverseSelectionModel : BasePythonWrapper, IUniverseSelectionModel
+ public class UniverseSelectionModel : BasePythonWrapper, IUniverseSelectionModel, INamedModel
{
+ ///
+ /// Defines a name for the framework model
+ ///
+ public virtual string Name { get; set; }
///
/// Initializes a new instance of the class.
///
public UniverseSelectionModel()
{
+ Name = GetType().Name;
}
///
@@ -52,4 +58,4 @@ public virtual IEnumerable CreateUniverses(QCAlgorithm algorithm)
throw new NotImplementedException("Types deriving from 'UniverseSelectionModel' must implement the 'IEnumerable CreateUniverses(QCAlgorithm) method.");
}
}
-}
\ No newline at end of file
+}
diff --git a/Algorithm/Selection/UniverseSelectionModelPythonWrapper.cs b/Algorithm/Selection/UniverseSelectionModelPythonWrapper.cs
index 8f2c88e14804..11fccbfb1ed8 100644
--- a/Algorithm/Selection/UniverseSelectionModelPythonWrapper.cs
+++ b/Algorithm/Selection/UniverseSelectionModelPythonWrapper.cs
@@ -29,6 +29,25 @@ public class UniverseSelectionModelPythonWrapper : UniverseSelectionModel
{
private readonly bool _modelHasGetNextRefreshTime;
+ ///
+ /// Defines a name for the framework model
+ ///
+ public override string Name
+ {
+ get
+ {
+ using (Py.GIL())
+ {
+ if (HasAttr(nameof(Name)))
+ {
+ return GetProperty(nameof(Name));
+ }
+
+ return GetProperty("__class__").GetAttr("__name__").GetAndDispose();
+ }
+ }
+ }
+
///
/// Gets the next time the framework should invoke the `CreateUniverses` method to refresh the set of universes.
///
diff --git a/Tests/Algorithm/Framework/FrameworkModelNameTests.cs b/Tests/Algorithm/Framework/FrameworkModelNameTests.cs
new file mode 100644
index 000000000000..49b71e3b01ab
--- /dev/null
+++ b/Tests/Algorithm/Framework/FrameworkModelNameTests.cs
@@ -0,0 +1,68 @@
+/*
+ * 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.Collections.Generic;
+using NUnit.Framework;
+using QuantConnect.Algorithm.Framework.Alphas;
+using QuantConnect.Algorithm.Framework.Execution;
+using QuantConnect.Algorithm.Framework.Portfolio;
+using QuantConnect.Algorithm.Framework.Risk;
+using QuantConnect.Algorithm.Framework.Selection;
+
+namespace QuantConnect.Tests.Algorithm.Framework
+{
+ [TestFixture]
+ public class FrameworkModelNameTests
+ {
+ private static IEnumerable FrameworkComponents
+ {
+ get
+ {
+ yield return new TestCaseData(new ExecutionModel(), "ExecutionModel");
+ yield return new TestCaseData(new PortfolioConstructionModel(), "PortfolioConstructionModel");
+ yield return new TestCaseData(new RiskManagementModel(), "RiskManagementModel");
+ yield return new TestCaseData(new UniverseSelectionModel(), "UniverseSelectionModel");
+ yield return new TestCaseData(new AlphaStreamsPortfolioConstructionModel(), "AlphaStreamsPortfolioConstructionModel");
+ }
+ }
+
+ private static IEnumerable PortfolioOptimizers
+ {
+ get
+ {
+ yield return new TestCaseData(
+ new MaximumSharpeRatioPortfolioOptimizer(-2.5, 3.5, 0.125),
+ "MaximumSharpeRatioPortfolioOptimizer(-2.5,3.5,0.125)");
+ yield return new TestCaseData(
+ new MinimumVariancePortfolioOptimizer(-2.5, 3.5, 0.125),
+ "MinimumVariancePortfolioOptimizer(-2.5,3.5,0.125)");
+ yield return new TestCaseData(
+ new RiskParityPortfolioOptimizer(0.05, 2.5),
+ "RiskParityPortfolioOptimizer(0.05,2.5)");
+ yield return new TestCaseData(
+ new UnconstrainedMeanVariancePortfolioOptimizer(),
+ "UnconstrainedMeanVariancePortfolioOptimizer");
+ }
+ }
+
+ [TestCaseSource(nameof(FrameworkComponents))]
+ [TestCaseSource(nameof(PortfolioOptimizers))]
+ public void FrameworkComponentProvidesExpectedName(object component, string expectedName)
+ {
+ Assert.IsInstanceOf(component);
+ Assert.AreEqual(expectedName, ((INamedModel)component).Name);
+ }
+ }
+}