Files
quantconnect--lean/Tests/Common/Data/DollarVolumeRenkoConsolidatorTests.cs
2026-07-13 13:02:50 +08:00

183 lines
7.4 KiB
C#

/*
* 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 System.Collections.Generic;
using Common.Data.Consolidators;
using NUnit.Framework;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
namespace QuantConnect.Tests.Common.Data
{
[TestFixture]
public class DollarVolumeRenkoConsolidatorTests : BaseConsolidatorTests
{
protected override IDataConsolidator CreateConsolidator()
{
return new DollarVolumeRenkoConsolidator(10m);
}
[Test]
public void OutputTypeIsVolumeRenkoBar()
{
using var consolidator = new DollarVolumeRenkoConsolidator(10);
Assert.AreEqual(typeof(VolumeRenkoBar), consolidator.OutputType);
}
[Test]
public void ConsolidatesOnTickDollarVolumeReached()
{
VolumeRenkoBar bar = null;
using var consolidator = new DollarVolumeRenkoConsolidator(100m); // $100 bar size
consolidator.DataConsolidated += (sender, consolidated) =>
{
bar = consolidated;
};
var startTime = new DateTime(2023, 1, 1);
// Price: $10, Quantity: 7 -> $70 dollar volume
consolidator.Update(new Tick(startTime, Symbols.AAPL, "", "", 7m, 10m));
Assert.IsNull(bar);
// Price: $3, Quantity: 20 -> $60 dollar volume (total $110)
consolidator.Update(new Tick(startTime.AddHours(1), Symbols.AAPL, "", "", 20m, 3m));
Assert.IsNotNull(bar);
// Verify bar properties
Assert.AreEqual(10m, bar.Open);
Assert.AreEqual(10m, bar.High);
Assert.AreEqual(3m, bar.Low);
Assert.AreEqual(3m, bar.Close);
Assert.AreEqual(100m, bar.Volume);
Assert.AreEqual(100m, bar.BrickSize);
Assert.AreEqual(Symbols.AAPL, bar.Symbol);
Assert.AreEqual(startTime, bar.Start);
Assert.AreEqual(startTime.AddHours(1), bar.EndTime);
Assert.IsTrue(bar.IsClosed);
}
[Test]
public void ConsolidatesOnTradeBarDollarVolumeReached()
{
VolumeRenkoBar bar = null;
using var consolidator = new DollarVolumeRenkoConsolidator(200m); // $200 bar size
consolidator.DataConsolidated += (sender, consolidated) =>
{
bar = consolidated;
};
var startTime = new DateTime(2023, 1, 1);
// Close: $11 Volume: 10 -> Dollar volume: $100
consolidator.Update(new TradeBar(startTime, Symbols.AAPL, 10m, 12m, 9m, 11m, 10m, TimeSpan.FromHours(1)));
Assert.IsNull(bar);
// Close: $21 Volume: 6 -> Dollar volume: $126 (total $226)
consolidator.Update(new TradeBar(startTime.AddHours(1), Symbols.AAPL, 20m, 22m, 18m, 21m, 6m, TimeSpan.FromHours(1)));
Assert.IsNotNull(bar);
// Verify bar properties
Assert.AreEqual(10m, bar.Open);
Assert.AreEqual(22m, bar.High);
Assert.AreEqual(9m, bar.Low);
Assert.AreEqual(21m, bar.Close);
Assert.AreEqual(200m, bar.Volume);
Assert.AreEqual(200m, bar.BrickSize);
Assert.AreEqual(Symbols.AAPL, bar.Symbol);
Assert.AreEqual(startTime, bar.Start);
Assert.AreEqual(startTime.AddHours(2), bar.EndTime);
Assert.IsTrue(bar.IsClosed);
}
[Test]
public void HandlesMultipleConsolidations()
{
var consolidatedBars = new List<VolumeRenkoBar>();
using var consolidator = new DollarVolumeRenkoConsolidator(100m);
consolidator.DataConsolidated += (sender, consolidated) =>
{
consolidatedBars.Add(consolidated);
};
var startTime = new DateTime(2023, 1, 1);
// First bar: $50 + $60 = $110
consolidator.Update(new Tick(startTime, Symbols.AAPL, "", "", 10m, 5m));
consolidator.Update(new Tick(startTime.AddHours(1), Symbols.AAPL, "", "", 20m, 3m));
// Second bar: $80 + $30 = $110 (total $220)
consolidator.Update(new Tick(startTime.AddHours(2), Symbols.AAPL, "", "", 20m, 4m));
consolidator.Update(new Tick(startTime.AddHours(3), Symbols.AAPL, "", "", 20m, 1.5m));
Assert.AreEqual(2, consolidatedBars.Count);
// Verify first bar
Assert.AreEqual(5m, consolidatedBars[0].Open);
Assert.AreEqual(3m, consolidatedBars[0].Close);
Assert.AreEqual(100m, consolidatedBars[0].Volume);
Assert.IsTrue(consolidatedBars[0].IsClosed);
// Verify second bar
Assert.AreEqual(3m, consolidatedBars[1].Open);
Assert.AreEqual(1.5m, consolidatedBars[1].Close);
Assert.AreEqual(100m, consolidatedBars[1].Volume);
Assert.IsTrue(consolidatedBars[1].IsClosed);
}
[Test]
public void ThrowsOnNonTradeData()
{
using var consolidator = new DollarVolumeRenkoConsolidator(100m);
var startTime = new DateTime(2023, 1, 1);
Assert.Throws<ArgumentException>(() =>
consolidator.Update(new QuoteBar(
startTime,
Symbols.AAPL,
new Bar(1m, 1m, 1m, 1m),
1m,
new Bar(1m, 1m, 1m, 1m),
1m,
TimeSpan.FromHours(1)
))
);
}
protected override IEnumerable<IBaseData> GetTestValues()
{
var time = new DateTime(2023, 1, 1);
return new List<Tick>()
{
new Tick(time, Symbols.AAPL, "", "", 10m, 5m), // $50
new Tick(time.AddSeconds(1), Symbols.AAPL, "", "", 12m, 4m), // $48
new Tick(time.AddSeconds(2), Symbols.AAPL, "", "", 15m, 2m), // $30
new Tick(time.AddSeconds(3), Symbols.AAPL, "", "", 14m, 3m), // $42
new Tick(time.AddSeconds(4), Symbols.AAPL, "", "", 16m, 5m), // $80
new Tick(time.AddSeconds(5), Symbols.AAPL, "", "", 18m, 3m), // $54
new Tick(time.AddSeconds(6), Symbols.AAPL, "", "", 17m, 4m), // $68
new Tick(time.AddSeconds(7), Symbols.AAPL, "", "", 19m, 2m), // $38
new Tick(time.AddSeconds(8), Symbols.AAPL, "", "", 20m, 6m), // $120
new Tick(time.AddSeconds(9), Symbols.AAPL, "", "", 22m, 3m), // $66
new Tick(time.AddSeconds(10), Symbols.AAPL, "", "", 21m, 4m), // $84
new Tick(time.AddSeconds(11), Symbols.AAPL, "", "", 23m, 5m), // $115
new Tick(time.AddSeconds(12), Symbols.AAPL, "", "", 25m, 2m) // $50
};
}
}
}