chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Custom.IconicTypes;
|
||||
using QuantConnect.Data.Auxiliary;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Tests.Common.Data.UniverseSelection;
|
||||
using QuantConnect.Securities.Option;
|
||||
using QuantConnect.Securities.Future;
|
||||
using QuantConnect.Securities.Equity;
|
||||
|
||||
namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
{
|
||||
[TestFixture]
|
||||
public class TimeSliceTests
|
||||
{
|
||||
private TimeSliceFactory _timeSliceFactory;
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_timeSliceFactory = new TimeSliceFactory(TimeZones.Utc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HandlesTicks_ExpectInOrderWithNoDuplicates()
|
||||
{
|
||||
var subscriptionDataConfig = new SubscriptionDataConfig(
|
||||
typeof(Tick),
|
||||
Symbols.EURUSD,
|
||||
Resolution.Tick,
|
||||
TimeZones.Utc,
|
||||
TimeZones.Utc,
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
|
||||
var security = new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
subscriptionDataConfig,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
|
||||
DateTime refTime = DateTime.UtcNow;
|
||||
|
||||
Tick[] rawTicks = Enumerable
|
||||
.Range(0, 10)
|
||||
.Select(i => new Tick(refTime.AddSeconds(i), Symbols.EURUSD, 1.3465m, 1.34652m))
|
||||
.ToArray();
|
||||
|
||||
IEnumerable<TimeSlice> timeSlices = rawTicks.Select(t => _timeSliceFactory.Create(
|
||||
t.Time,
|
||||
new List<DataFeedPacket> { new DataFeedPacket(security, subscriptionDataConfig, new List<BaseData>() { t }) },
|
||||
SecurityChangesTests.CreateNonInternal(Enumerable.Empty<Security>(), Enumerable.Empty<Security>()),
|
||||
new Dictionary<Universe, BaseDataCollection>()));
|
||||
|
||||
Tick[] timeSliceTicks = timeSlices.SelectMany(ts => ts.Slice.Ticks.Values.SelectMany(x => x)).ToArray();
|
||||
|
||||
Assert.AreEqual(rawTicks.Length, timeSliceTicks.Length);
|
||||
for (int i = 0; i < rawTicks.Length; i++)
|
||||
{
|
||||
Assert.IsTrue(Compare(rawTicks[i], timeSliceTicks[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private bool Compare(Tick expected, Tick actual)
|
||||
{
|
||||
return expected.Time == actual.Time
|
||||
&& expected.BidPrice == actual.BidPrice
|
||||
&& expected.AskPrice == actual.AskPrice
|
||||
&& expected.Quantity == actual.Quantity;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HandlesMultipleCustomDataOfSameTypeWithDifferentSymbols()
|
||||
{
|
||||
var symbol1 = Symbol.Create("SCF/CBOE_VX1_EW", SecurityType.Base, Market.USA);
|
||||
var symbol2 = Symbol.Create("SCF/CBOE_VX2_EW", SecurityType.Base, Market.USA);
|
||||
|
||||
var subscriptionDataConfig1 = new SubscriptionDataConfig(
|
||||
typeof(UnlinkedData), symbol1, Resolution.Daily, TimeZones.Utc, TimeZones.Utc, true, true, false, isCustom: true);
|
||||
var subscriptionDataConfig2 = new SubscriptionDataConfig(
|
||||
typeof(UnlinkedData), symbol2, Resolution.Daily, TimeZones.Utc, TimeZones.Utc, true, true, false, isCustom: true);
|
||||
|
||||
var security1 = new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
subscriptionDataConfig1,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
|
||||
var security2 = new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
subscriptionDataConfig1,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
|
||||
var timeSlice = _timeSliceFactory.Create(DateTime.UtcNow,
|
||||
new List<DataFeedPacket>
|
||||
{
|
||||
new DataFeedPacket(security1, subscriptionDataConfig1, new List<BaseData> {new UnlinkedData { Symbol = symbol1, Time = DateTime.UtcNow.Date, Value = 15 } }),
|
||||
new DataFeedPacket(security2, subscriptionDataConfig2, new List<BaseData> {new UnlinkedData { Symbol = symbol2, Time = DateTime.UtcNow.Date, Value = 20 } }),
|
||||
},
|
||||
SecurityChangesTests.CreateNonInternal(Enumerable.Empty<Security>(), Enumerable.Empty<Security>()),
|
||||
new Dictionary<Universe, BaseDataCollection>());
|
||||
|
||||
Assert.AreEqual(2, timeSlice.CustomData.Count);
|
||||
|
||||
var data1 = timeSlice.CustomData[0].Data[0];
|
||||
var data2 = timeSlice.CustomData[1].Data[0];
|
||||
|
||||
Assert.IsInstanceOf(typeof(UnlinkedData), data1);
|
||||
Assert.IsInstanceOf(typeof(UnlinkedData), data2);
|
||||
Assert.AreEqual(symbol1, data1.Symbol);
|
||||
Assert.AreEqual(symbol2, data2.Symbol);
|
||||
Assert.AreEqual(15, data1.Value);
|
||||
Assert.AreEqual(20, data2.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FutureDataHasVolume()
|
||||
{
|
||||
var initialVolume = 100;
|
||||
var slices = GetSlices(Symbols.Fut_SPY_Mar19_2016, initialVolume).ToArray();
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var chain = slices[i].FutureChains.FirstOrDefault().Value;
|
||||
var contract = chain.FirstOrDefault();
|
||||
var expected = (i + 1) * initialVolume;
|
||||
Assert.AreEqual(expected, contract.Volume);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OptionsDataHasVolume()
|
||||
{
|
||||
var initialVolume = 150;
|
||||
var slices = GetSlices(Symbols.SPY_C_192_Feb19_2016, initialVolume).ToArray();
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var chain = slices[i].OptionChains.FirstOrDefault().Value;
|
||||
var contract = chain.FirstOrDefault();
|
||||
var expected = (i + 1) * initialVolume;
|
||||
Assert.AreEqual(expected, contract.Volume);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SuspiciousTicksAreNotAddedToConsolidatorUpdateData()
|
||||
{
|
||||
var symbol = Symbols.SPY;
|
||||
|
||||
var subscriptionDataConfig = new SubscriptionDataConfig(
|
||||
typeof(Tick), symbol, Resolution.Tick, TimeZones.Utc, TimeZones.Utc, true, true, false);
|
||||
|
||||
var security = new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
subscriptionDataConfig,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
|
||||
var timeSlice = _timeSliceFactory.Create(DateTime.UtcNow,
|
||||
new List<DataFeedPacket>
|
||||
{
|
||||
new DataFeedPacket(security, subscriptionDataConfig, new List<BaseData>
|
||||
{
|
||||
new Tick(DateTime.UtcNow, symbol, 280, 0, 0),
|
||||
new Tick(DateTime.UtcNow, symbol, 500, 0, 0) { Suspicious = true },
|
||||
new Tick(DateTime.UtcNow, symbol, 281, 0, 0)
|
||||
})
|
||||
},
|
||||
SecurityChangesTests.CreateNonInternal(Enumerable.Empty<Security>(), Enumerable.Empty<Security>()),
|
||||
new Dictionary<Universe, BaseDataCollection>());
|
||||
|
||||
Assert.AreEqual(1, timeSlice.ConsolidatorUpdateData.Count);
|
||||
|
||||
var data = timeSlice.ConsolidatorUpdateData[0].Data;
|
||||
Assert.AreEqual(2, data.Count);
|
||||
Assert.AreEqual(280, data[0].Value);
|
||||
Assert.AreEqual(281, data[1].Value);
|
||||
}
|
||||
|
||||
private IEnumerable<Slice> GetSlices(Symbol symbol, int initialVolume)
|
||||
{
|
||||
var dataType = symbol.SecurityType.IsOption() ? typeof(OptionUniverse) : typeof(FutureUniverse);
|
||||
var subscriptionDataConfig = new SubscriptionDataConfig(dataType, symbol, Resolution.Second, TimeZones.Utc, TimeZones.Utc, true, true, false);
|
||||
var security = GetSecurity(subscriptionDataConfig);
|
||||
var refTime = DateTime.UtcNow;
|
||||
|
||||
return Enumerable
|
||||
.Range(0, 10)
|
||||
.Select(i =>
|
||||
{
|
||||
var time = refTime.AddSeconds(i);
|
||||
var bid = new Bar(100, 100, 100, 100);
|
||||
var ask = new Bar(110, 110, 110, 110);
|
||||
var volume = (i + 1) * initialVolume;
|
||||
|
||||
var packets = new List<DataFeedPacket>();
|
||||
var packet = new DataFeedPacket(security, subscriptionDataConfig, new List<BaseData>
|
||||
{
|
||||
new QuoteBar(time, symbol, bid, i*10, ask, (i + 1) * 11),
|
||||
new TradeBar(time, symbol, 100, 100, 110, 106, volume)
|
||||
});
|
||||
|
||||
if (symbol.SecurityType == SecurityType.Option)
|
||||
{
|
||||
var underlying = (security as Option).Underlying;
|
||||
packets.Add(new DataFeedPacket(underlying, underlying.SubscriptionDataConfig, new List<BaseData>
|
||||
{
|
||||
new QuoteBar(time, underlying.Symbol, bid, i*10, ask, (i + 1) * 11),
|
||||
new TradeBar(time, underlying.Symbol, 100, 100, 110, 106, volume)
|
||||
}));
|
||||
}
|
||||
|
||||
packets.Add(packet);
|
||||
|
||||
return _timeSliceFactory.Create(
|
||||
time,
|
||||
packets,
|
||||
SecurityChangesTests.CreateNonInternal(Enumerable.Empty<Security>(), Enumerable.Empty<Security>()),
|
||||
new Dictionary<Universe, BaseDataCollection>())
|
||||
.Slice;
|
||||
});
|
||||
}
|
||||
|
||||
private Security GetSecurity(SubscriptionDataConfig config)
|
||||
{
|
||||
if (config.Symbol.SecurityType == SecurityType.Option)
|
||||
{
|
||||
var option = new Option(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
config,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null);
|
||||
var underlyingConfig = new SubscriptionDataConfig(typeof(TradeBar), config.Symbol.Underlying, Resolution.Second,
|
||||
TimeZones.Utc, TimeZones.Utc, true, true, false);
|
||||
var equity = new Equity(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
underlyingConfig,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null);
|
||||
option.Underlying = equity;
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
if (config.Symbol.SecurityType == SecurityType.Future)
|
||||
{
|
||||
return new Future(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
config,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null);
|
||||
}
|
||||
|
||||
return new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Utc),
|
||||
config,
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user