/* * 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.Market; namespace QuantConnect.Data.Consolidators { /// /// This consolidator can transform a stream of instances into a stream of /// public class ClassicRenkoConsolidator : BaseTimelessConsolidator { private decimal _barSize; private bool _evenBars; private decimal? _lastCloseValue; /// /// Bar being created /// protected override RenkoBar CurrentBar { get; set; } /// /// Gets the kind of the bar /// public RenkoType Type => RenkoType.Classic; /// /// Gets a clone of the data being currently consolidated /// public override IBaseData WorkingData => CurrentBar?.Clone(); /// /// Gets which is the type emitted in the event. /// public override Type OutputType => typeof(RenkoBar); /// /// Initializes a new instance of the class using the specified . /// The value selector will by default select /// The volume selector will by default select zero. /// /// The constant value size of each bar /// When true bar open/close will be a multiple of the barSize public ClassicRenkoConsolidator(decimal barSize, bool evenBars = true) : base() { EpsilonCheck(barSize); _barSize = barSize; _evenBars = evenBars; } /// /// Initializes a new instance of the class. /// /// The size of each bar in units of the value produced by /// Extracts the value from a data instance to be formed into a . The default /// value is (x => x.Value) the property on /// Extracts the volume from a data instance. The default value is null which does /// not aggregate volume per bar. /// When true bar open/close will be a multiple of the barSize public ClassicRenkoConsolidator( decimal barSize, Func selector, Func volumeSelector = null, bool evenBars = true) : base(selector, volumeSelector) { EpsilonCheck(barSize); _barSize = barSize; _evenBars = evenBars; } /// ///Initializes a new instance of the class. /// /// The constant value size of each bar /// The RenkoType of the bar [Obsolete("Please use the new RenkoConsolidator if RenkoType is not Classic")] public ClassicRenkoConsolidator(decimal barSize, RenkoType type) : this(barSize, true) { if (type != RenkoType.Classic) { throw new ArgumentException("Please use the new RenkoConsolidator type if RenkoType is not Classic"); } } /// /// Initializes a new instance of the class. /// /// The size of each bar in units of the value produced by /// Extracts the value from a data instance to be formed into a . The default /// value is (x => x.Value) the property on /// Extracts the volume from a data instance. The default value is null which does /// not aggregate volume per bar. /// When true bar open/close will be a multiple of the barSize public ClassicRenkoConsolidator(decimal barSize, PyObject selector, PyObject volumeSelector = null, bool evenBars = true) : base(selector, volumeSelector) { EpsilonCheck(barSize); _barSize = barSize; _evenBars = evenBars; } /// /// Resets the ClassicRenkoConsolidator /// public override void Reset() { base.Reset(); _lastCloseValue = null; } /// /// Updates the current RangeBar being created with the given data. /// Additionally, if it's the case, it consolidates the current RangeBar /// /// Time of the given data /// Value of the given data /// Volume of the given data protected override void UpdateBar(DateTime time, decimal currentValue, decimal volume) { CurrentBar.Update(time, currentValue, volume); if (CurrentBar.IsClosed) { _lastCloseValue = CurrentBar.Close; OnDataConsolidated(CurrentBar); CurrentBar = null; } } /// /// Creates a new bar with the given data /// /// The new data for the bar /// The new value for the bar /// The new volume to the bar protected override void CreateNewBar(IBaseData data, decimal currentValue, decimal volume) { var open = _lastCloseValue ?? currentValue; if (_evenBars && !_lastCloseValue.HasValue) { open = Math.Ceiling(open / _barSize) * _barSize; } CurrentBar = new RenkoBar(data.Symbol, data.Time, _barSize, open, volume); } private static void EpsilonCheck(decimal barSize) { if (barSize < Extensions.GetDecimalEpsilon()) { throw new ArgumentOutOfRangeException(nameof(barSize), "RenkoConsolidator bar size must be positve and greater than 1e-28"); } } } /// /// Provides a type safe wrapper on the RenkoConsolidator class. This just allows us to define our selector functions with the real type they'll be receiving /// /// public class ClassicRenkoConsolidator : ClassicRenkoConsolidator where TInput : IBaseData { /// /// Initializes a new instance of the class. /// /// The size of each bar in units of the value produced by /// Extracts the value from a data instance to be formed into a . The default /// value is (x => x.Value) the property on /// Extracts the volume from a data instance. The default value is null which does /// not aggregate volume per bar. /// When true bar open/close will be a multiple of the barSize public ClassicRenkoConsolidator( decimal barSize, Func selector, Func volumeSelector = null, bool evenBars = true ) : base(barSize, x => selector((TInput) x), volumeSelector == null ? (Func) null : x => volumeSelector((TInput) x), evenBars) { } /// /// Initializes a new instance of the class using the specified . /// The value selector will by default select /// The volume selector will by default select zero. /// /// The constant value size of each bar /// When true bar open/close will be a multiple of the barSize public ClassicRenkoConsolidator(decimal barSize, bool evenBars = true) : this(barSize, x => x.Value, x => 0, evenBars) { } /// /// Initializes a new instance of the class using the specified . /// The value selector will by default select /// The volume selector will by default select zero. /// /// The constant value size of each bar /// The RenkoType of the bar [Obsolete("Please use the WickedRenkoConsolidator if RenkoType is not Classic")] public ClassicRenkoConsolidator(decimal barSize, RenkoType type) : base(barSize, type) { } /// /// Updates this consolidator with the specified data. /// /// /// Type safe shim method. /// /// The new data for the consolidator public void Update(TInput data) { base.Update(data); } } }