/* * 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 QuantConnect.Data.Market; namespace QuantConnect.Data.Consolidators { /// /// This consolidator can transform a stream of instances into a stream of /// with a constant volume for each bar. /// public class VolumeRenkoConsolidator : DataConsolidator { private VolumeRenkoBar _currentBar; private decimal _barSize; /// /// Gets a clone of the data being currently consolidated /// public override IBaseData WorkingData => _currentBar; /// /// Gets which is the type emitted in the event. /// public override Type OutputType => typeof(VolumeRenkoBar); /// /// Event handler that fires when a new piece of data is produced /// public new event EventHandler DataConsolidated; /// /// Initializes a new instance of the class using the specified . /// /// The constant volume size of each bar public VolumeRenkoConsolidator(decimal barSize) { _barSize = barSize; } /// /// Updates this consolidator with the specified data /// /// The new data for the consolidator public override void Update(BaseData data) { var close = data.Price; var dataType = data.GetType(); decimal volume; decimal open; decimal high; decimal low; if (dataType == typeof(TradeBar)) { var tradeBar = (TradeBar)data; volume = tradeBar.Volume; open = tradeBar.Open; high = tradeBar.High; low = tradeBar.Low; } else if (dataType == typeof(Tick)) { var tick = (Tick)data; // Only include actual trade information if (tick.TickType != TickType.Trade) { return; } volume = tick.Quantity; open = close; high = close; low = close; } else { throw new ArgumentException($"{GetType().Name} must be used with TradeBar or Tick data."); } var adjustedVolume = AdjustVolume(volume, close); if (_currentBar == null) { _currentBar = new VolumeRenkoBar(data.Symbol, data.Time, data.EndTime, _barSize, open, high, low, close, 0); } var volumeLeftOver = _currentBar.Update(data.EndTime, high, low, close, adjustedVolume); while (volumeLeftOver >= 0) { OnDataConsolidated(_currentBar); _currentBar = _currentBar.Rollover(); volumeLeftOver = _currentBar.Update(data.EndTime, high, low, close, volumeLeftOver); } } /// /// Returns the raw volume without any adjustment. /// /// The volume /// The price /// The unmodified volume protected virtual decimal AdjustVolume(decimal volume, decimal price) { return volume; } /// /// 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) { } /// /// Resets the consolidator /// public override void Reset() { base.Reset(); _currentBar = null; } /// /// Event invocator for the DataConsolidated event. This should be invoked /// by derived classes when they have consolidated a new piece of data. /// /// The newly consolidated data protected void OnDataConsolidated(VolumeRenkoBar consolidated) { base.OnDataConsolidated(consolidated); DataConsolidated?.Invoke(this, consolidated); } } }