/// <summary> /// Yields all possible matches for this leg definition held within the collection of <paramref name="positions"/> /// </summary> /// <param name="options">Strategy matcher options guiding matching behaviors</param> /// <param name="legs">The preceding legs already matched for the parent strategy definition</param> /// <param name="positions">The remaining, unmatched positions available to be matched against</param> /// <returns>An enumerable of potential matches</returns> public IEnumerable <OptionStrategyLegDefinitionMatch> Match( OptionStrategyMatcherOptions options, IReadOnlyList <OptionPosition> legs, OptionPositionCollection positions ) { foreach (var position in options.Enumerate(Filter(legs, positions, false))) { var multiplier = position.Quantity / Quantity; if (multiplier != 0) { yield return(new OptionStrategyLegDefinitionMatch(multiplier, position.WithQuantity(multiplier * Quantity) )); } } }
private IEnumerable <OptionStrategyDefinitionMatch> Match( OptionStrategyMatcherOptions options, ImmutableList <OptionStrategyLegDefinitionMatch> legMatches, ImmutableList <OptionPosition> legPositions, OptionPositionCollection positions, int multiplier ) { var nextLegIndex = legPositions.Count; if (nextLegIndex == Legs.Count) { if (nextLegIndex > 0) { yield return(new OptionStrategyDefinitionMatch(this, legMatches, multiplier)); } } else if (positions.Count >= LegCount - nextLegIndex) { // grab the next leg definition and perform the match, restricting total to configured maximum per leg var nextLeg = Legs[nextLegIndex]; var maxLegMatch = options.GetMaximumLegMatches(nextLegIndex); foreach (var legMatch in nextLeg.Match(options, legPositions, positions).Take(maxLegMatch)) { // add match to the match we're constructing and deduct matched position from positions collection // we track the min multiplier in line so when we're done, we have the total number of matches for // the matched set of positions in this 'thread' (OptionStrategy.Quantity) foreach (var definitionMatch in Match(options, legMatches.Add(legMatch), legPositions.Add(legMatch.Position), positions - legMatch.Position, Math.Min(multiplier, legMatch.Multiplier) )) { yield return(definitionMatch); } } } else { // positions.Count < LegsCount indicates a failed match // could include partial matches, would allow an algorithm to determine if adding a // new position could help reduce overall margin exposure by completing a strategy } }
/// <summary> /// Determines all possible matches for this definition using the provided <paramref name="positions"/>. /// This includes OVERLAPPING matches. It's up to the actual matcher to make decisions based on which /// matches to accept. This allows the matcher to prioritize matching certain positions over others. /// </summary> public IEnumerable <OptionStrategyDefinitionMatch> Match( OptionStrategyMatcherOptions options, OptionPositionCollection positions ) { // TODO : Pass OptionStrategyMatcherOptions in and respect applicable options if (positions.Count < LegCount) { return(Enumerable.Empty <OptionStrategyDefinitionMatch>()); } var multiplier = int.MaxValue; // first check underlying lots has correct sign and sufficient magnitude var underlyingLotsSign = Math.Sign(UnderlyingLots); if (underlyingLotsSign != 0) { var underlyingPositionSign = Math.Sign(positions.UnderlyingQuantity); if (underlyingLotsSign != underlyingPositionSign || Math.Abs(positions.UnderlyingQuantity) < Math.Abs(UnderlyingLots)) { return(Enumerable.Empty <OptionStrategyDefinitionMatch>()); } // set multiplier for underlying multiplier = positions.UnderlyingQuantity / UnderlyingLots; } // TODO : Consider add OptionStrategyLegDefinition for underlying for consistency purposes. // Might want to enforce that it's always the first leg definition as well for easier slicing. return(Match(options, ImmutableList <OptionStrategyLegDefinitionMatch> .Empty, ImmutableList <OptionPosition> .Empty, positions, multiplier ).Distinct()); }
/// <summary> /// Initializes a new instance of the <see cref="OptionStrategyMatcher"/> class /// </summary> /// <param name="options">Specifies definitions and other options controlling the matcher</param> public OptionStrategyMatcher(OptionStrategyMatcherOptions options) { Options = options; }
/// <summary> /// Determines all possible matches for this definition using the provided <paramref name="positions"/>. /// This includes OVERLAPPING matches. It's up to the actual matcher to make decisions based on which /// matches to accept. This allows the matcher to prioritize matching certain positions over others. /// </summary> public IEnumerable <OptionStrategyDefinitionMatch> Match(OptionPositionCollection positions) { return(Match(OptionStrategyMatcherOptions.ForDefinitions(this), positions)); }
/// <summary> /// Attempts to match the positions to this definition exactly once, by evaluating the enumerable and /// taking the first entry matched. If not match is found, then false is returned and <paramref name="match"/> /// will be null. /// </summary> public bool TryMatchOnce(OptionStrategyMatcherOptions options, OptionPositionCollection positions, out OptionStrategyDefinitionMatch match) { match = Match(options, positions).FirstOrDefault(); return(match != null); }