Skip to content

Commit 265e9a5

Browse files
committed
More changes to clean up and simplify
1 parent e6335b1 commit 265e9a5

10 files changed

Lines changed: 65 additions & 47 deletions

Algorithm.CSharp/SecurityInitializationOnReAdditionForEquityRegressionAlgorithm.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class SecurityInitializationOnReAdditionForEquityRegressionAlgorithm : QC
3232
private Security _equity;
3333
private Queue<DateTime> _tradableDates;
3434
private bool _securityWasRemoved;
35-
private bool _securityWasInitialized;
35+
private int _securityInitializationCount;
3636

3737
public override void Initialize()
3838
{
@@ -44,7 +44,7 @@ public override void Initialize()
4444
if ((_equity != null && ReferenceEquals(security, _equity)) ||
4545
(_equity == null && security.Symbol == _symbol))
4646
{
47-
_securityWasInitialized = true;
47+
_securityInitializationCount++;
4848
}
4949

5050
Debug($"[{Time}] Seeding {security.Symbol}");
@@ -69,6 +69,13 @@ public override void Initialize()
6969
return;
7070
}
7171

72+
// Before we remove the security let's check that it was not initialized again
73+
if (_securityInitializationCount != 1)
74+
{
75+
throw new RegressionTestException($"Expected the equity to be initialized once and once only, " +
76+
$"but was initialized {_securityInitializationCount} times");
77+
}
78+
7279
// Remove the security every day
7380
Debug($"[{Time}] Removing the equity");
7481
_securityWasRemoved = RemoveSecurity(_equity.Symbol);
@@ -82,12 +89,13 @@ public override void Initialize()
8289

8390
private Equity AddEquity()
8491
{
85-
_securityWasInitialized = false;
92+
_securityInitializationCount = 0;
8693
var equity = AddEquity("SPY");
8794

88-
if (!_securityWasInitialized)
95+
if (_securityInitializationCount != 1)
8996
{
90-
throw new RegressionTestException("Expected the equity to be initialized");
97+
throw new RegressionTestException($"Expected the equity to be initialized once and once only, " +
98+
$"but was initialized {_securityInitializationCount} times");
9199
}
92100

93101
return equity;

Algorithm.CSharp/SecurityInitializationOnReAdditionForManuallyAddedOptionRegressionAlgorithm.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class SecurityInitializationOnReAdditionForManuallyAddedOptionRegressionA
3939

4040
private bool _securityWasRemoved;
4141

42-
private bool _securityWasInitialized;
42+
private int _securityInitializationCount;
4343

4444
private Queue<DateTime> _tradableDates;
4545

@@ -54,7 +54,7 @@ public override void Initialize()
5454
if ((_manuallyAddedContract != null && ReferenceEquals(security, _manuallyAddedContract)) ||
5555
(_manuallyAddedContract == null && security.Symbol == _optionContractSymbol))
5656
{
57-
_securityWasInitialized = true;
57+
_securityInitializationCount++;
5858
}
5959

6060
Debug($"[{Time}] Seeding {security.Symbol}");
@@ -80,6 +80,13 @@ public override void Initialize()
8080
return;
8181
}
8282

83+
// Before we remove the security let's check that it was not initialized again
84+
if (_securityInitializationCount != 1)
85+
{
86+
throw new RegressionTestException($"Expected the option to be initialized once and once only, " +
87+
$"but was initialized {_securityInitializationCount} times");
88+
}
89+
8390
// Remove the security every day
8491
Debug($"[{Time}] Removing the equity");
8592
_securityWasRemoved = RemoveSecurity(_manuallyAddedContract.Symbol);
@@ -93,12 +100,13 @@ public override void Initialize()
93100

