OptimizationProblem#

class sigtech.framework.analytics.optimization.optimization_problem.OptimizationProblem

Class to store a portfolio optimisation problem configuration.

An optimisation problem is composed of two parts: objectives and constraints. They are added separately to a problem instance via calls to set_optimizer_objective and set_optimizer_bounds.

In both cases the term type can be:

  • 'WEIGHT' - Adds a term to reduce or bound the notional allocations.

  • 'EXPOSURE' - Adds a term to reduce or bound the factor exposures.

  • 'VARIANCE' - Adds a term to reduce or bound variance contributions.

  • 'SERIES' - Adds a term to reduce or bound all individual returns in the history.

  • 'ALTERNATIVE' - These terms can only be added as a objectives and apply specialist optimisations.

The alternative optimisations are defined on the Optimizer class as methods prefixed with 'alt_'.

Each of these can impact different elements. For example, the bounds to weights can be applied to individual constituents, the sum of the weights (via 'SUM_' or '_SUM'), the 'NORM' metric or to 'ALL' weights.

A metric can be added to the elements for different impacts. A 'LINEAR' setting has no impact on the term, while 'ABSOLUTE' or 'SQUARE' transform the constraint or objective term to apply to the absolute or squared values. The behaviour of 'SUM_' and '_SUM' differ in how they interact with the metric, e.g. 'SUM_' with a 'SQUARE' metric considers the sum of squares, while '_SUM' considers the squared sum of values. The metric can also be set to 'MIN' or 'MAX' to take the minimum or maximum of the values.

Each term can take a weights and base input source. These sources are string identifiers for data added to the problem. Standard source variables are added during the optimisation. These include:

  • 'AVG_RET.' - The average historic returns.

  • 'AVG_RES.' - The average historic residual returns after factor contributions are removed.

  • 'SIGNAL' - A user provided signal to use for an alpha element. This is populated when using the optimized_allocations allocation function in the signal strategy.

  • 'FULL' - Covariance matrix for the historic returns.

  • 'FACTOR' - Covariance matrix for the factor contribution.

  • 'RESIDUAL' - Covariance matrix of the residuals.

  • 'INITIAL' - The initial portfolio weights. This is populated when using the optimized_allocations allocation function in the signal strategy.

Additional sources can be added to the problem with the set_source method. A source can be a number, series, dictionary, matrix or callable.

The weights input is used to adjust the contribution of the elements. Using the 'AVG_RET.' as weights, with a nominal weights objective term, will produce an objective to maximize the sum product of the weights and returns.

The base input is subtracted from the element before the metric is applied.

A few examples are given below:

# Create problem instance.
problem = OptimizationProblem()

# Add an objective to maximize the sumproduct of weights with historic returns.
problem.set_optimizer_objective(TermTypes.WEIGHT,
                                element='SUM_',
                                weights='AVG_RET.',
                                metric=MetricTypes.LINEAR,
                                value=1)

# Add an objective to minimize the squared exposure to a given 'MARKET' factor.
problem.set_optimizer_objective(TermTypes.EXPOSURE,
                                element='MARKET',
                                metric=MetricTypes.SQUARE,
                                value=-0.0001)  # Negative value: minimize, small magnitude: relatively unimportant.

# Add an objective to minimize the variance.
problem.set_optimizer_objective(TermTypes.VARIANCE,
                                element='FULL',
                                metric=MetricTypes.VARIANCE,
                                value=-1)

# Add a constraint to go long only for all instruments.
problem.set_optimizer_bounds(TermTypes.WEIGHT,
                             element='ALL',
                             metric=MetricTypes.LINEAR,
                             min_value=0)

# Add a constraint that the net allocation is 100%.
problem.set_optimizer_bounds(TermTypes.WEIGHT,
                             element='SUM_',
                             metric=MetricTypes.LINEAR,
                             min_value=1,
                             max_value=1)

# Add an objective to minimize the turnover from the initial portfolio.
problem.set_optimizer_objective(TermTypes.WEIGHT,
                                element='ALL',
                                metric=MetricTypes.ABSOLUTE,
                                base='INITIAL',
                                value=-1)

# Add an objective to minimize the worst loss in the history.
problem.set_optimizer_objective(TermTypes.SERIES,
                                element='ALL',
                                metric=MetricTypes.MIN,
                                value=-1)

# Add an objective to minimize the deviation from a given 'BENCHMARK' series.
problem.set_optimizer_objective(TermTypes.SERIES,
                                element='NORM',
                                base='BENCHMARK',
                                metric=MetricTypes.SQUARE,
                                value=-1)

# Add an alternative objective to minimize the variance contribution from the first principal component.
problem.set_optimizer_objective(TermTypes.ALTERNATIVE,
                                element='PC_1_VARIANCE',
                                value=1)

# Add a constraint that all nominal weights are in the same direction as a signal.
problem.set_optimizer_bounds(TermTypes.WEIGHT,
                             element='ALL',
                             weights='SIGNAL',
                             min_value=0)
copy()

Return a copy of this problem.

clear_optimizer_setting()

Clear all the optimiser settings.

set_optimizer_bounds(term_type, constraint_id=None, element='ALL', metric='LINEAR', base=None, weights=None, min_value=None, max_value=None)

Add a bound to the optimisation task.

Parameters
  • term_type – Bound identifier.

  • constraint_id – Constraint identifier (optional).

  • element – Element identifier (optional, default is 'ALL').

  • metric – Metric identifier (optional, default is MetricTypes.LINEAR).

  • base – Base source (optional).

  • weights – Weights source (optional).

  • min_value – Min value (optional).

  • max_value – Max value (optional).

set_optimizer_objective(term_type, constraint_id=None, element='ALL', metric='LINEAR', base=None, weights=None, value=None)

Add an objective to the optimisation task.

Parameters
  • term_type – Objective identifier.

  • constraint_id – Constraint identifier (optional).

  • element – Element identifier (optional, default is 'ALL').

  • metric – Metric identifier (optional, default is MetricTypes.LINEAR).

  • base – Base source (optional).

  • weights – Weights source (optional).

  • value – Input value (optional). The magnitude sets the relative weight of the objective term, the sign determines if the objective will be maximized (positive) or minimized (negative).

set_source(name, value)

Set the value/callback for a source.

Parameters
  • name – Input source.

  • value – Input value.

get_source_value(name)

Get the value for a source entry.

Parameters

name – Input source.

Returns

Source value.