/// <summary> /// Filters the provided <paramref name="positions"/> collection such that any remaining positions are all /// valid options that match this leg definition instance. /// </summary> public OptionPositionCollection Filter(IReadOnlyList <OptionPosition> legs, OptionPositionCollection positions, bool includeUnderlying = true) { // first filter down to applicable right positions = positions.Slice(Right, includeUnderlying); if (positions.IsEmpty) { return(positions); } // second filter according to the required side var side = (PositionSide)Math.Sign(Quantity); positions = positions.Slice(side, includeUnderlying); if (positions.IsEmpty) { return(positions); } // these are ordered such that indexed filters are performed force and // opaque/complex predicates follow since they require full table scans foreach (var predicate in _predicates) { positions = predicate.Filter(legs, positions, includeUnderlying); if (positions.IsEmpty) { break; } } // at this point, every position in the positions // collection is a valid match for this definition return(positions); }
/// <summary> /// Filters the specified <paramref name="positions"/> by applying this predicate based on the referenced legs. /// </summary> public OptionPositionCollection Filter(IReadOnlyList <OptionPosition> legs, OptionPositionCollection positions, bool includeUnderlying) { if (!IsIndexed) { // if the predicate references non-indexed properties or contains complex/multiple conditions then // we'll need to do a full table scan. this is not always avoidable, but we should try to avoid it return(OptionPositionCollection.Empty.AddRange( positions.Where(position => _predicate(legs, position)) )); } var referenceValue = _reference.Resolve(legs); switch (_reference.Target) { case PredicateTargetValue.Right: return(positions.Slice((OptionRight)referenceValue, includeUnderlying)); case PredicateTargetValue.Strike: return(positions.Slice(_comparison, (decimal)referenceValue, includeUnderlying)); case PredicateTargetValue.Expiration: return(positions.Slice(_comparison, (DateTime)referenceValue, includeUnderlying)); default: throw new ArgumentOutOfRangeException(); } }