chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* 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 NodaTime;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Data.Consolidators;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Lean.Engine.DataFeeds.Enumerators;
|
||||
|
||||
namespace QuantConnect.Tests.Engine.DataFeeds.Enumerators
|
||||
{
|
||||
[TestFixture, Parallelizable(ParallelScope.All)]
|
||||
public class ScannableEnumeratorTests
|
||||
{
|
||||
[Test]
|
||||
public void PassesTicksStraightThrough()
|
||||
{
|
||||
var currentTime = new DateTime(2000, 01, 01);
|
||||
using var identityDataConsolidator = new IdentityDataConsolidator<Tick>();
|
||||
var enumerator = new ScannableEnumerator<Tick>(
|
||||
identityDataConsolidator,
|
||||
DateTimeZone.ForOffset(Offset.FromHours(-5)),
|
||||
new ManualTimeProvider(currentTime),
|
||||
(s, e) => { }
|
||||
);
|
||||
|
||||
// returns true even if no data present until stop is called
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick1 = new Tick(currentTime, Symbols.SPY, 199.55m, 199, 200) { Quantity = 10 };
|
||||
enumerator.Update(tick1);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual(tick1, enumerator.Current);
|
||||
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick2 = new Tick(currentTime, Symbols.SPY, 199.56m, 199.21m, 200.02m) { Quantity = 5 };
|
||||
enumerator.Update(tick2);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.AreEqual(tick2, enumerator.Current);
|
||||
|
||||
enumerator.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NewDataAvailableShouldFire()
|
||||
{
|
||||
var currentTime = new DateTime(2000, 01, 01);
|
||||
var available = false;
|
||||
using var identityDataConsolidator = new IdentityDataConsolidator<Tick>();
|
||||
var enumerator = new ScannableEnumerator<Tick>(
|
||||
identityDataConsolidator,
|
||||
DateTimeZone.ForOffset(Offset.FromHours(-5)),
|
||||
new ManualTimeProvider(currentTime),
|
||||
(s, e) => { available = true; }
|
||||
);
|
||||
|
||||
// returns true even if no data present until stop is called
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
Assert.IsFalse(available);
|
||||
|
||||
var tick1 = new Tick(currentTime, Symbols.SPY, 199.55m, 199, 200) { Quantity = 10 };
|
||||
enumerator.Update(tick1);
|
||||
Assert.IsTrue(available);
|
||||
|
||||
enumerator.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AggregatesNewQuoteBarProperly()
|
||||
{
|
||||
var reference = DateTime.Today;
|
||||
|
||||
using var tickQuoteBarConsolidator = new TickQuoteBarConsolidator(4);
|
||||
using var enumerator = new ScannableEnumerator<Data.BaseData>(
|
||||
tickQuoteBarConsolidator,
|
||||
DateTimeZone.ForOffset(Offset.FromHours(-5)),
|
||||
new ManualTimeProvider(reference),
|
||||
(s, e) => { }
|
||||
);
|
||||
|
||||
var tick1 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference,
|
||||
BidPrice = 10,
|
||||
BidSize = 20,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick1);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick2 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddMinutes(1),
|
||||
AskPrice = 20,
|
||||
AskSize = 10,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
|
||||
var badTick = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddMinutes(1),
|
||||
AskPrice = 25,
|
||||
AskSize = 100,
|
||||
BidPrice = -100,
|
||||
BidSize = 2,
|
||||
Value = 50,
|
||||
Quantity = 1234,
|
||||
TickType = TickType.Trade
|
||||
};
|
||||
enumerator.Update(badTick);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
enumerator.Update(tick2);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick3 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddMinutes(2),
|
||||
BidPrice = 12,
|
||||
BidSize = 50,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick3);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick4 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddMinutes(3),
|
||||
AskPrice = 17,
|
||||
AskSize = 15,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick4);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNotNull(enumerator.Current);
|
||||
|
||||
QuoteBar quoteBar = enumerator.Current as QuoteBar;
|
||||
Assert.IsNotNull(quoteBar);
|
||||
|
||||
Assert.AreEqual(Symbols.SPY, quoteBar.Symbol);
|
||||
Assert.AreEqual(tick1.Time, quoteBar.Time);
|
||||
Assert.AreEqual(tick4.EndTime, quoteBar.EndTime);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Open);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Low);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.High);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.Close);
|
||||
Assert.AreEqual(tick3.BidSize, quoteBar.LastBidSize);
|
||||
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.Open);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Low);
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.High);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Close);
|
||||
Assert.AreEqual(tick4.AskSize, quoteBar.LastAskSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ForceScanQuoteBar()
|
||||
{
|
||||
var reference = new DateTime(2020, 2, 2, 1, 0, 0);
|
||||
var timeProvider = new ManualTimeProvider(reference);
|
||||
var dateTimeZone = DateTimeZone.ForOffset(Offset.FromHours(-5));
|
||||
using var tickQuoteBarConsolidator = new TickQuoteBarConsolidator(TimeSpan.FromMinutes(1));
|
||||
using var enumerator = new ScannableEnumerator<Data.BaseData>(
|
||||
tickQuoteBarConsolidator,
|
||||
dateTimeZone,
|
||||
timeProvider,
|
||||
(s, e) => { }
|
||||
);
|
||||
|
||||
var tick1 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.ConvertFromUtc(dateTimeZone),
|
||||
BidPrice = 10,
|
||||
BidSize = 20,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick1);
|
||||
|
||||
var tick2 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddSeconds(1).ConvertFromUtc(dateTimeZone),
|
||||
AskPrice = 20,
|
||||
AskSize = 10,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
|
||||
enumerator.Update(tick2);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick3 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddSeconds(2).ConvertFromUtc(dateTimeZone),
|
||||
BidPrice = 12,
|
||||
BidSize = 50,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick3);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick4 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.AddSeconds(3).ConvertFromUtc(dateTimeZone),
|
||||
AskPrice = 17,
|
||||
AskSize = 15,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick4);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
timeProvider.AdvanceSeconds(120);
|
||||
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNotNull(enumerator.Current);
|
||||
QuoteBar quoteBar = enumerator.Current as QuoteBar;
|
||||
Assert.IsNotNull(quoteBar);
|
||||
|
||||
Assert.AreEqual(Symbols.SPY, quoteBar.Symbol);
|
||||
Assert.AreEqual(tick1.Time, quoteBar.Time);
|
||||
Assert.AreNotEqual(tick4.EndTime, quoteBar.EndTime);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Open);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Low);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.High);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.Close);
|
||||
Assert.AreEqual(tick3.BidSize, quoteBar.LastBidSize);
|
||||
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.Open);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Low);
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.High);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Close);
|
||||
Assert.AreEqual(tick4.AskSize, quoteBar.LastAskSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MoveNextScanQuoteBar()
|
||||
{
|
||||
var offset = Offset.FromHours(-5);
|
||||
var timeZone = DateTimeZone.ForOffset(offset);
|
||||
var utc = new DateTimeOffset(DateTime.Today);
|
||||
var reference = utc.ToOffset(offset.ToTimeSpan());
|
||||
var timeProvider = new ManualTimeProvider(reference.DateTime, timeZone);
|
||||
|
||||
using var tickQuoteBarConsolidator = new TickQuoteBarConsolidator(TimeSpan.FromMinutes(1));
|
||||
using var enumerator = new ScannableEnumerator<Data.BaseData>(
|
||||
tickQuoteBarConsolidator,
|
||||
timeZone,
|
||||
timeProvider,
|
||||
(s, e) => { }
|
||||
);
|
||||
|
||||
var tick1 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.DateTime,
|
||||
BidPrice = 10,
|
||||
BidSize = 20,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick1);
|
||||
|
||||
var tick2 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.DateTime.AddSeconds(1),
|
||||
AskPrice = 20,
|
||||
AskSize = 10,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
|
||||
enumerator.Update(tick2);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick3 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.DateTime.AddSeconds(2),
|
||||
BidPrice = 12,
|
||||
BidSize = 50,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick3);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
var tick4 = new Tick
|
||||
{
|
||||
Symbol = Symbols.SPY,
|
||||
Time = reference.DateTime.AddSeconds(3),
|
||||
AskPrice = 17,
|
||||
AskSize = 15,
|
||||
TickType = TickType.Quote
|
||||
};
|
||||
enumerator.Update(tick4);
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNull(enumerator.Current);
|
||||
|
||||
timeProvider.SetCurrentTime(reference.DateTime.AddMinutes(2));
|
||||
|
||||
Assert.IsTrue(enumerator.MoveNext());
|
||||
Assert.IsNotNull(enumerator.Current);
|
||||
QuoteBar quoteBar = enumerator.Current as QuoteBar;
|
||||
Assert.IsNotNull(quoteBar);
|
||||
|
||||
Assert.AreEqual(Symbols.SPY, quoteBar.Symbol);
|
||||
Assert.AreEqual(tick1.Time, quoteBar.Time);
|
||||
Assert.AreNotEqual(tick4.EndTime, quoteBar.EndTime);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Open);
|
||||
Assert.AreEqual(tick1.BidPrice, quoteBar.Bid.Low);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.High);
|
||||
Assert.AreEqual(tick3.BidPrice, quoteBar.Bid.Close);
|
||||
Assert.AreEqual(tick3.BidSize, quoteBar.LastBidSize);
|
||||
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.Open);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Low);
|
||||
Assert.AreEqual(tick2.AskPrice, quoteBar.Ask.High);
|
||||
Assert.AreEqual(tick4.AskPrice, quoteBar.Ask.Close);
|
||||
Assert.AreEqual(tick4.AskSize, quoteBar.LastAskSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user