public void NextTickTime_CreatesTimes(Resolution resolution, DataDensity density) { var count = 100; var deltaSum = TimeSpan.Zero; var previous = new DateTime(2019, 01, 14, 9, 30, 0); var increment = resolution.ToTimeSpan(); if (increment == TimeSpan.Zero) { increment = TimeSpan.FromMilliseconds(500); } var marketHours = MarketHoursDatabase.FromDataFolder() .GetExchangeHours(_symbol.ID.Market, _symbol, _symbol.SecurityType); for (int i = 0; i < count; i++) { var next = _tickGenerator.NextTickTime(previous, resolution, density); var barStart = next.Subtract(increment); Assert.Less(previous, next); Assert.IsTrue(marketHours.IsOpen(barStart, next, false)); var delta = next - previous; deltaSum += delta; previous = next; } var avgDelta = TimeSpan.FromTicks(deltaSum.Ticks / count); switch (density) { case DataDensity.Dense: // more frequent than once an increment Assert.Less(avgDelta, increment); break; case DataDensity.Sparse: // less frequent that once an increment Assert.Greater(avgDelta, increment); break; case DataDensity.VerySparse: // less frequent than one every 10 increments Assert.Greater(avgDelta, TimeSpan.FromTicks(increment.Ticks * 10)); break; default: throw new ArgumentOutOfRangeException(nameof(density), density, null); } }
public virtual DateTime NextTickTime(Symbol symbol, DateTime previous, Resolution resolution, DataDensity density) { var increment = resolution.ToTimeSpan(); if (increment == TimeSpan.Zero) { increment = TimeSpan.FromMilliseconds(500); } double steps; switch (density) { case DataDensity.Dense: steps = 0.5 * _random.NextDouble(); break; case DataDensity.Sparse: steps = 5 * _random.NextDouble(); break; case DataDensity.VerySparse: steps = 50 * _random.NextDouble(); break; default: throw new ArgumentOutOfRangeException(nameof(density), density, null); } var delta = TimeSpan.FromTicks((long) (steps * increment.Ticks)); var tickTime = previous.Add(delta); if (tickTime == previous) { tickTime = tickTime.Add(increment); } var barStart = tickTime.Subtract(increment); var marketHours = _marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType); if (!marketHours.IsDateOpen(tickTime) || !marketHours.IsOpen(barStart, tickTime, false)) { // we ended up outside of market hours, emit a new tick at market open var nextMarketOpen = marketHours.GetNextMarketOpen(tickTime, false); if (resolution == Resolution.Tick) { resolution = Resolution.Second; } // emit a new tick somewhere in the next trading day at a step higher resolution to guarantee a hit return NextTickTime(symbol, nextMarketOpen, resolution - 1, density); } return tickTime; }