/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Securities.Option.StrategyMatcher
{
///
/// Defines options that influence how the matcher operates.
///
///
/// Many properties in this type are not implemented in the matcher but are provided to document
/// the types of things that can be added to the matcher in the future as necessary. Some of the
/// features contemplated in this class would require updating the various matching/filtering/slicing
/// functions to accept these options, or a particular property. This is the case for the enumerators
/// which would be used to prioritize which positions to try and match first. A great implementation
/// of the would be to yield positions with the
/// highest margin requirements first. At time of writing, the goal is to achieve a workable rev0,
/// and we can later improve the efficiency/optimization of the matching process.
///
public class OptionStrategyMatcherOptions
{
///
/// The maximum amount of time spent trying to find an optimal solution.
///
public TimeSpan MaximumDuration { get; }
///
/// The maximum number of matches to evaluate for the entire portfolio.
///
public int MaximumSolutionCount { get; }
///
/// Indexed by leg index, defines the max matches to evaluate per leg.
/// For example, MaximumCountPerLeg[1] is the max matches to evaluate
/// for the second leg (index=1).
///
public IReadOnlyList MaximumCountPerLeg { get; }
///
/// The definitions to be used for matching.
///
public IEnumerable Definitions
=> _definitionEnumerator.Enumerate(_definitions);
///
/// Objective function used to compare different match solutions for a given set of positions/definitions
///
public IOptionStrategyMatchObjectiveFunction ObjectiveFunction { get; }
private readonly IReadOnlyList _definitions;
private readonly IOptionPositionCollectionEnumerator _positionEnumerator;
private readonly IOptionStrategyDefinitionEnumerator _definitionEnumerator;
///
/// Initializes a new instance of the class, providing
/// options that control the behavior of the
///
public OptionStrategyMatcherOptions(
IReadOnlyList definitions,
IReadOnlyList maximumCountPerLeg,
TimeSpan maximumDuration = default(TimeSpan),
int maximumSolutionCount = 100,
IOptionStrategyDefinitionEnumerator definitionEnumerator = null,
IOptionStrategyMatchObjectiveFunction objectiveFunction = null,
IOptionPositionCollectionEnumerator positionEnumerator = null
)
{
if (maximumDuration == default(TimeSpan))
{
maximumDuration = Time.OneMinute;
}
if (definitionEnumerator == null)
{
// by default we want more complex option strategies to have matching priority
definitionEnumerator = new DescendingByLegCountOptionStrategyDefinitionEnumerator();
}
if (objectiveFunction == null)
{
objectiveFunction = new UnmatchedPositionCountOptionStrategyMatchObjectiveFunction();
}
if (positionEnumerator == null)
{
positionEnumerator = new DefaultOptionPositionCollectionEnumerator();
}
_definitions = definitions;
MaximumDuration = maximumDuration;
ObjectiveFunction = objectiveFunction;
MaximumCountPerLeg = maximumCountPerLeg;
_positionEnumerator = positionEnumerator;
_definitionEnumerator = definitionEnumerator;
MaximumSolutionCount = maximumSolutionCount;
}
///
/// Gets the maximum number of leg matches to be evaluated. This is to limit evaluating exponential
/// numbers of potential matches as a result of large numbers of unique option positions for the same
/// underlying security.
///
public int GetMaximumLegMatches(int legIndex)
{
return MaximumCountPerLeg[legIndex];
}
///
/// Enumerates the specified according to the configured
///
///
public IEnumerable Enumerate(OptionPositionCollection positions)
{
return _positionEnumerator.Enumerate(positions);
}
///
/// Creates a new with the specified ,
/// with no limits of maximum matches per leg and default values for the remaining options
///
public static OptionStrategyMatcherOptions ForDefinitions(params OptionStrategyDefinition[] definitions)
{
return ForDefinitions(definitions.AsEnumerable());
}
///
/// Creates a new with the specified ,
/// with no limits of maximum matches per leg and default values for the remaining options
///
public static OptionStrategyMatcherOptions ForDefinitions(IEnumerable definitions)
{
var maximumCountPerLeg = new[] {int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue};
return new OptionStrategyMatcherOptions(definitions.ToList(), maximumCountPerLeg);
}
///
/// Specifies the maximum time provided for obtaining an optimal solution.
///
public OptionStrategyMatcherOptions WithMaximumDuration(TimeSpan duration)
{
return new OptionStrategyMatcherOptions(
_definitions,
MaximumCountPerLeg,
duration,
MaximumSolutionCount,
_definitionEnumerator,
ObjectiveFunction,
_positionEnumerator
);
}
///
/// Specifies the maximum number of solutions to evaluate via the objective function.
///
public OptionStrategyMatcherOptions WithMaximumSolutionCount(int count)
{
return new OptionStrategyMatcherOptions(
_definitions,
MaximumCountPerLeg,
MaximumDuration,
count,
_definitionEnumerator,
ObjectiveFunction,
_positionEnumerator
);
}
///
/// Specifies the maximum number of solutions per leg index in a solution. Matching is a recursive
/// process, for example, we'll find a very large number of positions to match the first leg. Matching
/// the second leg we'll see less, and third still even less. This is because each subsequent leg must
/// abide by all the previous legs. This parameter defines how many potential matches to evaluate at
/// each leg. For the first leg, we'll evaluate counts[0] matches. For the second leg we'll evaluate
/// counts[1] matches and so on. By decreasing this parameter we can evaluate more total, complete
/// solutions for the entire portfolio rather than evaluation every single permutation of matches for
/// a particular strategy definition, which grows in absurd exponential fashion as the portfolio grows.
///
public OptionStrategyMatcherOptions WithMaximumCountPerLeg(IReadOnlyList counts)
{
return new OptionStrategyMatcherOptions(
_definitions,
counts,
MaximumDuration,
MaximumSolutionCount,
_definitionEnumerator,
ObjectiveFunction,
_positionEnumerator
);
}
///
/// Specifies a function used to evaluate how desirable a particular solution is. A good implementation for
/// this would be to minimize the total margin required to hold all of the positions.
///
public OptionStrategyMatcherOptions WithObjectiveFunction(IOptionStrategyMatchObjectiveFunction function)
{
return new OptionStrategyMatcherOptions(
_definitions,
MaximumCountPerLeg,
MaximumDuration,
MaximumSolutionCount,
_definitionEnumerator,
function,
_positionEnumerator
);
}
///
/// Specifies the order in which definitions are evaluated. Definitions evaluated sooner are more likely to
/// find matches than ones evaluated later.
///
public OptionStrategyMatcherOptions WithDefinitionEnumerator(IOptionStrategyDefinitionEnumerator enumerator)
{
return new OptionStrategyMatcherOptions(
_definitions,
MaximumCountPerLeg,
MaximumDuration,
MaximumSolutionCount,
enumerator,
ObjectiveFunction,
_positionEnumerator
);
}
///
/// Specifies the order in which positions are evaluated. Positions evaluated sooner are more likely to
/// find matches than ones evaluated later. A good implementation for this is its stand-alone margin required,
/// which would encourage the algorithm to match higher margin positions before matching lower margin positiosn.
///
public OptionStrategyMatcherOptions WithPositionEnumerator(IOptionPositionCollectionEnumerator enumerator)
{
return new OptionStrategyMatcherOptions(
_definitions,
MaximumCountPerLeg,
MaximumDuration,
MaximumSolutionCount,
_definitionEnumerator,
ObjectiveFunction,
enumerator
);
}
}
}