94101
public Option AddOptionContract()
95102
{
96-
_securityWasInitialized = false;
103+
_securityInitializationCount = 0;
97104
var option = AddOptionContract(_optionContractSymbol, Resolution.Daily);
98105

99-
if (!_securityWasInitialized)
106+
if (_securityInitializationCount != 1)
100107
{
101-
throw new RegressionTestException($"Expected the option contract to be initialized. Symbol: {option.Symbol}");
108+
throw new RegressionTestException($"Expected the option to be initialized once and once only, " +
109+
$"but was initialized {_securityInitializationCount} times");
102110
}
103111

104112
return option;

Algorithm.CSharp/SecurityInitializationOnReAdditionForSelectedOptionRegressionAlgorithm.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class SecurityInitializationOnReAdditionForSelectedOptionRegressionAlgori
2929
{
3030
private List<Symbol> _contractsToSelect;
3131
private HashSet<Option> _selectedContracts = new();
32-
private List<Security> _initializedContracts = new();
32+
private Dictionary<Security, int> _initializedContracts = new();
3333

3434
private bool _selectSingle;
3535
private int _selectionsCount;
@@ -44,7 +44,11 @@ public override void Initialize()
4444
{
4545
if (security is Option option)
4646
{
47-
_initializedContracts.Add(option);
47+
if (!_initializedContracts.TryGetValue(security, out var count))
48+
{
49+
count = 0;
50+
}
51+
_initializedContracts[security] = count + 1;
4852
}
4953

5054
Debug($"[{Time}] Seeding {security.Symbol}");
@@ -104,9 +108,9 @@ public override void OnSecuritiesChanged(SecurityChanges changes)
104108
}
105109

106110
var addedContracts = changes.AddedSecurities.OfType<Option>().ToList();
107-
if (addedContracts.Any(x => !_initializedContracts.Contains(x)))
111+
if (addedContracts.Any(x => !_initializedContracts.TryGetValue(x, out var count) || count != 1))
108112
{
109-
throw new RegressionTestException($"Expected all contracts to be initialized. Added: {string.Join(", ", addedContracts.Select(x => x.Symbol.Value))}, Initialized: {string.Join(", ", _initializedContracts.Select(x => x.Symbol.Value))}");
113+
throw new RegressionTestException($"Expected all contracts to be initialized. Added: {string.Join(", ", addedContracts.Select(x => x.Symbol.Value))}, Initialized: {string.Join(", ", _initializedContracts.Select(x => $"{x.Key.Symbol.Value} - {x.Value}"))}");
110114
}
111115

112116
// The first contract will be selected always, so we expect it to be added only once

Algorithm/QCAlgorithm.Universe.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,6 @@ private Security AddToUserDefinedUniverse(
589589
Securities.Remove(security.Symbol);
590590
Securities.Add(security);
591591
}
592-
else
593-
{
594-
security.MakeTradable();
595-
}
596592
}
597593
else
598594
{

Algorithm/QCAlgorithm.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ public Security AddSecurity(Symbol symbol, Resolution? resolution = null, bool f
19771977

19781978
if (isCanonical)
19791979
{
1980-
security.MakeNonTradable();
1980+
security.IsTradable = false;
19811981
Securities.Add(security);
19821982

19831983
// add this security to the user defined universe
@@ -2503,7 +2503,7 @@ public bool RemoveSecurity(Symbol symbol)
25032503
}
25042504

25052505
// Mark security as not tradable
2506-
security.MakeNonTradable();
2506+
security.Reset();
25072507
if (symbol.IsCanonical())
25082508
{
25092509
// remove underlying equity data if it's marked as internal

Common/Extensions.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3920,20 +3920,6 @@ public static void MakeTradable(this Security security)
39203920
}
39213921
}
39223922

3923-
/// <summary>
3924-
/// Helper method to set the <see cref="Security.IsTradable"/> property to <code>false</code>
3925-
/// when a security is being removed from the algorithm or delisted
3926-
/// </summary>
3927-
/// <param name="security"></param>
3928-
public static void MakeNonTradable(this Security security)
3929-
{
3930-
if (security is Securities.Index.Index index)
3931-
{
3932-
index.ManualSetIsTradable = false;
3933-
}
3934-
security.IsTradable = false;
3935-
}
3936-
39373923
/// <summary>
39383924
/// Helper method to set an algorithm runtime exception in a normalized fashion
39393925
/// </summary>

Common/Securities/Index/Index.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,15 @@ public Index(Symbol symbol,
124124
IsTradable = false; //Index are non tradable by default
125125
Holdings = new IndexHolding(this, currencyConverter);
126126
}
127+
128+
/// <summary>
129+
/// Resets the security to its initial state by marking it as uninitialized and non-tradable
130+
/// and clearing the subscriptions.
131+
/// </summary>
132+
public override void Reset()
133+
{
134+
base.Reset();
135+
ManualSetIsTradable = false;
136+
}
127137
}
128138
}

