Skip to content

Commit

Permalink
Performance improvements for Options
Browse files Browse the repository at this point in the history
- Replace Enum to string operations on Options enums, since it's
  expensive
- Replace Enum IsDefined check since it uses reflection
- Improve OptionFilterUniverse linq operations
- Improve performance of SecurityIdentifier properties to avoid having
  to extract them from properties always
- Avoid calling ToList for already list data collections (it creates a
  copy)
- Avoid iterating over securities for which we have no holdings when
  calculating TPV or MarginUsed
  • Loading branch information
Martin-Molinero committed May 6, 2020
1 parent 6588def commit 714b98f
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 56 deletions.
14 changes: 13 additions & 1 deletion Common/Data/UniverseSelection/BaseDataCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,23 @@ public BaseDataCollection(DateTime time, Symbol symbol, IEnumerable<BaseData> da
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, IEnumerable<BaseData> data = null)
: this(time, endTime, symbol, data != null ? data.ToList() : new List<BaseData>())
{
}

/// <summary>
/// Initializes a new instance of the <see cref="BaseDataCollection"/> class
/// </summary>
/// <param name="time">The start time of this data</param>
/// <param name="endTime">The end time of this data</param>
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data)
{
Symbol = symbol;
Time = time;
_endTime = endTime;
Data = data != null ? data.ToList() : new List<BaseData>();
Data = data ?? new List<BaseData>();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public FuturesChainUniverseDataCollection()
/// <param name="time">The time of this data</param>
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
public FuturesChainUniverseDataCollection(DateTime time, Symbol symbol, IEnumerable<BaseData> data = null)
public FuturesChainUniverseDataCollection(DateTime time, Symbol symbol, List<BaseData> data = null)
: this(time, time, symbol, data)
{
}
Expand All @@ -56,7 +56,7 @@ public FuturesChainUniverseDataCollection(DateTime time, Symbol symbol, IEnumera
/// <param name="endTime">The end time of this data</param>
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
public FuturesChainUniverseDataCollection(DateTime time, DateTime endTime, Symbol symbol, IEnumerable<BaseData> data = null)
public FuturesChainUniverseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data = null)
: base(time, endTime, symbol, data)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public OptionChainUniverseDataCollection()
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
/// <param name="underlying">The option chain's underlying price data</param>
public OptionChainUniverseDataCollection(DateTime time, Symbol symbol, IEnumerable<BaseData> data = null, BaseData underlying = null)
public OptionChainUniverseDataCollection(DateTime time, Symbol symbol, List<BaseData> data = null, BaseData underlying = null)
: this(time, time, symbol, data, underlying)
{
}
Expand All @@ -63,7 +63,7 @@ public OptionChainUniverseDataCollection(DateTime time, Symbol symbol, IEnumerab
/// <param name="symbol">A common identifier for all data in this packet</param>
/// <param name="data">The data to add to this collection</param>
/// <param name="underlying">The option chain's underlying price data</param>
public OptionChainUniverseDataCollection(DateTime time, DateTime endTime, Symbol symbol, IEnumerable<BaseData> data = null, BaseData underlying = null)
public OptionChainUniverseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data = null, BaseData underlying = null)
: base(time, endTime, symbol, data)
{
Underlying = underlying;
Expand Down
44 changes: 44 additions & 0 deletions Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,50 @@ public static string ToLower(this Enum @enum)
return @enum.ToString().ToLowerInvariant();
}

/// <summary>
/// Asserts the specified <paramref name="securityType"/> value is valid
/// </summary>
/// <remarks>This method provides faster performance than <see cref="Enum.IsDefined"/> which uses reflection</remarks>
/// <param name="securityType">The SecurityType value</param>
/// <returns>True if valid security type value</returns>
public static bool IsValid(this SecurityType securityType)
{
switch (securityType)
{
case SecurityType.Base:
case SecurityType.Equity:
case SecurityType.Option:
case SecurityType.Commodity:
case SecurityType.Forex:
case SecurityType.Future:
case SecurityType.Cfd:
case SecurityType.Crypto:
return true;
default:
return false;
}
}

/// <summary>
/// Converts the specified <paramref name="optionRight"/> value to its corresponding string representation
/// </summary>
/// <remarks>This method provides faster performance than enum <see cref="ToString"/></remarks>
/// <param name="optionRight">The optionRight value</param>
/// <returns>A string representation of the specified OptionRight value</returns>
public static string ToStringPerformance(this OptionRight optionRight)
{
switch (optionRight)
{
case OptionRight.Call:
return "Call";
case OptionRight.Put:
return "Put";
default:
// just in case
return optionRight.ToString();
}
}

/// <summary>
/// Converts the specified <paramref name="securityType"/> value to its corresponding lower-case string representation
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Common/Securities/Future/FutureFilterUniverse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public FutureFilterUniverse(IEnumerable<Symbol> allSymbols, BaseData underlying)
/// <returns></returns>
public FutureFilterUniverse FrontMonth()
{
if (_allSymbols.Count() == 0) return this;
var ordered = this.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return this;
var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);

_allSymbols = frontMonth.ToList();
Expand All @@ -83,8 +83,8 @@ public FutureFilterUniverse FrontMonth()
/// <returns></returns>
public FutureFilterUniverse BackMonths()
{
if (_allSymbols.Count() == 0) return this;
var ordered = this.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return this;
var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);

_allSymbols = backMonths.ToList();
Expand Down
26 changes: 12 additions & 14 deletions Common/Securities/Option/OptionFilterUniverse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using QuantConnect.Data;
using System.Linq;
using System.Collections;
using QuantConnect.Util;
using QuantConnect.Securities.Option;

namespace QuantConnect.Securities
Expand Down Expand Up @@ -125,15 +124,16 @@ internal OptionFilterUniverse ApplyOptionTypesFilter()
{
var dt = symbol.ID.Date;

if (memoizedMap.ContainsKey(dt))
return memoizedMap[dt];
bool result;
if (memoizedMap.TryGetValue(dt, out result))
return result;
var res = OptionSymbol.IsStandard(symbol);
memoizedMap[dt] = res;

return res;
};

var filtered = _allSymbols.Where(x =>
_allSymbols = _allSymbols.Where(x =>
{
switch (_type)
{
Expand All @@ -146,9 +146,8 @@ internal OptionFilterUniverse ApplyOptionTypesFilter()
default:
return false;
}
});
}).ToList();

