chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 NUnit.Framework;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
{
|
||||
[TestFixture]
|
||||
public class SubscriptionDataReaderTests
|
||||
{
|
||||
// this is the core of this unit test:
|
||||
// the stream will have two data points one of which does not correspond to the tradable date,
|
||||
// and it shouldn't be emitted because we have a new source for the next tradable date
|
||||
[TestCase(@"25980000,1679600,1679700,1679600,1679700,200
|
||||
99900000,1679400,1679400,1679200,1679200,600", false, Resolution.Minute)]
|
||||
// this test case has two data point which should be emitted because they correspond to the same tradable date
|
||||
[TestCase(@"25980000,1679600,1679700,1679600,1679700,200
|
||||
30980000,1679400,1679400,1679200,1679200,600", true, Resolution.Minute)]
|
||||
// even if the second data point is another tradable date we emit it because daily resolution
|
||||
// always uses the same source
|
||||
[TestCase(@"20191209 00:00,956900,959700,947200,958100,3647000
|
||||
20191211 00:00,956900,959700,947200,958100,3647000", true, Resolution.Daily)]
|
||||
public void DoesNotEmitDataBeyondTradableDate(string data, bool shouldEmitSecondDataPoint, Resolution dataResolution)
|
||||
{
|
||||
var start = new DateTime(2019, 12, 9);
|
||||
var end = new DateTime(2019, 12, 12);
|
||||
|
||||
var request = GetRequest(typeof(TradeBar), start, end, dataResolution, out var config);
|
||||
using var testDataCacheProvider = new TestDataCacheProvider() { Data = data };
|
||||
using var dataReader = new SubscriptionDataReader(config,
|
||||
request,
|
||||
TestGlobals.MapFileProvider,
|
||||
TestGlobals.FactorFileProvider,
|
||||
testDataCacheProvider,
|
||||
TestGlobals.DataProvider,
|
||||
null);
|
||||
|
||||
Assert.IsTrue(dataReader.MoveNext());
|
||||
Assert.AreEqual(shouldEmitSecondDataPoint, dataReader.MoveNext());
|
||||
|
||||
}
|
||||
|
||||
[TestCase(typeof(TradeBar))]
|
||||
[TestCase(typeof(QuoteBar))]
|
||||
[TestCase(typeof(OpenInterest))]
|
||||
public void EmitsNewTradableDateWhenDateAfterDelistingIsNonTradable(Type dataType)
|
||||
{
|
||||
var start = new DateTime(2023, 06, 30);
|
||||
var end = new DateTime(2023, 08, 01);
|
||||
|
||||
var request = GetRequest(dataType, start, end, Resolution.Minute, out var config);
|
||||
using var testDataCacheProvider = new TestDataCacheProvider();
|
||||
using var dataReader = new SubscriptionDataReader(config,
|
||||
request,
|
||||
TestGlobals.MapFileProvider,
|
||||
TestGlobals.FactorFileProvider,
|
||||
testDataCacheProvider,
|
||||
TestGlobals.DataProvider,
|
||||
null);
|
||||
|
||||
var expectedLastTradableDate = new DateTime(2023, 07, 05);
|
||||
var lastTradableDate = default(DateTime);
|
||||
|
||||
dataReader.NewTradableDate += (sender, args) =>
|
||||
{
|
||||
lastTradableDate = args.Date;
|
||||
};
|
||||
|
||||
while (dataReader.MoveNext())
|
||||
{
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedLastTradableDate, lastTradableDate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotYieldDataWhenDelisted()
|
||||
{
|
||||
var start = new DateTime(2023, 8, 1);
|
||||
var end = new DateTime(2023, 08, 10);
|
||||
|
||||
var request = GetRequest(typeof(TradeBar), start, end, Resolution.Minute, out var config);
|
||||
using var testDataCacheProvider = new TestDataCacheProvider();
|
||||
using var dataReader = new SubscriptionDataReader(config,
|
||||
request,
|
||||
TestGlobals.MapFileProvider,
|
||||
TestGlobals.FactorFileProvider,
|
||||
testDataCacheProvider,
|
||||
TestGlobals.DataProvider,
|
||||
null);
|
||||
|
||||
var dataYielded = false;
|
||||
var newTradableDateCalled = false;
|
||||
dataReader.NewTradableDate += (sender, args) =>
|
||||
{
|
||||
newTradableDateCalled = true;
|
||||
};
|
||||
|
||||
while (dataReader.MoveNext())
|
||||
{
|
||||
dataYielded = true;
|
||||
}
|
||||
|
||||
Assert.IsFalse(dataYielded);
|
||||
Assert.IsFalse(newTradableDateCalled);
|
||||
}
|
||||
|
||||
private static BaseDataRequest GetRequest(Type dataType, DateTime start, DateTime end, Resolution resolution, out SubscriptionDataConfig config)
|
||||
{
|
||||
var symbol = Symbol.CreateOption(
|
||||
Symbols.SPX,
|
||||
"SPXW",
|
||||
Market.USA,
|
||||
OptionStyle.European,
|
||||
OptionRight.Call,
|
||||
4445m,
|
||||
// Next day is a holiday
|
||||
new DateTime(2023, 7, 3));
|
||||
|
||||
var entry = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
config = new SubscriptionDataConfig(dataType,
|
||||
symbol,
|
||||
resolution,
|
||||
entry.DataTimeZone,
|
||||
entry.ExchangeHours.TimeZone,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
return new HistoryRequest(config, entry.ExchangeHours, start, end);
|
||||
}
|
||||
|
||||
private class TestDataCacheProvider : IDataCacheProvider
|
||||
{
|
||||
private StreamWriter _writer;
|
||||
private bool _alreadyEmitted;
|
||||
|
||||
public string Data { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
_writer.DisposeSafely();
|
||||
}
|
||||
public List<string> GetZipEntries(string zipFile)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public bool IsDataEphemeral => true;
|
||||
public Stream Fetch(string key)
|
||||
{
|
||||
if (_alreadyEmitted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
_alreadyEmitted = true;
|
||||
|
||||
var stream = new MemoryStream();
|
||||
_writer = new StreamWriter(stream);
|
||||
_writer.Write(Data);
|
||||
_writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
public void Store(string key, byte[] data)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user