From 5d0e18d3e46040cab8bc92deb335db8bf8780eaa Mon Sep 17 00:00:00 2001 From: Jhonathan Abreu Date: Thu, 26 Sep 2024 19:17:39 -0400 Subject: [PATCH] Handle Greeks unwrapping by PandasData --- ...ainsMultipleFullDataRegressionAlgorithm.cs | 2 +- Common/Data/Market/OptionContract.cs | 25 ---- Common/Python/PandasData.cs | 108 ++++++++++++++---- 3 files changed, 89 insertions(+), 46 deletions(-) diff --git a/Algorithm.CSharp/OptionChainsMultipleFullDataRegressionAlgorithm.cs b/Algorithm.CSharp/OptionChainsMultipleFullDataRegressionAlgorithm.cs index 33dafd99d242..0e5484e5f0fc 100644 --- a/Algorithm.CSharp/OptionChainsMultipleFullDataRegressionAlgorithm.cs +++ b/Algorithm.CSharp/OptionChainsMultipleFullDataRegressionAlgorithm.cs @@ -61,7 +61,7 @@ private Symbol GetContract(OptionChains chains, Symbol underlying, TimeSpan expi // Get contracts expiring within a given span, with an implied volatility greater than 0.5 and a delta less than 0.5 .Where(contractData => contractData.ID.Date - Time <= expirySpan && contractData.ImpliedVolatility > 0.5m && - contractData.Delta < 0.5m) + contractData.Greeks.Delta < 0.5m) // Get the contract with the latest expiration date .OrderByDescending(x => x.ID.Date) .First(); diff --git a/Common/Data/Market/OptionContract.cs b/Common/Data/Market/OptionContract.cs index 63aaeedb55e6..e422711518e8 100644 --- a/Common/Data/Market/OptionContract.cs +++ b/Common/Data/Market/OptionContract.cs @@ -87,31 +87,6 @@ public Symbol Symbol /// public Greeks Greeks => _optionData.Greeks; - /// - /// Gets the delta. Pass-through for - /// - public decimal Delta => Greeks.Delta; - - /// - /// Gets the gamma. Pass-through for - /// - public decimal Gamma => Greeks.Gamma; - - /// - /// Gets the vega. Pass-through for - /// - public decimal Vega => Greeks.Vega; - - /// - /// Gets the theta. Pass-through for - /// - public decimal Theta => Greeks.Theta; - - /// - /// Gets the rho. Pass-through for - /// - public decimal Rho => Greeks.Rho; - /// /// Gets the local date time this contract's data was last updated /// diff --git a/Common/Python/PandasData.cs b/Common/Python/PandasData.cs index 9f76503170ab..258325bbefc2 100644 --- a/Common/Python/PandasData.cs +++ b/Common/Python/PandasData.cs @@ -62,9 +62,22 @@ public class PandasData private static readonly string[] _optionContractExcludedMembers = new[] { nameof(OptionContract.ID), - nameof(OptionContract.Greeks) }; + private static readonly string[] _greeksMemberNames = new[] + { + nameof(Greeks.Delta), + nameof(Greeks.Gamma), + nameof(Greeks.Vega), + nameof(Greeks.Theta), + nameof(Greeks.Rho), + }; + + private static readonly MemberInfo[] _greeksMembers = typeof(Greeks) + .GetMembers(BindingFlags.Instance | BindingFlags.Public) + .Where(x => (x.MemberType == MemberTypes.Field || x.MemberType == MemberTypes.Property) && _greeksMemberNames.Contains(x.Name)) + .ToArray(); + // we keep these so we don't need to ask for them each time private static PyString _empty; private static PyObject _pandas; @@ -138,6 +151,7 @@ public PandasData(object data) foreach (var item in enumerable) { data = item; + baseData = data as IBaseData; break; } } @@ -206,6 +220,26 @@ public PandasData(object data) _members = members.Where(x => keys.Contains(x.Name.ToLowerInvariant())).ToList(); _membersByType.TryAdd(type, _members); } + + // Make sure to add the greeks member names to the series so they can be added to the data frame + if (_members.Any(member => + { + var memberType = member switch + { + PropertyInfo property => property.PropertyType, + FieldInfo field => field.FieldType, + // Should not happen + _ => throw new InvalidOperationException($"Unexpected member type: {member.MemberType}") + }; + + return memberType.IsAssignableTo(typeof(Greeks)); + })) + { + foreach (var greek in _greeksMemberNames) + { + keys.Add(greek.ToLowerInvariant()); + } + } } var customColumns = new HashSet(columns) { "value" }; @@ -231,25 +265,31 @@ public void Add(object baseData) foreach (var member in _members) { - // TODO field/property.GetValue is expensive - var key = member.Name.ToLowerInvariant(); - var propertyMember = member as PropertyInfo; - if (propertyMember != null) + var memberType = member switch { - var propertyValue = propertyMember.GetValue(baseData); - if (_isFundamentalType && propertyMember.PropertyType.IsAssignableTo(typeof(FundamentalTimeDependentProperty))) - { - propertyValue = ((FundamentalTimeDependentProperty)propertyValue).Clone(new FixedTimeProvider(endTime)); - } - AddToSeries(key, endTime, propertyValue); - continue; + PropertyInfo property => property.PropertyType, + FieldInfo field => field.FieldType, + // Should not happen + _ => throw new InvalidOperationException($"Unexpected member type: {member.MemberType}") + }; + + if (!memberType.IsAssignableTo(typeof(Greeks))) + { + AddMemberToSeries(baseData, endTime, member); } else { - var fieldMember = member as FieldInfo; - if (fieldMember != null) + var greeks = member switch + { + PropertyInfo property => property.GetValue(baseData), + FieldInfo field => field.GetValue(baseData), + // Should not happen + _ => throw new InvalidOperationException($"Unexpected member type: {member.MemberType}") + }; + + foreach (var greekMember in _greeksMembers) { - AddToSeries(key, endTime, fieldMember.GetValue(baseData)); + AddMemberToSeries(greeks, endTime, greekMember); } } } @@ -267,13 +307,41 @@ public void Add(object baseData) AddToSeries(kvp.Key, endTime, kvp.Value); } } - else + else if (baseData is Tick tick) + { + AddTick(tick); + } + else if (baseData is TradeBar tradeBar) + { + Add(tradeBar, null); + } + else if (baseData is QuoteBar quoteBar) { - AddTick(baseData as Tick); + Add(null, quoteBar); + } + } - var tradeBar = baseData as TradeBar; - var quoteBar = baseData as QuoteBar; - Add(tradeBar, quoteBar); + private void AddMemberToSeries(object baseData, DateTime endTime, MemberInfo member) + { + // TODO field/property.GetValue is expensive + var key = member.Name.ToLowerInvariant(); + var propertyMember = member as PropertyInfo; + if (propertyMember != null) + { + var propertyValue = propertyMember.GetValue(baseData); + if (_isFundamentalType && propertyMember.PropertyType.IsAssignableTo(typeof(FundamentalTimeDependentProperty))) + { + propertyValue = ((FundamentalTimeDependentProperty)propertyValue).Clone(new FixedTimeProvider(endTime)); + } + AddToSeries(key, endTime, propertyValue); + } + else + { + var fieldMember = member as FieldInfo; + if (fieldMember != null) + { + AddToSeries(key, endTime, fieldMember.GetValue(baseData)); + } } }