Skip to content

Portfolio Optimization with Investment Bands API Reference

Data

Data model for Portfolio Optimization with Investment Bands use case.

PoIbtvData

Bases: UcData

Data for the Portfolio Optimization with Investment Bands use case.

Models a Markowitz-style mean-variance portfolio optimization where each asset has a minimum and maximum investment band. Continuous allocations are discretised using binary variables so the problem is suitable for QUBO/quantum solvers.

Attributes:

  • name (Literal['portfolio_optimization_with_investment_bands']) –

    Identifier for this data type.

  • log_returns (list[float]) –

    Expected log-return per asset. Positive values indicate expected gains, negative values indicate expected losses.

  • covariance_matrix (NumPyArray) –

    Symmetric positive semi-definite covariance matrix of shape (n_assets, n_assets). Entry [i,j] is the covariance between asset i and asset j. Diagonal entries are variances.

  • investment_bands (list[tuple[float, float]]) –

    (lower, upper) investment bounds per asset. Each allocation is constrained to lie within [lower, upper].

  • risk_aversion (float) –

    Risk aversion parameter lambda in the Markowitz objective: Higher values penalise variance more strongly. Default: 1.0.

  • max_budget (float) –

    Maximum total budget that can be allocated across all assets: sum_i investment[i] <= max_budget.

  • n_bits (int) –

    Number of binary bits used to discretise each asset's allocation within its investment band. Higher values give finer resolution but increase the number of binary variables (n_assets * n_bits).

plot(*, ax: Axes | None = None) -> Axes

Plot investment bands and expected returns per asset.

Shows a horizontal bar for each asset's investment band, colored per asset. The expected log-return is annotated to the right of each bar.

Parameters:

  • ax (Axes | None, default: None ) –

    Matplotlib axes to draw on. Creates a new figure if None.

Returns:

  • Axes

    The axes with the plot.

to_string() -> str

Return a human-readable description of the problem data.

Returns:

  • str

    String representation of the data including all parameters and per-asset investment bands and expected returns.

from_values(log_returns: list[float], covariance_matrix: np.ndarray, investment_bands: list[tuple[float, float]], max_budget: float, n_bits: int = 3, risk_aversion: float = 1.0) -> PoIbtvData staticmethod

Create a PoIbtvData instance from explicit problem parameters.

Parameters:

  • log_returns (list[float]) –

    Expected log-return per asset. Positive values indicate expected gains, negative values indicate expected losses.

  • covariance_matrix (ndarray) –

    Symmetric positive semi-definite covariance matrix of shape (n_assets, n_assets). Entry [i,j] represents the covariance between asset i and asset j. Diagonal entries are variances.

  • investment_bands (list[tuple[float, float]]) –

    (lower, upper) investment bounds per asset. Each allocation is constrained to [lower, upper]. Must have length n_assets.

  • max_budget (float) –

    Maximum total budget across all assets: sum_i investment[i] <= max_budget.

  • n_bits (int, default: 3 ) –

    Number of binary bits used to discretise each asset's allocation within its band. Higher values give finer resolution but increase the number of variables exponentially. Default: 3.

  • risk_aversion (float, default: 1.0 ) –

    Risk aversion parameter lambda in the Markowitz objective: Higher values penalise variance more strongly. Default: 1.0.

Returns:

  • PoIbtvData

    A validated data instance ready for optimisation.

Raises:

  • ValueError

    If any of the following conditions are violated:

    • covariance_matrix is not square
    • covariance_matrix shape does not match len(log_returns)
    • investment_bands length does not match len(log_returns)
    • Any lower bound exceeds its upper bound
    • max_budget is not positive
    • n_bits is not positive
    • risk_aversion is not positive

Examples:

>>> import numpy as np
>>> data = PoIbtvData.from_values(
...     log_returns=[0.05, 0.08, 0.03],
...     covariance_matrix=np.array(
...         [
...             [0.04, 0.01, 0.005],
...             [0.01, 0.09, 0.02],
...             [0.005, 0.02, 0.03],
...         ]
...     ),
...     investment_bands=[(0.1, 0.5), (0.1, 0.4), (0.1, 0.6)],
...     max_budget=1.0,
...     n_bits=3,
...     risk_aversion=1.0,
... )

generate_random(n_assets: int = 3, n_bits: int = 3, risk_aversion: float = 1.0, seed: int | None = None) -> PoIbtvData staticmethod

Generate a random PO-IBTV instance.

Creates a random portfolio problem with plausible return and covariance structure. Investment bands are sampled uniformly, and the covariance matrix is constructed to be positive semi-definite.

Parameters:

  • n_assets (int, default: 3 ) –

    Number of assets, by default 3.

  • n_bits (int, default: 3 ) –

    Number of binary bits per asset for discretisation, by default 3.

  • risk_aversion (float, default: 1.0 ) –

    Risk aversion parameter lambda controlling the trade-off between expected return and variance. Default: 1.0.

  • seed (int | None, default: None ) –

    Random seed for reproducibility, by default None.

