/* * 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 Python.Runtime; using QuantConnect.Data; using QuantConnect.Data.Market; using System; namespace QuantConnect.Indicators { /// /// Provides a wrapper for implementations written in python /// public class PythonIndicator : IndicatorBase { private readonly dynamic _indicator; /// /// Get the indicator Name. If not defined, use the class name /// /// The python implementation of /// The indicator Name. private static string GetIndicatorName(PyObject indicator) { using (Py.GIL()) { var name = indicator.HasAttr("Name") ? indicator.GetAttr("Name") : indicator.GetAttr("__class__").GetAttr("__name__"); return name.GetAndDispose(); } } /// /// Initializes a new instance of the PythonIndicator class using the specified name. /// /// The python implementation of public PythonIndicator(PyObject indicator) : base(GetIndicatorName(indicator)) { using (Py.GIL()) { foreach (var attributeName in new[] {"Update", "IsReady", "Value"}) { if (!indicator.HasAttr(attributeName)) { throw new NotImplementedException( $"Indicator.{attributeName} must be implemented. Please implement this missing method on {indicator.GetPythonType()}" ); } } } _indicator = indicator; } /// /// Updates the state of this indicator with the given value and returns true /// if this indicator is ready, false otherwise /// /// The value to use to update this indicator /// True if this indicator is ready, false otherwise public new bool Update(IBaseData input) { using (Py.GIL()) { _indicator.Update(input); } return IsReady; } /// /// Gets a flag indicating when this indicator is ready and fully initialized /// /// If IsReady is not defined in the Python indicator, always returns false public override bool IsReady { get { using (Py.GIL()) { return _indicator.IsReady; } } } /// /// Computes the next value of this indicator from the given state /// /// The input given to the indicator /// A new value for this indicator protected override decimal ComputeNextValue(IBaseDataBar input) { Update(input); using (Py.GIL()) { return _indicator.Value; } } } }