Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Common/Data/UniverseSelection/Universe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ public virtual bool Asynchronous
/// </summary>
public Symbol Symbol => Configuration.Symbol;

/// <summary>
/// Gets the order in which this universe was added to the algorithm.
/// </summary>
public int SelectionOrder
{
get; internal set;
}

/// <summary>
/// Gets the data type of this universe
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions Common/Securities/UniverseManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace QuantConnect.Securities
public class UniverseManager : BaseExtendedDictionary<Symbol, Universe, ConcurrentDictionary<Symbol, Universe>>
{
private readonly Queue<UniverseManagerChanged> _pendingChanges = new();
private int _nextSelectionOrder;

/// <summary>
/// Event fired when a universe is added or removed
Expand Down Expand Up @@ -60,6 +61,7 @@ public override void Add(Symbol key, Universe value)
{
if (Dictionary.TryAdd(key, value))
{
value.SelectionOrder = _nextSelectionOrder++;
lock (_pendingChanges)
{
_pendingChanges.Enqueue(new UniverseManagerChanged(NotifyCollectionChangedAction.Add, value));
Expand Down
8 changes: 5 additions & 3 deletions Engine/DataFeeds/SubscriptionSynchronizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,11 @@ public IEnumerable<TimeSlice> Sync(IEnumerable<Subscription> subscriptions,
// time pulse to align algorithm time with current frontier
yield return _timeSliceFactory.CreateTimePulse(frontierUtc);

// trigger the smalled resolution first, so that FF res get's set once from the start correctly
// while at it, let's make it determininstic and sort by universe sid later
foreach (var kvp in universeData.OrderBy(x => x.Key.Configuration.Resolution).ThenBy(x => x.Key.Symbol.ID))
// trigger the smallest resolution first, so that FF res gets set once from the start correctly.
// For universes at the same resolution, preserve the order they were added to the algorithm.
foreach (var kvp in universeData.OrderBy(x => x.Key.Configuration.Resolution)
.ThenBy(x => x.Key.SelectionOrder)
.ThenBy(x => x.Key.Symbol.ID))
{
var universe = kvp.Key;
var baseDataCollection = kvp.Value;
Expand Down
25 changes: 25 additions & 0 deletions Tests/Common/Securities/UniverseManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,34 @@ public void NotifiesWhenSecurityRemoved()
manager.Remove(universe.Configuration.Symbol);
}

[Test]
public void AssignsSelectionOrderWhenUniverseAdded()
{
var manager = new UniverseManager();
var first = CreateUniverse(Symbols.SPY);
var second = CreateUniverse(Symbols.AAPL);
var third = CreateUniverse(Symbols.IBM);

manager.Add(first.Configuration.Symbol, first);
manager[second.Configuration.Symbol] = second;
manager.Add(third.Configuration.Symbol, third);

Assert.AreEqual(0, first.SelectionOrder);
Assert.AreEqual(1, second.SelectionOrder);
Assert.AreEqual(2, third.SelectionOrder);
}

private SubscriptionDataConfig CreateTradeBarConfig()
{
return new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, false, false, true);
}

private Universe CreateUniverse(Symbol symbol)
{
return new FuncUniverse(
new SubscriptionDataConfig(typeof(TradeBar), symbol, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, false, false, true),
new UniverseSettings(Resolution.Minute, 2, true, false, TimeSpan.Zero),
data => data.Select(x => x.Symbol));
}
}
}