190 lines
7.1 KiB
C#
190 lines
7.1 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 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)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|