Lean  $LEAN_TAG$
AlphaModelPythonWrapper.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 Python.Runtime;
17 using QuantConnect.Data;
19 using System;
20 using System.Collections.Generic;
21 using QuantConnect.Python;
22 
24 {
25  /// <summary>
26  /// Provides an implementation of <see cref="IAlphaModel"/> that wraps a <see cref="PyObject"/> object
27  /// </summary>
29  {
30  private readonly BasePythonWrapper<AlphaModel> _model;
31 
32  /// <summary>
33  /// Defines a name for a framework model
34  /// </summary>
35  public override string Name
36  {
37  get
38  {
39  using (Py.GIL())
40  {
41  // if the model defines a Name property then use that
42  if (_model.HasAttr(nameof(Name)))
43  {
44  return _model.GetProperty<string>(nameof(Name));
45  }
46 
47  // if the model does not define a name property, use the python type name
48  return _model.GetProperty(" __class__" ).GetAttr("__name__").GetAndDispose<string>();
49  }
50  }
51  }
52 
53  /// <summary>
54  /// Constructor for initialising the <see cref="IAlphaModel"/> class with wrapped <see cref="PyObject"/> object
55  /// </summary>
56  /// <param name="model">>Model that generates alpha</param>
57  public AlphaModelPythonWrapper(PyObject model)
58  {
59  _model = new BasePythonWrapper<AlphaModel>(model, false);
60  foreach (var attributeName in new[] { "Update", "OnSecuritiesChanged" })
61  {
62  if (!_model.HasAttr(attributeName))
63  {
64  throw new NotImplementedException($"IAlphaModel.{attributeName} must be implemented. Please implement this missing method on {model.GetPythonType()}");
65  }
66  }
67  }
68 
69  /// <summary>
70  /// Updates this alpha model with the latest data from the algorithm.
71  /// This is called each time the algorithm receives data for subscribed securities
72  /// </summary>
73  /// <param name="algorithm">The algorithm instance</param>
74  /// <param name="data">The new data available</param>
75  /// <returns>The new insights generated</returns>
76  public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
77  {
78  using (Py.GIL())
79  {
80  var insights = _model.InvokeMethod(nameof(Update), algorithm, new PythonSlice(data));
81  var iterator = insights.GetIterator();
82  foreach (PyObject insight in iterator)
83  {
84  yield return insight.GetAndDispose<Insight>();
85  }
86  iterator.Dispose();
87  insights.Dispose();
88  }
89  }
90 
91  /// <summary>
92  /// Event fired each time the we add/remove securities from the data feed
93  /// </summary>
94  /// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
95  /// <param name="changes">The security additions and removals from the algorithm</param>
96  public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
97  {
98  _model.InvokeMethod(nameof(OnSecuritiesChanged), algorithm, changes).Dispose();
99  }
100  }
101 }