/* * 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 Python.Runtime; using QuantConnect.Data; using QuantConnect.Data.Consolidators; namespace QuantConnect.Python { /// /// Provides an Data Consolidator that wraps a object that represents a custom Python consolidator /// public class DataConsolidatorPythonWrapper : ConsolidatorBase { private readonly BasePythonWrapper _pythonWrapper; private readonly DataConsolidatedHandler _pythonDataConsolidated; private bool _disposed; /// /// Gets a clone of the data being currently consolidated /// public override IBaseData WorkingData { get { return _pythonWrapper.GetProperty(nameof(WorkingData)); } } /// /// Gets the type consumed by this consolidator /// public override Type InputType { get { return _pythonWrapper.GetProperty(nameof(InputType)); } } /// /// Gets the type produced by this consolidator /// public override Type OutputType { get { return _pythonWrapper.GetProperty(nameof(OutputType)); } } /// /// Constructor for initialising the class with wrapped object /// /// Represents a custom python consolidator public DataConsolidatorPythonWrapper(PyObject consolidator) { _pythonWrapper = new BasePythonWrapper(consolidator, true); _pythonDataConsolidated = (_, bar) => OnDataConsolidated(bar); // GetEvent releases the GIL before returning, so the event subscription must // hold it explicitly, otherwise pythonnet mutates the Python object without the GIL using (Py.GIL()) { dynamic pythonEvent = _pythonWrapper.GetEvent("DataConsolidated"); pythonEvent += _pythonDataConsolidated; } } /// /// Scans this consolidator to see if it should emit a bar due to time passing /// /// The current time in the local time zone (same as ) public override void Scan(DateTime currentLocalTime) { _pythonWrapper.InvokeMethod(nameof(Scan), currentLocalTime); } /// /// Updates this consolidator with the specified data /// /// The new data for the consolidator public override void Update(IBaseData data) { _pythonWrapper.InvokeMethod(nameof(Update), data); } /// /// Resets the consolidator /// public override void Reset() { _pythonWrapper.InvokeMethod(nameof(Reset)); base.Reset(); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public override void Dispose() { if (_disposed) { return; } _disposed = true; // Dispose can run from engine threads that do not hold the GIL, so acquire it before // unsubscribing, otherwise the pythonnet event mutation can crash the runtime using (Py.GIL()) { dynamic pythonEvent = _pythonWrapper.GetEvent("DataConsolidated"); pythonEvent -= _pythonDataConsolidated; } _pythonWrapper.Dispose(); base.Dispose(); } /// /// Two wrappers are equal if they wrap the same Python object reference. /// public override bool Equals(object obj) { if (obj is DataConsolidatorPythonWrapper other) { return _pythonWrapper.Equals(other._pythonWrapper); } return _pythonWrapper.Equals(obj); } /// /// Hash code based on the underlying Python object reference. /// public override int GetHashCode() => _pythonWrapper.GetHashCode(); } }