Optimizador de cartera cuántica: una función Qiskit de Global Data Quantum
Consulte la referencia de la API
Las funciones Qiskit son una función experimental disponible únicamente para los usuarios de los planes IBM Quantum® Premium Plan, Flex Plan y On-Prem (a través de IBM Quantum Platform API). Se trata de versiones preliminares sujetas a cambios.
Visión general
Quantum Portfolio Optimizer es una función de Qiskit que aborda el problema de la optimización dinámica de carteras, un problema estándar en finanzas cuyo objetivo es reequilibrar las inversiones periódicas en un conjunto de activos para maximizar la rentabilidad y minimizar los riesgos. Al utilizar técnicas de optimización cuántica de vanguardia, esta función simplifica el proceso para que los usuarios, sin conocimientos de informática cuántica, puedan beneficiarse de sus ventajas a la hora de encontrar trayectorias de inversión óptimas. Ideal para gestores de carteras, investigadores en finanzas cuantitativas e inversores particulares, esta herramienta permite realizar pruebas retrospectivas de estrategias de negociación en la optimización de carteras.
Descripción de la función
La función Quantum Portfolio Optimizer utiliza el algoritmo Variational Quantum Eigensolver (VQE) para resolver un problema de optimización binaria cuadrática sin restricciones (QUBO), abordando problemas dinámicos de optimización de carteras. Los usuarios sólo tienen que proporcionar los datos sobre el precio de los activos y definir la restricción de inversión; a continuación, la función ejecuta el proceso de optimización cuántica que devuelve un conjunto de trayectorias de inversión optimizadas.
El proceso consta de cuatro fases principales. En primer lugar, los datos de entrada se asignan a un problema compatible con la mecánica cuántica, construyéndose el QUBO del problema de optimización dinámica de carteras y transformándose en un operador cuántico (hamiltoniano de Ising). A continuación, se adaptan el problema de entrada y el algoritmo VQE para que puedan ejecutarse en el hardware cuántico. A continuación, el algoritmo VQE se ejecuta en el hardware cuántico y, por último, los resultados se someten a un procesamiento posterior para obtener las trayectorias de inversión óptimas. El sistema también incluye un posprocesamiento sensible al ruido ( basado en SQD) para maximizar la calidad del resultado.
Esta función Qiskit se basa en el manuscrito publicado por Global Data Quantum.
Cómo empezar
Inicia sesión con tu clave API y selecciona la función de Qiskit tal y como se indica a continuación. (En este fragmento de código se da por hecho que ya has guardado tu cuenta en tu entorno local.)
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Verify that you have access to the function
catalog.list()Output:
[QiskitFunction(qunova/hivqe-chemistry),
QiskitFunction(global-data-quantum/quantum-portfolio-optimizer),
QiskitFunction(algorithmiq/tem),
QiskitFunction(qedma/qesem),
QiskitFunction(multiverse/singularity),
QiskitFunction(ibm/circuit-function),
QiskitFunction(q-ctrl/optimization-solver),
QiskitFunction(colibritd/quick-pde),
QiskitFunction(q-ctrl/performance-management),
QiskitFunction(kipu-quantum/iskay-quantum-optimizer)]
# Access function
dpo_solver = catalog.load("global-data-quantum/quantum-portfolio-optimizer")Ejemplo: Optimización dinámica de cartera con siete activos
Este ejemplo muestra cómo ejecutar la función de optimización dinámica de carteras (OPC) y ajustar su configuración para obtener un rendimiento óptimo. Incluye pasos detallados para ajustar los parámetros y lograr los resultados deseados.
Este caso implica siete activos, cuatro pasos temporales y cuatro qubits de resolución, lo que da como resultado un requisito total de 112 qubits.
1. Lee los activos incluidos en la cartera
Si todos los activos de la cartera se almacenan en una carpeta en una ruta específica, puede cargarlos en un pandas.DataFrame y convertirlo en un objeto de formato dict utilizando la siguiente función.
import os
import glob
import pandas as pd
def read_and_join_csv(file_pattern):
"""
Reads multiple CSV files matching the file pattern and combines them
into a single DataFrame.
Parameters:
file_pattern (str): The pattern to match CSV files.
Returns:
pd.DataFrame: Combined DataFrame with data from all CSV files.
"""
# Find all files matching the pattern
csv_files = glob.glob(file_pattern)
# Get the base file names without the .csv extension
file_names = [os.path.basename(f).replace(".csv", "") for f in csv_files]
# Read each CSV file into a DataFrame and set the first column as the index
df_list = [pd.read_csv(f).set_index("Unnamed: 0") for f in csv_files]
# Rename columns in each DataFrame to the base file names
for df, name in zip(df_list, file_names):
df.columns = [name]
# Combine all DataFrames into one by merging them side by side
combined_df = pd.concat(df_list, axis=1)
return combined_df
file_pattern = "route/to/folder/with/assets/data/*.csv"
assets = read_and_join_csv(file_pattern).to_dict()Para este ejemplo, hemos utilizado los activos 8801.T, CLF, GBPJPY, ITX.MC, META, TMBMKDE-10Y y XS2239553048. La siguiente figura ilustra los datos utilizados en este ejemplo, mostrando la evolución diaria del precio de cierre de los activos desde el 1 de enero hasta el 1 de septiembre de 2023.
En este ejemplo, para garantizar la uniformidad entre fechas, hemos rellenado los días no hábiles con el precio de cierre de la fecha anterior disponible. Aplicamos este paso porque los activos seleccionados proceden de distintos mercados con días de negociación variables, por lo que es esencial estandarizar el conjunto de datos en aras de la coherencia.
2. Definir el problema
Defina las especificaciones del problema configurando los parámetros en el diccionario qubo_settings .
qubo_settings = {
"nt": 4,
"nq": 4,
"dt": 30,
"max_investment": 25,
"risk_aversion": 1000.0,
"transaction_fee": 0.01,
"restriction_coeff": 1.0,
}3. Definir los parámetros del optimizador y del ansatz (opcional)
Opcionalmente, defina requisitos específicos para el proceso de optimización, incluida la selección del optimizador y sus parámetros, así como la especificación de la primitiva y sus configuraciones.
Para el Tailored Ansatz, el tamaño de población elegido se basó en experimentos previos que mostraban que este valor produce una optimización estable y eficiente.
En el caso de la Ansatz de Amplitudes Reales, se puede seguir una relación lineal entre la population_size y el número de qubits del circuito. Como regla general aproximada, se recomienda utilizar un mínimo de population_size ~ 0.8 * n_qubits para el ansatz real_amplitudes .
Se espera que las Amplitudes Reales Optimizadas tengan un mejor rendimiento de optimización que el ansatz de Amplitudes Reales. Sin embargo, el número de variables a optimizar en este ansatz aumenta mucho más rápido que en el caso de Amplitudes Reales (véase el manuscrito ). Así, para problemas grandes, las Amplitudes Reales Optimizadas requieren más ejecuciones del circuito. Es probable que las Amplitudes Reales Optimizadas sean útiles para problemas que requieran hasta 100 qubits, pero se recomienda tener cuidado al configurar los parámetros de population_size . Como ejemplo de este escalado en population_size, la tabla anterior muestra que para un problema de 84 qubits, la Optimización de Amplitudes Reales requiere 120 population_size, mientras que para un problema de 56 qubits, es suficiente con population_size de 40.
optimizer_settings = {
"de_optimizer_settings": {
"num_generations": 20,
"population_size": 90,
"recombination": 0.4,
"max_parallel_jobs": 5,
"max_batchsize": 4,
"mutation_range": [0.0, 0.25],
},
"optimizer": "differential_evolution",
"primitive_settings": {
"estimator_shots": 25_000,
"estimator_precision": None,
"sampler_shots": 100_000,
},
}También es posible elegir un ansatz específico. A continuación se utiliza el ansatz de 'Tailored' .
ansatz_settings = {
"ansatz": "tailored",
"multiple_passmanager": False,
}4. Ejecuta el problema
dpo_job = dpo_solver.run(
assets=assets,
qubo_settings=qubo_settings,
optimizer_settings=optimizer_settings,
ansatz_settings=ansatz_settings,
backend_name="<backend name>",
previous_session_id=[],
apply_postprocess=True,
)5. Obtener los resultados
La función devuelve un diccionario con las trayectorias de inversión ordenadas de menor a mayor según el valor de su función objetivo (véase la sección «Resultados» de la referencia de la API). Este conjunto de resultados permite identificar la trayectoria de menor coste y las evaluaciones de inversión correspondientes. Además, permite analizar diferentes trayectorias, lo que facilita la selección de aquellas que mejor se ajustan a necesidades u objetivos específicos. Esta flexibilidad garantiza que las opciones se puedan adaptar a una gran variedad de preferencias o situaciones.
Comience presentando la estrategia resultante que haya logrado el menor coste objetivo encontrado durante el proceso.
# Get the results of the job
dpo_result = dpo_job.result()
# Show the solution strategy
dpo_result["result"]Output:
{'time_step_0': {'8801.T': 0.11764705882352941,
'ITX.MC': 0.20588235294117646,
'META': 0.38235294117647056,
'GBPJPY=X': 0.058823529411764705,
'TMBMKDE-10Y': 0.0,
'CLF': 0.058823529411764705,
'XS2239553048': 0.17647058823529413},
'time_step_1': {'8801.T': 0.11428571428571428,
'ITX.MC': 0.14285714285714285,
'META': 0.2,
'GBPJPY=X': 0.02857142857142857,
'TMBMKDE-10Y': 0.42857142857142855,
'CLF': 0.0,
'XS2239553048': 0.08571428571428572},
'time_step_2': {'8801.T': 0.0,
'ITX.MC': 0.09375,
'META': 0.3125,
'GBPJPY=X': 0.34375,
'TMBMKDE-10Y': 0.0,
'CLF': 0.0,
'XS2239553048': 0.25},
'time_step_3': {'8801.T': 0.3939393939393939,
'ITX.MC': 0.09090909090909091,
'META': 0.12121212121212122,
'GBPJPY=X': 0.18181818181818182,
'TMBMKDE-10Y': 0.0,
'CLF': 0.0,
'XS2239553048': 0.21212121212121213}}
Después, utilizando los metadatos, puede acceder a los resultados de todas las estrategias muestreadas. De este modo, puede seguir analizando las trayectorias alternativas devueltas por el optimizador. Para ello, lee el diccionario almacenado en dpo_result['metadata']['all_samples_metrics'], que contiene no sólo información adicional sobre la estrategia óptima, sino también detalles de las demás estrategias candidatas evaluadas durante la optimización.
El siguiente ejemplo muestra cómo leer esta información utilizando pandas para extraer las métricas clave asociadas a la estrategia óptima. Entre ellos se incluyen la Desviación de Restricción, el Ratio de Sharpe y el correspondiente rendimiento de la inversión.
# Convert metadata to a DataFrame
df = pd.DataFrame(dpo_result["metadata"]["all_samples_metrics"])
# Find the minimum objective cost
min_cost = df["objective_costs"].min()
print(f"Minimum Objective Cost Found: {min_cost:.2f}")
# Extract the row with the lowest cost
best_row = df[df["objective_costs"] == min_cost].iloc[0]
# Display the results associated with the best solution
print("Best Solution:")
print(f" - Restriction Deviation: {best_row['rest_breaches']}%")
print(f" - Sharpe Ratio: {best_row['sharpe_ratios']:.2f}")
print(f" - Return: {best_row['returns']}")Output:
Minimum Objective Cost Found: -3.78
Best Solution:
- Restriction Deviation: 40.0
- Sharpe Ratio: 24.82
- Return: 0.46
6. Análisis del rendimiento
Por último, analice el rendimiento de su aplicación de optimización. En concreto, compare sus resultados, obtenidos en el ejemplo anterior, con una línea de base aleatoria para evaluar la eficacia de nuestro enfoque. Si el algoritmo cuántico produce de forma demostrable y consistente resultados con valores de coste más bajos, indica un proceso de optimización eficaz.
La figura presenta las distribuciones de probabilidad de los costes objetivos. Para generar estas distribuciones, tome la lista de costes objetivos del resultado de la función y cuente las apariciones de cada valor de coste (valores redondeados al segundo decimal). A continuación, actualice la columna de recuento en consecuencia uniendo los recuentos de valores redondeados idénticos. Tenga en cuenta que, para una mejor comparación visual, los recuentos de ocurrencias se han normalizado de modo que cada distribución se muestre entre 0 y 1.
Como se muestra en la figura (línea continua azul), la distribución de costes para nuestro enfoque Variational Quantum Eigensolver (posprocesado con SQD) se concentra marcadamente en los valores de coste objetivo más bajos, lo que indica un buen rendimiento de la optimización. En cambio, la línea de base ruidosa muestra una distribución más amplia, centrada en los valores de coste más elevados. La línea vertical discontinua gris representa el valor medio de la distribución aleatoria, lo que pone aún más de relieve la coherencia de la función a la hora de devolver estrategias de inversión optimizadas. Para una comparación adicional, la línea negra discontinua de la figura corresponde a la solución obtenida con el optimizador Gurobi (versión gratuita). Todos estos resultados se analizan con más detalle en las pruebas comparativas que figuran a continuación para el ejemplo de "Activos mixtos" evaluado con el ansatz "Adaptado".
Referencias comparativas
Esta función se probó con distintas configuraciones de qubits de resolución, circuitos ansatz y agrupaciones de activos de varios sectores: una mezcla de distintos activos (Conjunto 1), derivados del petróleo (Conjunto 2) y IBEX35 (Conjunto 3). Consulte más detalles en la siguiente tabla.
Conjunto | Fecha | Activos |
|---|---|---|
| conjunto 1 | 01/01/2023 | 8801.T, CL=F, GBPJPY=X, ITX.MC, META, TMBMKDE-10Y, XS2239553048 |
| conjunto 2 | 01/06/2023 | CL=F, BZ=F, HO=F, NG=F, XOM, RB=F, 2222.SR |
| Conjunto 3 | 01/11/2022 | ACS.MC, ITX.MC, FER.MC, ELE.MC, SCYR.MC, AENA.MC, AMS.MC |
Para evaluar la calidad de las soluciones se utilizaron dos parámetros clave.
- El coste objetivo, que mide la eficacia de la optimización comparando el valor de la función de coste de cada experimento con los resultados de Gurobi (versión gratuita).
- El ratio de Sharpe, que refleja el rendimiento ajustado al riesgo de cada cartera y ofrece una visión del rendimiento financiero de las soluciones.
En conjunto, estas métricas sirven de referencia tanto para los aspectos computacionales como financieros de las carteras generadas cuánticamente.
Ejemplo | Qubits | Ansatz | Profundidad | Tiempo de ejecución (s) | Uso total (s) | Coste objetivo | Sharpe | Coste objetivo de Gurobi | Gurobi Sharpe |
|---|---|---|---|---|---|---|---|---|---|
| Activos mixtos (Set 1, 4 pasos de tiempo, 4 bits) | 112 | A medida | 83 | 12735 | 13095 | -3.78 | 24.82 | -4.25 | 24.71 |
| Activos mixtos (Set 1,4 pasos de tiempo, 4 pasos de tiempo, 4 bits) | 112 | Amplitudes reales | 359 | 11739 | 11903 | -3.39 | 23.64 | -4.25 | 24.71 |
| Derivados del petróleo (conjunto 2, 4 pasos temporales, 3 bits) | 84 | Amplitudes reales optimizadas | 78 | 6180 | 6350 | -3.73 | 19.13 | -4.19 | 21.71 |
| IBEX35 (Conjunto 3, 4 pasos temporales, 2 bits) | 56 | Amplitudes reales optimizadas | 96 | 3314 | 3523 | -3.67 | 14.48 | -4.11 | 16.44 |
Los resultados muestran que el optimizador cuántico, con ansatzes específicos para cada problema, identifica eficazmente estrategias de inversión eficientes en varios tipos de cartera.
A continuación detallamos tanto el tamaño de la población como el número de generaciones especificados en el diccionario optimizer_options . Todos los demás parámetros se ajustaron a sus valores por defecto.
Ejemplo | population_size | num_generations |
|---|---|---|
| Cartera de activos mixtos | 90 | 20 |
| Cartera de activos mixtos | 92 | 20 |
| Cartera de derivados del petróleo | 120 | 20 |
| IBEX35 Cartera | 40 | 20 |
El número de generaciones se fijó en 20, ya que se consideró que este valor era suficiente para alcanzar la convergencia. Además, no se modificaron los valores por defecto de los parámetros internos del optimizador, ya que siempre ofrecieron un buen rendimiento y, en general, son los recomendados por la bibliografía y las directrices de aplicación.
Obtener soporte
Si necesita ayuda, puede enviar un correo electrónico a globaldataquantum.com qpo.support En su mensaje, indique el identificador de la función.
Próximos pasos
- Lea el documento de investigación asociado.
-
- Consulta la referencia de la API de esta función de Qiskit.
- Solicite acceso a la función rellenando este formulario.
- Pruebe el tutorial Dynamic Portfolio Optimization.