Skip to content

Commit

Permalink
Fix: refresh symbol properties using right type for security. (#8087)
Browse files Browse the repository at this point in the history
Fix for live trading SPDB refresh
  • Loading branch information
jhonabreul committed Jun 11, 2024
1 parent 4ca5cbc commit a159950
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Common/Securities/IndexOption/IndexOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,16 @@ protected override void UpdateConsumersMarketPrice(BaseData data)
base.UpdateConsumersMarketPrice(data);
((IndexOptionSymbolProperties)SymbolProperties).UpdateMarketPrice(data);
}

/// <summary>
/// Updates the symbol properties of this security
/// </summary>
internal override void UpdateSymbolProperties(SymbolProperties symbolProperties)
{
if (symbolProperties != null)
{
SymbolProperties = new IndexOptionSymbolProperties(symbolProperties);
}
}
}
}
11 changes: 11 additions & 0 deletions Common/Securities/Option/Option.cs
Original file line number Diff line number Diff line change
Expand Up @@ -668,5 +668,16 @@ private void SetFilterImp(Func<OptionFilterUniverse, OptionFilterUniverse> unive
return result.ApplyTypesFilter();
});
}

/// <summary>
/// Updates the symbol properties of this security
/// </summary>
internal override void UpdateSymbolProperties(SymbolProperties symbolProperties)
{
if (symbolProperties != null)
{
SymbolProperties = new OptionSymbolProperties(symbolProperties);
}
}
}
}
13 changes: 12 additions & 1 deletion Common/Securities/Security.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Cash QuoteCurrency
public SymbolProperties SymbolProperties
{
get;
internal set;
protected set;
}

/// <summary>
Expand Down Expand Up @@ -1146,5 +1146,16 @@ internal void ApplySplit(Split split)
Cache.ApplySplit(split);
UpdateMarketPrice(Cache.GetData());
}

/// <summary>
/// Updates the symbol properties of this security
/// </summary>
internal virtual void UpdateSymbolProperties(SymbolProperties symbolProperties)
{
if (symbolProperties != null)
{
SymbolProperties = symbolProperties;
}
}
}
}
2 changes: 1 addition & 1 deletion Engine/RealTime/LiveTradingRealTimeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ protected virtual void UpdateSymbolProperties(Security security)
{
var symbolProperties = SymbolPropertiesDatabase.GetSymbolProperties(security.Symbol.ID.Market, security.Symbol,
security.Symbol.ID.SecurityType, security.QuoteCurrency.Symbol);
security.SymbolProperties = symbolProperties;
security.UpdateSymbolProperties(symbolProperties);
}

/// <summary>
Expand Down
76 changes: 76 additions & 0 deletions Tests/Engine/RealTime/LiveTradingRealTimeHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
using QuantConnect.Lean.Engine.HistoricalData;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Util;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.IndexOption;

namespace QuantConnect.Tests.Engine.RealTime
{
Expand Down Expand Up @@ -202,6 +204,80 @@ public void RefreshesSymbolProperties(string refreshPeriodStr)
}
}

[TestCase(SecurityType.Equity, typeof(SymbolProperties))]
[TestCase(SecurityType.Forex, typeof(SymbolProperties))]
[TestCase(SecurityType.Future, typeof(SymbolProperties))]
[TestCase(SecurityType.FutureOption, typeof(SymbolProperties))]
[TestCase(SecurityType.Cfd, typeof(SymbolProperties))]
[TestCase(SecurityType.Crypto, typeof(SymbolProperties))]
[TestCase(SecurityType.CryptoFuture, typeof(SymbolProperties))]
[TestCase(SecurityType.Index, typeof(SymbolProperties))]
[TestCase(SecurityType.Option, typeof(OptionSymbolProperties))]
[TestCase(SecurityType.IndexOption, typeof(IndexOptionSymbolProperties))]
public void SecuritySymbolPropertiesTypeIsRespectedAfterRefresh(SecurityType securityType, Type expectedSymbolPropertiesType)
{
using var realTimeHandler = new SPDBTestLiveTradingRealTimeHandler();

var timeProvider = realTimeHandler.PublicTimeProvider;
timeProvider.SetCurrentTimeUtc(new DateTime(2023, 5, 30));

var algorithm = new AlgorithmStub();
var refreshPeriod = TimeSpan.FromDays(1);
algorithm.Settings.DatabasesRefreshPeriod = refreshPeriod;

var symbol = GetSymbol(securityType);
var security = algorithm.AddSecurity(symbol);

Assert.IsInstanceOf(expectedSymbolPropertiesType, security.SymbolProperties);

realTimeHandler.Setup(algorithm,
new AlgorithmNodePacket(PacketType.AlgorithmNode),
new BacktestingResultHandler(),
null,
new TestTimeLimitManager());
realTimeHandler.SpdbRefreshed.Reset();
realTimeHandler.SecuritySymbolPropertiesUpdated.Reset();

algorithm.SetFinishedWarmingUp();
realTimeHandler.SetTime(timeProvider.GetUtcNow());

var previousSymbolProperties = security.SymbolProperties;

// Refresh the spdb
timeProvider.Advance(refreshPeriod);
Assert.IsTrue(realTimeHandler.SpdbRefreshed.WaitOne(1000));
Assert.IsTrue(realTimeHandler.SecuritySymbolPropertiesUpdated.WaitOne(1000));

// Access the symbol properties again
// The instance must have been changed
Assert.AreNotSame(security.SymbolProperties, previousSymbolProperties);
Assert.IsInstanceOf(expectedSymbolPropertiesType, security.SymbolProperties);
}

private static Symbol GetSymbol(SecurityType securityType)
{
return securityType switch
{
SecurityType.Equity => Symbols.SPY,
SecurityType.Forex => Symbols.USDJPY,
SecurityType.Future => Symbols.Future_ESZ18_Dec2018,
SecurityType.FutureOption => Symbol.CreateOption(
Symbols.Future_ESZ18_Dec2018,
Market.CME,
OptionStyle.American,
OptionRight.Call,
4000m,
new DateTime(2023, 6, 16)),
SecurityType.Cfd => Symbols.DE10YBEUR,
SecurityType.Crypto => Symbols.BTCUSD,
SecurityType.CryptoFuture => Symbol.Create("BTCUSD", securityType, Market.Binance),
SecurityType.Index => Symbols.SPX,
SecurityType.Option => Symbols.SPY_C_192_Feb19_2016,
SecurityType.IndexOption => Symbol.Create("SPX", securityType, Market.USA),
_ => throw new ArgumentOutOfRangeException(nameof(securityType), securityType, null)
};
}

private class TestTimeLimitManager : IIsolatorLimitResultProvider
{
public IsolatorLimitResult IsWithinLimit()
Expand Down

0 comments on commit a159950

Please sign in to comment.