chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NodaTime;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Lean.Engine.DataFeeds.Enumerators;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Equity;
|
||||
using QuantConnect.Securities.Future;
|
||||
using QuantConnect.Securities.Option;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
{
|
||||
[TestFixture, Parallelizable(ParallelScope.All)]
|
||||
public class SubscriptionCollectionTests
|
||||
{
|
||||
[Test]
|
||||
public void EnumerationWhileUpdatingDoesNotThrow()
|
||||
{
|
||||
using var cts = new CancellationTokenSource();
|
||||
var subscriptions = new SubscriptionCollection();
|
||||
var start = DateTime.UtcNow;
|
||||
var end = start.AddSeconds(10);
|
||||
var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, DateTimeZone.Utc, DateTimeZone.Utc, true, false, false);
|
||||
var security = new Equity(
|
||||
Symbols.SPY,
|
||||
SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
|
||||
new Cash(Currencies.USD, 0, 1),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
var timeZoneOffsetProvider = new TimeZoneOffsetProvider(DateTimeZone.Utc, start, end);
|
||||
using var enumerator = new EnqueueableEnumerator<BaseData>();
|
||||
using var subscriptionDataEnumerator = new SubscriptionDataEnumerator(config, security.Exchange.Hours, timeZoneOffsetProvider, enumerator, false, false);
|
||||
var subscriptionRequest = new SubscriptionRequest(false, null, security, config, start, end);
|
||||
var subscription = new Subscription(subscriptionRequest, subscriptionDataEnumerator, timeZoneOffsetProvider);
|
||||
|
||||
var addTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
Log.Trace("Add task started");
|
||||
|
||||
while (DateTime.UtcNow < end)
|
||||
{
|
||||
if (!subscriptions.Contains(config))
|
||||
{
|
||||
subscriptions.TryAdd(subscription);
|
||||
}
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
Log.Trace("Add task ended");
|
||||
}, cts.Token);
|
||||
|
||||
var removeTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
Log.Trace("Remove task started");
|
||||
|
||||
while (DateTime.UtcNow < end)
|
||||
{
|
||||
Subscription removed;
|
||||
subscriptions.TryRemove(config, out removed);
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
Log.Trace("Remove task ended");
|
||||
}, cts.Token);
|
||||
|
||||
var readTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
Log.Trace("Read task started");
|
||||
|
||||
while (DateTime.UtcNow < end)
|
||||
{
|
||||
foreach (var sub in subscriptions) { }
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
Log.Trace("Read task ended");
|
||||
}, cts.Token);
|
||||
|
||||
Task.WaitAll(addTask, removeTask, readTask);
|
||||
subscription.Dispose();
|
||||
}
|
||||
[Test]
|
||||
public void DefaultFillForwardResolution()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var defaultFillForwardResolutio = subscriptionColletion.UpdateAndGetFillForwardResolution();
|
||||
Assert.AreEqual(defaultFillForwardResolutio.Value, new TimeSpan(0, 1, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdatesFillForwardResolutionOverridesDefaultWhenNotAdding()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Daily);
|
||||
|
||||
var fillForwardResolutio = subscriptionColletion.UpdateAndGetFillForwardResolution(subscription.Configuration);
|
||||
Assert.AreEqual(fillForwardResolutio.Value, new TimeSpan(1, 0, 0, 0));
|
||||
subscription.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdatesFillForwardResolutionSuccessfullyWhenNotAdding()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Second);
|
||||
|
||||
var fillForwardResolutio = subscriptionColletion.UpdateAndGetFillForwardResolution(subscription.Configuration);
|
||||
Assert.AreEqual(fillForwardResolutio.Value, new TimeSpan(0, 0, 1));
|
||||
subscription.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdatesFillForwardResolutionSuccessfullyWhenAdding()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
using var subscription = CreateSubscription(Resolution.Second);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdatesFillForwardResolutionSuccessfullyOverridesDefaultWhenAdding()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Daily);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(1, 0, 0, 0));
|
||||
subscription.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotUpdateFillForwardResolutionWhenAddingBiggerResolution()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Second);
|
||||
var subscription2 = CreateSubscription(Resolution.Minute);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscription.Dispose();
|
||||
subscription2.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdatesFillForwardResolutionWhenRemoving()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
using var subscription = CreateSubscription(Resolution.Second);
|
||||
using var subscription2 = CreateSubscription(Resolution.Daily);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscriptionColletion.TryRemove(subscription.Configuration, out var outSubscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(1, 0, 0, 0));
|
||||
subscriptionColletion.TryRemove(subscription2.Configuration, out var outSubscription2);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
outSubscription.Dispose();
|
||||
outSubscription2.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FillForwardResolutionIgnoresTick()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
using var subscription = CreateSubscription(Resolution.Tick);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
subscriptionColletion.TryRemove(subscription.Configuration, out var outSubscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
outSubscription.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FillForwardResolutionIgnoresInternalFeed()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
using var subscription = CreateSubscription(Resolution.Second, "AAPL", true);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
subscriptionColletion.TryRemove(subscription.Configuration, out var outSubscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
outSubscription.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotUpdateFillForwardResolutionWhenRemovingDuplicateResolution()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
using var subscription = CreateSubscription(Resolution.Second);
|
||||
using var subscription2 = CreateSubscription(Resolution.Second, "SPY");
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscriptionColletion.TryRemove(subscription.Configuration, out var outSubscription);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 0, 1));
|
||||
subscriptionColletion.TryRemove(subscription2.Configuration, out var outSubscription2);
|
||||
Assert.AreEqual(subscriptionColletion.UpdateAndGetFillForwardResolution().Value, new TimeSpan(0, 1, 0));
|
||||
outSubscription.Dispose();
|
||||
outSubscription2.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscriptionsAreSortedWhenAdding()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Second, Futures.Metals.Gold, false, SecurityType.Future);
|
||||
var subscription2 = CreateSubscription(Resolution.Second, "SPY");
|
||||
var subscription3 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option);
|
||||
var subscription4 = CreateSubscription(Resolution.Second, "EURGBP");
|
||||
var subscription5 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option, TickType.OpenInterest);
|
||||
var subscription6 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option, TickType.Quote);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription });
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription2, subscription });
|
||||
subscriptionColletion.TryAdd(subscription3);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription2, subscription3, subscription });
|
||||
subscriptionColletion.TryAdd(subscription4);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription2, subscription3, subscription });
|
||||
subscriptionColletion.TryAdd(subscription5);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription2, subscription3, subscription5, subscription });
|
||||
subscriptionColletion.TryAdd(subscription6);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription2, subscription3, subscription6, subscription5, subscription });
|
||||
|
||||
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Equity, SecurityType.Option,
|
||||
SecurityType.Option, SecurityType.Option, SecurityType.Future });
|
||||
|
||||
subscription.Dispose();
|
||||
subscription2.Dispose();
|
||||
subscription3.Dispose();
|
||||
subscription4.Dispose();
|
||||
subscription5.Dispose();
|
||||
subscription6.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscriptionsAreSortedWhenAdding2()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Second, Futures.Metals.Gold, false, SecurityType.Future);
|
||||
var subscription2 = CreateSubscription(Resolution.Second, "SPY");
|
||||
var subscription3 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option);
|
||||
var subscription4 = CreateSubscription(Resolution.Second, "EURGBP");
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription });
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription2, subscription });
|
||||
subscriptionColletion.TryAdd(subscription3);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription2, subscription3, subscription });
|
||||
subscriptionColletion.TryAdd(subscription4);
|
||||
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription2, subscription3, subscription });
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Equity, SecurityType.Option, SecurityType.Future });
|
||||
|
||||
subscription.Dispose();
|
||||
subscription2.Dispose();
|
||||
subscription3.Dispose();
|
||||
subscription4.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscriptionsAreSortedWhenRemoving()
|
||||
{
|
||||
var subscriptionColletion = new SubscriptionCollection();
|
||||
var subscription = CreateSubscription(Resolution.Second, Futures.Metals.Gold, false, SecurityType.Future);
|
||||
var subscription2 = CreateSubscription(Resolution.Second, "SPY");
|
||||
var subscription3 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option);
|
||||
var subscription4 = CreateSubscription(Resolution.Second, "EURGBP");
|
||||
var subscription5 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option, TickType.OpenInterest);
|
||||
var subscription6 = CreateSubscription(Resolution.Second, "AAPL", false, SecurityType.Option, TickType.Quote);
|
||||
|
||||
subscriptionColletion.TryAdd(subscription);
|
||||
subscriptionColletion.TryAdd(subscription2);
|
||||
subscriptionColletion.TryAdd(subscription3);
|
||||
subscriptionColletion.TryAdd(subscription4);
|
||||
subscriptionColletion.TryAdd(subscription5);
|
||||
subscriptionColletion.TryAdd(subscription6);
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription2, subscription3, subscription6, subscription5, subscription });
|
||||
|
||||
subscriptionColletion.TryRemove(subscription2.Configuration, out subscription2);
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Option,
|
||||
SecurityType.Option, SecurityType.Option, SecurityType.Future });
|
||||
|
||||
subscriptionColletion.TryRemove(subscription3.Configuration, out subscription3);
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Option, SecurityType.Option, SecurityType.Future });
|
||||
|
||||
subscriptionColletion.TryRemove(subscription.Configuration, out subscription);
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Option, SecurityType.Option });
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription6, subscription5 });
|
||||
|
||||
subscriptionColletion.TryRemove(subscription6.Configuration, out subscription6);
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] { SecurityType.Equity, SecurityType.Option });
|
||||
Assert.AreEqual(subscriptionColletion.ToList(), new[] { subscription4, subscription5 });
|
||||
|
||||
subscriptionColletion.TryRemove(subscription5.Configuration, out subscription5);
|
||||
Assert.AreEqual(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList(), new[] {SecurityType.Equity});
|
||||
|
||||
subscriptionColletion.TryRemove(subscription4.Configuration, out subscription4);
|
||||
Assert.IsTrue(subscriptionColletion.Select(x => x.Configuration.SecurityType).ToList().IsNullOrEmpty());
|
||||
|
||||
subscription.Dispose();
|
||||
subscription2.Dispose();
|
||||
subscription3.Dispose();
|
||||
subscription4.Dispose();
|
||||
subscription5.Dispose();
|
||||
subscription6.Dispose();
|
||||
}
|
||||
|
||||
private Subscription CreateSubscription(Resolution resolution, string symbol = "AAPL", bool isInternalFeed = false,
|
||||
SecurityType type = SecurityType.Equity, TickType tickType = TickType.Trade)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
var end = start.AddSeconds(10);
|
||||
Security security;
|
||||
Symbol _symbol;
|
||||
if (type == SecurityType.Equity)
|
||||
{
|
||||
_symbol = new Symbol(SecurityIdentifier.GenerateEquity(DateTime.Now, symbol, Market.USA), symbol);
|
||||
security = new Equity(
|
||||
_symbol,
|
||||
SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
|
||||
new Cash(Currencies.USD, 0, 1),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
}
|
||||
else if (type == SecurityType.Option)
|
||||
{
|
||||
_symbol = Symbol.CreateOption(
|
||||
new Symbol(SecurityIdentifier.GenerateEquity(DateTime.Now, symbol, Market.USA), symbol),
|
||||
Market.USA,
|
||||
OptionStyle.American,
|
||||
OptionRight.Call,
|
||||
0m,
|
||||
DateTime.Now
|
||||
);
|
||||
security = new Option(
|
||||
_symbol,
|
||||
SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
|
||||
new Cash(Currencies.USD, 0, 1),
|
||||
new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache(),
|
||||
null
|
||||
);
|
||||
}
|
||||
else if (type == SecurityType.Future)
|
||||
{
|
||||
_symbol = new Symbol(SecurityIdentifier.GenerateFuture(DateTime.Now, symbol, Market.COMEX), symbol);
|
||||
security = new Future(
|
||||
_symbol,
|
||||
SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
|
||||
new Cash(Currencies.USD, 0, 1),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RegressionTestException("SecurityType not implemented");
|
||||
}
|
||||
var config = new SubscriptionDataConfig(typeof(TradeBar), _symbol, resolution, DateTimeZone.Utc, DateTimeZone.Utc, true, false, isInternalFeed, false, tickType);
|
||||
var timeZoneOffsetProvider = new TimeZoneOffsetProvider(DateTimeZone.Utc, start, end);
|
||||
# pragma warning disable CA2000
|
||||
var enumerator = new EnqueueableEnumerator<BaseData>();
|
||||
var subscriptionDataEnumerator = new SubscriptionDataEnumerator(config, security.Exchange.Hours, timeZoneOffsetProvider, enumerator, false, false);
|
||||
# pragma warning restore CA2000
|
||||
var subscriptionRequest = new SubscriptionRequest(false, null, security, config, start, end);
|
||||
return new Subscription(subscriptionRequest, subscriptionDataEnumerator, timeZoneOffsetProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user