_allSymbols = filtered.ToList();
return this;
}

Expand All @@ -158,8 +157,8 @@ internal OptionFilterUniverse ApplyOptionTypesFilter()
/// <returns></returns>
public OptionFilterUniverse FrontMonth()
{
if (!_allSymbols.Any()) return this;
var ordered = this.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return this;
var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);

_allSymbols = frontMonth.ToList();
Expand All @@ -172,8 +171,8 @@ public OptionFilterUniverse FrontMonth()
/// <returns></returns>
public OptionFilterUniverse BackMonths()
{
if (!_allSymbols.Any()) return this;
var ordered = this.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return this;
var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);

_allSymbols = backMonths.ToList();
Expand Down Expand Up @@ -205,10 +204,10 @@ public OptionFilterUniverse Strikes(int minStrike, int maxStrike)
if (_underlying.Time.Date != _uniqueStrikesResolveDate)
{
// each day we need to recompute the unique strikes list
_uniqueStrikes = _allSymbols
.DistinctBy(x => x.ID.StrikePrice)
.OrderBy(x => x.ID.StrikePrice)
.ToList(symbol => symbol.ID.StrikePrice);
_uniqueStrikes = _allSymbols.Select(x => x.ID.StrikePrice)
.Distinct()
.OrderBy(strikePrice => strikePrice)
.ToList();

_uniqueStrikesResolveDate = _underlying.Time.Date;
}
Expand Down Expand Up @@ -286,8 +285,7 @@ public OptionFilterUniverse Strikes(int minStrike, int maxStrike)
var price = symbol.ID.StrikePrice;
return price >= minPrice && price <= maxPrice;
}
)
.ToList();
).ToList();

return this;
}
Expand Down
8 changes: 2 additions & 6 deletions Common/Securities/SecurityPortfolioManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ public decimal TotalPortfolioValue
{
decimal totalHoldingsValueWithoutForexCryptoFutureCfd = 0;
decimal totalFuturesAndCfdHoldingsValue = 0;
foreach (var kvp in Securities)
foreach (var kvp in Securities.Where((pair, i) => pair.Value.Holdings.Quantity != 0))
{
var position = kvp.Value;
var securityType = position.Type;
Expand Down Expand Up @@ -477,13 +477,9 @@ public decimal TotalMarginUsed
get
{
decimal sum = 0;
foreach (var kvp in Securities)
foreach (var kvp in Securities.Where((pair, i) => pair.Value.Holdings.Quantity != 0))
{
var security = kvp.Value;
if (security.Holdings.Quantity == 0)
{
continue;
}
var context = new ReservedBuyingPowerForPositionParameters(security);
var reservedBuyingPower = security.BuyingPowerModel.GetReservedBuyingPowerForPosition(context);
sum += reservedBuyingPower.AbsoluteUsedBuyingPower;
Expand Down
Loading

0 comments on commit 714b98f

Please sign in to comment.