Quantum Portfolio Optimizer API reference
Qiskit Functions — pre-built tools created by partner organizations — abstract away parts of the software development workflow to simplify and accelerate utility-scale algorithm discovery and application development. Click to view the guide for this Qiskit Function.
Quantum Portfolio Optimizer Qiskit Function guide
Input
The input arguments of the function are described in the following list. The assets data and other problem specifications must be provided; additionally, the VQE settings can be included to customize the optimization process.
assets
Type: `json`
Dictionary with the asset prices. The data must be structured as a JSON object that stores information about the closing prices of financial assets on specific dates. The format is as follows:
- Primary key (string): The name or ticker symbol of the financial asset (for example, "8801.T").
- Secondary key (string): The date in YYYY-MM-DD format.
- Value (number): The closing price of the asset on the specified date. Prices can be entered either normalized or non-normalized.
Note that all dictionaries must have the same secondary key (dates). If a specific asset lacks a date that others have, the data must be filled to ensure consistency. For example, this can be done by using the last tracked closing price of that asset.
- Required: Yes
- Example:
{
"8801.T": {
"2023-01-01": 2374.0,
"2023-01-02": 2374.0,
"2023-01-03": 2374.0,
"2023-01-04": 2356.5,
...
},
"AAPL": {
"2023-01-01": 145.2,
"2023-01-02": 146.5,
"2023-01-03": 147.3,
"2023-01-04": 148.1,
...
},
...
}{
"asset_name": {
"date": closing_value,
...
},
...
}The asset data must contain, at least, the closing prices at (nt+1) * dt (see the qubo_settings input section) time stamps (for example, days).
qubo_settings
Type: `json`
Settings of the QUBO. The following table describes the keys of the qubo_settings dictionary. Build the dictionary specifying the number of time steps nt, the number of resolution qubits nq, and the max_investment - or change other default values.
Name | Type | Description | Required | Default | Example |
|---|---|---|---|---|---|
nt | int | Number of time steps | Yes | - | 4 |
nq | int | Number of resolution qubits | Yes | - | 4 |
max_investment | float | Maximum number of invested currency units across all assets | Yes | - | 10 |
dt* | int | Time window considered in each time step. The unit matches the time intervals between the keys in the asset data | No | 30 | - |
risk_aversion | float | Risk aversion coefficient | No | 1000 | - |
transaction_fee | float | Transaction fee coefficient | No | 0.01 | - |
restriction_coeff | float | Lagrange multiplier used to enforce the problem constraint within the QUBO formulation | No | 1 | - |
- Required: Yes
ansatz_settings
Type: `json`
Default value: `None`
Settings of the ansatz. To modify the default options, create a dictionary for the ansatz_settings parameter with the following keys. By default, the ansatz is set to "real_amplitudes", and both extra options (see the following table) are set to False.
Name | Type | Description | Required | Default |
|---|---|---|---|---|
ansatz* | str | Ansatz to be used | No | "real_amplitudes" |
multiple_passmanager** | bool | Enables multiple passmanager subroutine (not available for Tailored ansatz) | No | False |
dd_enable | bool | Adds dynamical decoupling | No | False |
* Available ansatzes
real_amplitudescyclicoptimized_real_amplitudestailored(Only foribm_torinobackend, 7 assets, 4 time steps, and 4 resolution qubits)
** If multiple_passmanager is set to False, the function uses the default Qiskit pass manager with optimization_level=3. If set to True, the multiple_passmanager subroutine compares three pass managers: the previous default Qiskit pass manager, a pass manager mapping qubits over the QPU first neighbors chain, and the AI transpiler services. Then, the pass manager with the estimated lower cumulative error is selected.
- Required: No
optimizer_settings
Type: `json`
Default value: `None`
Settings of the optimizer. This parameter is a dictionary with some tunable options of the optimizing process.
Name | Type | Description | Required | Default |
|---|---|---|---|---|
primitive_options | json | Settings of the primitive | No | - |
optimizer | str | Selected classical optimizer | No | "differential_evolution" |
optimizer_options | json | Configuration of the optimizer | No | - |
Currently, the only optimizer option available is "differential_evolution".
Under primitive_options and optimizer_options keys we set dictionaries with the following parameters:
primitive_options
Name | Type | Description | Required | Default | Example |
|---|---|---|---|---|---|
sampler_shots | int | Number of shots of the Sampler. | No | 100000 | - |
estimator_shots | int | Number of shots of the Estimator. | No | 25000 | - |
estimator_precision | float | Desired precision of the expected value. If specified, the precision will be used instead of the estimator_shots. | No | None | 0.015625 · (1 / sqrt(4096)) |
max_time | int or str | Maximum amount of time a runtime session can remain open before being forcibly closed. Can be given in seconds (int) or as a string, like "2h 30m 40s". Must be less than the system-imposed maximum. | No | None | "1h 15m" |
optimizer_options
Name | Type | Description | Required | Default |
|---|---|---|---|---|
num_generations | int | Number of generations | No | 20 |
population_size | int | Size of the population | No | 20 |
mutation_range | list | Maximum and minimum mutation factor | No | [0, 0.25] |
recombination | float | Recombination factor | No | 0.4 |
max_parallel_jobs | int | Maximum number of QPU jobs executed in parallel | No | 3 |
max_batchsize | int | Maximum batch size | No | 200 |
-
The number of generations evaluated by the differential evolution is
num_generations+ 1 since the initial population is included. -
The total number of circuits is calculated as
(num_generations + 1) * population_size. -
Using a larger population size and more generations generally improves the quality of the optimization results. However, it is not recommended to exceed a population size of 120 and a number of generations greater than 20 (for example,
120 * 21 = 2520total circuits), as this would generate an excessive number of circuits, which can be computationally expensive and time-consuming to process. -
The function allows you to resume previous optimization, and it is always possible to increase the number of generations (by providing the same input except for
previous_session_idand an increasednum_generations).
- Required: No
backend
Type: `str`
The QPU backend name
- Required: No
- Example:
ibm_torino
previous_session_id
Type: `list` of `str`
Default value: Empty list
List of session IDs to retrieve data from previous runs. To resume an execution or retrieve jobs that were processed in one or more previous sessions, the list of session IDs must be passed in the previous_session_id parameter. This is particularly useful in cases where an optimization task failed to complete due to any error in the process, and execution needs to finish. To achieve this, you must provide the same arguments used in the initial execution, along with the previous_session_id list as described.
- Required: No
- Example:
["session_id_1", "session_id_2"]
apply_postprocess
Type: `bool`
Default value: `True`
Apply noise-aware SQD post-processing.
- Required: No
- Example:
True
tags
Type: `list` of `str`
Default value: Empty list
List of tags to identify the experiment.
- Required: No
- Example:
["optimization", "quantum_computing"]
Loading data from previous sessions (to resume an optimization) can take up to one hour of classical computational time. This does not consume quantum runtime resources.
Ensure compliance with Qiskit Runtime job limits.
- Sampler:
sampler_shots <= 10_000_000. - Estimator:
max_batchsize * estimator_shots * observable_size <= 10_000_000(for this function, all the terms of the observable commute, soobservable_size=1).
See the Job limits guide for more information.
Output
The function returns two dictionaries: "result" dictionary, containing the best optimization results, including the optimal solution and its associated minimum objective cost; and "metadata", with data from all results obtained during the optimization process, along with their respective metrics.
The first dictionary focuses on the best-performing solution, while the second provides detailed information about all solutions, including objective costs and other relevant metrics.
result dictionary
Type: dict[str, dict[str, float]]
Contains the investment strategy over time, with each time-stamp mapping to asset-specific investment weights (each weight is the investment amount normalized by the total investment amount).
- Example:
{'time_1': {'asset_1': 0.2, 'asset_2': 0.3, ...}, ...}
metadata dictionary
Type: dict[str, Any]
Data generated during the analysis, including solutions, costs, and metrics.
Name | Type | Description | Example |
|---|---|---|---|
session_id | str | Unique identifier for the IBM Quantum session. | "d0h30qjvpqf00084fgw0" |
all_samples_metrics | dict | Dictionary containing various metrics for each postprocessed sample, such as costs or constraints. | See description |
sampler_counts | dict[str, int] | Dictionary where keys are bitstring representations of sampled solutions and values are their counts. | {"101010": 3, "111000": 1} |
asset_order | list[str] | List with the corresponding investment order of assets at each time step within the investment strategies. | ["Asset_0", "Asset_1", "Asset_3"] |
QUBO | list[list[float]] | QUBO matrix of the problem. | [[-6.96e-01, 5.81e-01, -1.26e-02, 0.00e+00], ...] |
resource_summary | dict[str, dict[str, float]] | Summary of CPU and QPU usage times (in seconds) across different stages of the process. | {'RUNNING: EXECUTING_QPU': {'CPU_TIME': 412.84, 'QPU_TIME': 87.22}, ...} |
Description of the all_samples_metrics dictionary
Name | Type | Description | Example |
|---|---|---|---|
investment_trajectories | list[list] | Investment strategies derived from decoded quantum states. | [[1, 2, 2], [1, 2, 1]] |
counts | list[int] | Number of times each investment trajectory was sampled. Index matches investment_trajectories. | [5, 3] |
objective_costs | list[float] | Value of the objective function for each investment trajectory, ordered from lowest to highest. | [0.98, 1.25] |
sharpe_ratios | list[float] | Risk-adjusted performance (Sharpe ratio) for each investment trajectory. Aligned by index. | [1.1, 0.7] |
returns | list[float] | Expected return for each investment trajectory. Aligned by index. | [0.15, 0.10] |
rest_breaches | list[float] | Maximum constraint deviation within each investment trajectory. Aligned by index. | [0.0, 0.25] |
transaction_costs | list[float] | Estimated transaction cost associated with each investment trajectory. Aligned by index. | [0.01, 0.02] |