Returns:

  • PoIbtvData

    A randomly generated data instance.

Examples:

>>> data = PoIbtvData.generate_random(n_assets=4, n_bits=3, seed=42)

Formulation

Formulation for Portfolio Optimization with Investment Bands use case.

PoIbtvFormulation

Bases: UcFormulation[PoIbtvData, PoIbtvSolution]

Formulation for Portfolio Optimization with Investment Bands.

Each asset's allocation is discretised within its investment band using n_bits binary variables. The objective is the Markowitz mean-variance formulation: maximise expected return minus risk-aversion-weighted variance.

The continuous allocation per asset is encoded as: investment[i] = lower[i] + step[i] * sum_q (2^q * x[i,q]) where step[i] = (upper[i] - lower[i]) / (2^n_bits - 1)

This allows a quantum solver to search over discretised allocations within the investment bands without requiring continuous variables.

Mathematical Formulation

Decision Variables: x[i,q] in {0,1} for asset i, bit q in 0..n_bits-1

Derived investment: investment[i] = lower[i] + step[i] * sum_q (2^q * x[i,q]) where step[i] = (upper[i] - lower[i]) / (2^n_bits - 1)

Objective (maximize): sum_i log_returns[i] * investment[i] - risk_aversion * sum_{i,j} sigma[i][j] * investment[i] * investment[j] where risk_aversion = 1 / (2 * target_volatility^2)

Constraints: 1. Budget: sum_i investment[i] <= max_budget

to_string(data: PoIbtvData) -> str staticmethod

Format the formulation as a string.

Parameters:

Returns:

  • str

    String representation of the formulation.

formulate(data: PoIbtvData) -> Model staticmethod

Formulate PO-IBTV as an optimization model.

Expands the continuous Markowitz objective fully into binary variables by substituting the discretised investment expression. The resulting objective contains linear and quadratic terms in x[i,q].

Parameters:

  • data (PoIbtvData) –

    The problem data containing returns, covariance, bands, and parameters.

Returns:

  • Model

    A Luna optimization model representing the investment band portfolio problem.

interpret(solution: Solution, data: PoIbtvData) -> PoIbtvSolution staticmethod

Extract solution from solver result.

Reconstructs the continuous allocation per asset from the binary variables and computes portfolio return, volatility, and validity.

Parameters:

  • solution (Solution) –

    The solution containing variable assignments.

  • data (PoIbtvData) –

    The original problem data.

Returns:

  • PoIbtvSolution

    A structured solution object with: - allocations: continuous allocation per asset - portfolio_return: expected return of the portfolio - portfolio_volatility: standard deviation of the portfolio - is_valid: whether investment bands and budget are satisfied

Raises:

Solution

Solution model for Portfolio Optimization with Investment Bands use case.

PoIbtvSolution

Bases: UcSolution

Solution for the Portfolio Optimization with Investment Bands use case.

Attributes:

  • name (Literal['portfolio_optimization_with_investment_bands']) –

    Identifier for this solution type.

  • allocations (list[float]) –

    Allocation fraction per asset (discretised).

  • portfolio_return (float) –

    Expected portfolio return.

  • portfolio_volatility (float) –

    Portfolio volatility (standard deviation).

  • is_valid (bool) –

    Whether the solution satisfies all constraints (allocations within bands, budget met).

plot(data: PoIbtvData, *, ax: Axes | None = None) -> Axes

Plot the portfolio allocation against investment bands.

Mirrors the data plot layout: horizontal bars show the investment bands (background) with the selected allocation overlaid as a marker, making it easy to see where each allocation falls within its band.

Parameters:

  • data (PoIbtvData) –

    The original problem data containing investment bands.

  • ax (Axes | None, default: None ) –

    Matplotlib axes to draw on. Creates a new figure if None.

Returns:

  • Axes

    The axes with the plot.

to_string() -> str

Return a string describing the PO-IBTV solution.

Instance

Instance model for PoIbtv use case.

PoIbtvInstance

Bases: UcInstance[PoIbtvData, PoIbtvFormulation, PoIbtvSolution]

Instance combining data and formulation for PoIbtv.

Collection

Collection of PO Investment Bands instances.

PoIbtvCollection

Bases: UcInstanceCollection[PoIbtvInstance]

Collection of PO Investment Bands instances.

This collection provides methods to generate benchmark instances with various characteristics for testing and evaluation.

from_random(min_assets: int = 2, max_assets: int = 5, n_bits: int = 3, num_instances: int = 1, *, seed: int | None = None) -> PoIbtvCollection classmethod

Generate random PO-IBTV instances.

Parameters:

  • min_assets (int, default: 2 ) –

    Minimum number of assets per instance (default: 2).

  • max_assets (int, default: 5 ) –

    Maximum number of assets per instance (default: 5).

  • n_bits (int, default: 3 ) –

    Number of binary bits per asset (default: 3).

  • num_instances (int, default: 1 ) –

    Number of instances per asset count (default: 1).

  • seed (int | None, default: None ) –

    Random seed for reproducibility (default: None).

Returns: