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));
+ }
}
}