Common/Securities/Security.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class Security : DynamicObject, ISecurityPrice
5252
/// Uses concurrent bag to avoid list enumeration threading issues
5353
/// </summary>
5454
/// <remarks>Just use a list + lock, not concurrent bag, avoid garbage it creates for features we don't need here. See https://github.com/dotnet/runtime/issues/23103</remarks>
55-
private readonly List<SubscriptionDataConfig> _subscriptionsBag;
55+
private readonly HashSet<SubscriptionDataConfig> _subscriptionsBag;
5656

5757
/// <summary>
5858
/// Flag to keep track of initialized securities, to avoid double initialization.
@@ -1073,7 +1073,7 @@ internal void AddData(SubscriptionDataConfig subscription)
10731073
{
10741074
throw new ArgumentException(Messages.Security.UnmatchingExchangeTimeZones, $"{nameof(subscription)}.{nameof(subscription.ExchangeTimeZone)}");
10751075
}
1076-
AddSubscription(subscription);
1076+
_subscriptionsBag.Add(subscription);
10771077
UpdateSubscriptionProperties();
10781078
}
10791079
}
@@ -1096,7 +1096,7 @@ internal void AddData(SubscriptionDataConfigList subscriptions)
10961096
{
10971097
throw new ArgumentException(Messages.Security.UnmatchingExchangeTimeZones, $"{nameof(subscription)}.{nameof(subscription.ExchangeTimeZone)}");
10981098
}
1099-
AddSubscription(subscription);
1099+
_subscriptionsBag.Add(subscription);
11001100
}
11011101
UpdateSubscriptionProperties();
11021102
}
@@ -1179,18 +1179,19 @@ internal virtual void UpdateSymbolProperties(SymbolProperties symbolProperties)
11791179
}
11801180

11811181
/// <summary>
1182-
/// Add a new subscription to this security if not already present
1182+
/// Resets the security to its initial state by marking it as uninitialized and non-tradable
1183+
/// and clearing the subscriptions.
11831184
/// </summary>
1184-
/// <remarks>
1185-
/// The caller must acquire the lock.
1186-
/// Using this instead of changing <see cref="_subscriptionsBag"/> from a list to a hash set to keep
1187-
/// the same behavior. Don't want to change the ordering.
1188-
/// </remarks>
1189-
private void AddSubscription(SubscriptionDataConfig subscription)
1185+
public virtual void Reset()
11901186
{
1191-
if (!_subscriptionsBag.Contains(subscription))
1187+
IsInitialized = false;
1188+
IsTradable = false;
1189+
1190+
// Reset the subscriptions
1191+
lock (_subscriptionsBag)
11921192
{
1193-
_subscriptionsBag.Add(subscription);
1193+
_subscriptionsBag.Clear();
1194+
UpdateSubscriptionProperties();
11941195
}
11951196
}
11961197
}

Common/Securities/SecurityService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ private Security CreateSecurity(Symbol symbol,
8080
if (!reCreateSecurity && _algorithm != null && _algorithm.Securities.TryGetValue(symbol, out var existingSecurity))
8181
{
8282
existingSecurity.AddData(configList);
83+
84+
// If non-internal, mark as tradable if it was not already since this is an existing security but might include new subscriptions
85+
if (!configList.IsInternalFeed)
86+
{
8387
existingSecurity.MakeTradable();
88+
}
8489

8590
// invoke the security initializer
8691
InitializeSecurity(initializeSecurity, existingSecurity);

Engine/DataFeeds/UniverseSelection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ public SecurityChanges HandleDelisting(BaseData data, bool isInternalFeed)
430430
{
431431
// don't allow users to open a new position once delisted
432432
security.IsDelisted = true;
433-
security.MakeNonTradable();
433+
security.Reset();
434434

435435
// Add the security removal to the security changes but only if not pending for removal.
436436
// If pending, the removed change event was already emitted for this security

0 commit comments

Comments
 (0)