Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Common/Data/Consolidators/SessionConsolidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ protected override void AggregateBar(ref SessionBar workingBar, BaseData data)
return;
}

// Correct the timestamp if data skipped the predicted next trading day
if (workingBar.Time != DateTime.MaxValue && data.Time.Date > workingBar.Time.Date)
{
workingBar.Time = data.Time.Date;
}

// Update the working session bar
workingBar.Update(data, Consolidated);
}
Expand All @@ -90,7 +96,11 @@ public override void Update(BaseData data)
{
if (!_initialized)
{
_workingBar.Time = data.Time.Date;
// Set the working bar time only if it hasn't been set yet
if (_workingBar.Time == DateTime.MaxValue)
{
_workingBar.Time = data.Time.Date;
}
_initialized = true;
}
base.Update(data);
Expand Down
43 changes: 43 additions & 0 deletions Tests/Indicators/SessionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,49 @@ private static IEnumerable<TestCaseData> NextSessionTradingDayCases()
yield return new TestCaseData(new DateTime(2025, 8, 29, 10, 0, 0), new DateTime(2025, 9, 2));
}

[Test]
public void ManualDailyBarUpdateProducesOneConsolidationPerBar()
{
var symbol = Symbols.SPY;
var barCount = 20;
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
var session = new Session(TickType.Trade, exchangeHours, symbol, barCount + 1);

var barDate = new DateTime(2025, 9, 2, 9, 30, 0);
for (var i = 0; i < barCount; i++)
{
session.Update(new TradeBar(barDate, symbol, 100 + i, 101 + i, 99 + i, 100 + i, 1000, Time.OneDay));
barDate = barDate.AddDays(1);
while (!exchangeHours.IsDateOpen(barDate.Date, false))
{
barDate = barDate.AddDays(1);
}
}

Assert.AreEqual(barCount, session.Samples);
}

[Test]
public void GapDayDataPreservesCorrectTimestampAndContent()
{
var symbol = Symbols.SPY;
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
var session = new Session(TickType.Trade, exchangeHours, symbol, 5);

var sep2 = new DateTime(2025, 9, 2, 9, 30, 0);
var sep4 = new DateTime(2025, 9, 4, 9, 30, 0);
var sep5 = new DateTime(2025, 9, 5, 9, 30, 0);

session.Update(new TradeBar(sep2, symbol, 100, 110, 90, 105, 1000, Time.OneDay));
session.Update(new TradeBar(sep4, symbol, 200, 210, 190, 205, 2000, Time.OneDay));
session.Update(new TradeBar(sep5, symbol, 300, 310, 290, 305, 3000, Time.OneDay));

Assert.AreEqual(sep4.Date, session[1].Time);
Assert.AreEqual(200, session[1].Open);
Assert.AreEqual(sep2.Date, session[2].Time);
Assert.AreEqual(100, session[2].Open);
}

private static Session GetSession(TickType tickType, int initialSize)
{
var symbol = Symbols.SPY;
Expand Down
Loading