public void ResultingPositionsAreCorrectWithUnderlying() { var positions = Empty.AddRange( Position(Call[100], -5), // should match 4 covered calls new OptionPosition(Underlying, 4) ); var matches = CoveredCall.Match(positions).ToList(); Assert.AreEqual(1, matches.Count); // underlying isn't included yet Assert.AreEqual(1, matches[0].Legs.Count); Assert.AreEqual(1, matches[0].Legs.Count(m => m.Position.Strike == 100 && m.Position.Quantity == -5)); var strategy = matches[0].CreateStrategy(); Assert.AreEqual(1, strategy.OptionLegs.Count); Assert.AreEqual(1, strategy.UnderlyingLegs.Count); Assert.AreEqual(1, strategy.OptionLegs.Count(m => m.Strike == 100 && m.Quantity == -4)); Assert.AreEqual(1, strategy.UnderlyingLegs.Count(m => m.Quantity == 4)); // assert the remaining positions are the expected ones positions = matches[0].RemoveFrom(positions); Assert.AreEqual(1, positions.Count); Assert.AreEqual(1, positions.Count(m => !m.IsUnderlying && m.Strike == 100 && m.Quantity == -1)); }
/// <summary> /// Creates a new <see cref="OptionPositionCollection"/> from the specified enumerable of <paramref name="positions"/> /// </summary> public static OptionPositionCollection FromPositions(IEnumerable <IPosition> positions, decimal contractMultiplier) { return(Empty.AddRange(positions.Select(position => { var quantity = (int)position.Quantity; if (position.Symbol.SecurityType.HasOptions()) { quantity = (int)(quantity / contractMultiplier); } return new OptionPosition(position.Symbol, quantity); }))); }
public void DoubleCountPositionsMatchingSamePositionMultipleTimesInDifferentMatches() { // this test aims to verify that we can match the same definition multiple times if positions allows // 1: -C110 +C105 // 0: -C110 +C100 // 2: -C115 +C105 // 3: -C115 +C100 var positions = Empty.AddRange( Position(Call[100], -1), Position(Call[105], -1), Position(Call[110]), Position(Call[115]) ); var matches = BearCallSpread.Match(positions).ToList(); Assert.AreEqual(4, matches.Count); Assert.AreEqual(1, matches.Count(m => m.Legs[1].Position.Strike == 110 && m.Legs[0].Position.Strike == 105)); Assert.AreEqual(1, matches.Count(m => m.Legs[1].Position.Strike == 110 && m.Legs[0].Position.Strike == 100)); Assert.AreEqual(1, matches.Count(m => m.Legs[1].Position.Strike == 115 && m.Legs[0].Position.Strike == 105)); Assert.AreEqual(1, matches.Count(m => m.Legs[1].Position.Strike == 115 && m.Legs[0].Position.Strike == 100)); }
public void CoveredCall_MatchesMultipleTimes_ForEachUniqueShortCallContract() { // CoveredCall // 0: +1 underlying lot // 1: -1 Call // so we should match // (4U, -4C100) // (3U, -3C110) // (5U, -5C120) // (9U, -9C130) // (20U, -20C140) // OptionStrategyDefinition.Match produces ALL possible matches var positions = Empty.AddRange(Position(Underlying, +20), Position(Call[100], -4), Position(Put[105], -4), Position(Call[105], +4), Position(Put[110], +4), Position(Call[110], -3), Position(Put[115], -3), Position(Call[115], +3), Position(Put[120], +3), Position(Call[120], -5), Position(Put[125], -5), Position(Call[125], +5), Position(Put[130], +5), Position(Call[130], -9), Position(Put[135], -9), Position(Call[140], -21), Position(Put[145], -21) ); // force lower strikes to be evaluated first to provide determinism for this test var options = OptionStrategyMatcherOptions.ForDefinitions(CoveredCall) .WithPositionEnumerator(new FunctionalOptionPositionCollectionEnumerator( pos => pos.OrderBy(p => p.IsUnderlying ? 0 : p.Strike) )); var matches = CoveredCall.Match(options, positions).ToList(); Assert.AreEqual(5, matches.Count); Assert.AreEqual(1, matches.Count(m => m.Multiplier == 4)); Assert.AreEqual(1, matches.Count(m => m.Multiplier == 3)); Assert.AreEqual(1, matches.Count(m => m.Multiplier == 5)); Assert.AreEqual(1, matches.Count(m => m.Multiplier == 9)); Assert.AreEqual(1, matches.Count(m => m.Multiplier == 20)); }
public void ResultingPositionsAreCorrectNoUnderlying() { var positions = Empty.AddRange( Position(Call[100], 10), Position(Call[110], -20), Position(Call[120], 10) ); var matches = ButterflyCall.Match(positions).ToList(); Assert.AreEqual(1, matches.Count); Assert.AreEqual(3, matches[0].Legs.Count); Assert.AreEqual(1, matches[0].Legs.Count(m => m.Position.Strike == 100 && m.Position.Quantity == 10)); Assert.AreEqual(1, matches[0].Legs.Count(m => m.Position.Strike == 110 && m.Position.Quantity == -20)); Assert.AreEqual(1, matches[0].Legs.Count(m => m.Position.Strike == 120 && m.Position.Quantity == 10)); // Now let add some extra option contracts which shouldn't match since they aren't enough positions = positions.Add(Position(Call[100], 5)); positions = positions.Add(Position(Call[110], -5)); matches = ButterflyCall.Match(positions).ToList(); Assert.AreEqual(1, matches.Count); Assert.AreEqual(3, matches[0].Legs.Count); // assert the strategy size respects the matching multiplier var strategy = matches[0].CreateStrategy(); Assert.AreEqual(1, strategy.OptionLegs.Count(m => m.Strike == 100 && m.Quantity == 10)); Assert.AreEqual(1, strategy.OptionLegs.Count(m => m.Strike == 110 && m.Quantity == -20)); Assert.AreEqual(1, strategy.OptionLegs.Count(m => m.Strike == 120 && m.Quantity == 10)); // assert the remaining positions are the expected ones positions = matches[0].RemoveFrom(positions); Assert.AreEqual(2, positions.Count); Assert.AreEqual(1, positions.Count(m => m.Strike == 100 && m.Quantity == 5)); Assert.AreEqual(1, positions.Count(m => m.Strike == 110 && m.Quantity == -5)); }
/// <summary> /// Creates a new <see cref="OptionPositionCollection"/> from the specified enumerable of <paramref name="positions"/> /// </summary> public static OptionPositionCollection FromPositions(IEnumerable <OptionPosition> positions) { return(Empty.AddRange(positions)); }