Aller au contenu principal

Quantum Portfolio Optimizer : une Qiskit Function par Global Data Quantum

remarque

Les Qiskit Functions sont une fonctionnalité expérimentale réservée aux utilisateurs des plans IBM Quantum® Premium, Flex et On-Prem (via l'API IBM Quantum Platform). Elles sont en version préliminaire et peuvent évoluer.

Vue d'ensemble

Le Quantum Portfolio Optimizer est une Qiskit Function qui s'attaque au problème d'optimisation dynamique de portefeuille, un problème classique en finance visant à rééquilibrer périodiquement des investissements sur un ensemble d'actifs afin de maximiser les rendements et de minimiser les risques. En déployant des techniques d'optimisation quantique de pointe, cette fonction simplifie le processus pour que les utilisateurs, sans expertise particulière en informatique quantique, puissent profiter de ses avantages dans la recherche de trajectoires d'investissement optimales. Idéal pour les gestionnaires de portefeuille, les chercheurs en finance quantitative et les investisseurs individuels, cet outil permet le backtesting de stratégies de trading dans le cadre de l'optimisation de portefeuille.

Description de la fonction

Le Quantum Portfolio Optimizer utilise l'algorithme Variational Quantum Eigensolver (VQE) pour résoudre un problème d'optimisation binaire quadratique sans contrainte (QUBO), en traitant des problèmes d'optimisation dynamique de portefeuille. Il suffit de fournir les données de prix des actifs et de définir la contrainte d'investissement ; la fonction exécute ensuite le processus d'optimisation quantique et retourne un ensemble de trajectoires d'investissement optimisées.

Le processus comporte quatre étapes principales. D'abord, les données d'entrée sont transformées en un problème compatible quantique : on construit le QUBO du problème d'optimisation dynamique de portefeuille et on le convertit en un opérateur quantique (Hamiltonien d'Ising). Ensuite, le problème d'entrée et l'algorithme VQE sont adaptés pour s'exécuter sur le matériel quantique. Le VQE est alors exécuté sur ce matériel, et enfin, les résultats sont post-traités pour fournir les trajectoires d'investissement optimales. Le système intègre également un post-traitement tenant compte du bruit (basé sur SQD) afin de maximiser la qualité des résultats.

Cette Qiskit Function est basée sur le manuscrit publié par Global Data Quantum. Visualisation du flux de travail de la fonction

Entrée

Les arguments d'entrée de la fonction sont décrits dans le tableau suivant. Les données des actifs et les autres spécifications du problème sont obligatoires ; les paramètres VQE peuvent être ajoutés pour personnaliser le processus d'optimisation.

NomTypeDescriptionRequisDéfautExemple
assetsjsonDictionnaire avec les prix des actifsOui--
qubo_settingsjsonParamètres du QUBOOui-Voir les exemples dans le tableau ci-dessous
ansatz_settingsjsonParamètres de l'ansatzNonNoneVoir les exemples dans le tableau ci-dessous.
optimizer_settingsjsonParamètres de l'optimiseurNonNoneVoir les exemples dans le tableau ci-dessous.
backendstrNom du backend QPUNon-"ibm_torino"
previous_session_idlist of strListe des identifiants de session pour récupérer des données des exécutions précédentes (*)NonListe vide["session_id_1", "session_id_2"]
apply_postprocessboolApplique le post-traitement SQD tenant compte du bruitNonTrueTrue
tagslist of stringsListe de tags pour identifier l'expérienceNonListe vide["optimization", "quantum_computing"]

Pour reprendre une exécution ou récupérer des jobs traités lors d'une ou plusieurs sessions précédentes, la liste des identifiants de session doit être passée dans le paramètre previous_session_id. Cela est particulièrement utile lorsqu'une tâche d'optimisation n'a pas pu se terminer en raison d'une erreur, et que l'exécution doit être finalisée. Pour ce faire, tu dois fournir les mêmes arguments que lors de l'exécution initiale, ainsi que la liste previous_session_id telle que décrite.

Avertissement

Le chargement des données des sessions précédentes (pour reprendre une optimisation) peut prendre jusqu'à une heure.

assets

Les données doivent être structurées sous forme d'objet JSON contenant les prix de clôture d'actifs financiers à des dates spécifiques. Le format est le suivant :

  • Clé primaire (chaîne de caractères) : le nom ou le symbole boursier de l'actif financier (par exemple, "8801.T").
  • Clé secondaire (chaîne de caractères) : la date au format AAAA-MM-JJ.
  • Valeur (nombre) : le prix de clôture de l'actif à la date indiquée. Les prix peuvent être saisis normalisés ou non normalisés.

Note : tous les dictionnaires doivent avoir la même clé secondaire (dates). Si un actif donné n'a pas de valeur pour une date présente chez les autres, les données doivent être complétées pour garantir la cohérence. Par exemple, on peut utiliser le dernier prix de clôture connu de cet actif.

Exemple

{
"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,
...
},
...
}
# Added by doQumentation — required packages for this notebook
!pip install -q pandas qiskit-ibm-catalog
{
"asset_name": {
"date": closing_value,
...
},
...
}
Note

Les données des actifs doivent contenir au minimum les prix de clôture à (nt+1) * dt (voir la section d'entrée qubo_settings) horodatages (par exemple, des jours).

qubo_settings

Le tableau suivant décrit les clés du dictionnaire qubo_settings. Construis le dictionnaire en spécifiant le nombre de pas de temps nt, le nombre de qubits de résolution nq et la valeur max_investment — ou modifie d'autres valeurs par défaut.

NomTypeDescriptionRequisDéfautExemple
ntintNombre de pas de tempsOui-4
nqintNombre de qubits de résolutionOui-4
max_investmentfloatNombre maximum d'unités de devise investies au total sur tous les actifsOui-10
dt*intFenêtre temporelle prise en compte à chaque pas de temps. L'unité correspond aux intervalles de temps entre les clés des données d'actifsNon30-
risk_aversionfloatCoefficient d'aversion au risqueNon1000-
transaction_feefloatCoefficient de frais de transactionNon0.01-
restriction_coefffloatMultiplicateur de Lagrange utilisé pour imposer la contrainte du problème dans la formulation QUBONon1-

ansatz_settings

Pour modifier les options par défaut, crée un dictionnaire pour le paramètre ansatz_settings avec les clés suivantes. Par défaut, l'ansatz est réglé sur "real_amplitudes" et les deux options supplémentaires (voir le tableau ci-dessous) sont à False.

NomTypeDescriptionRequisDéfaut
ansatz*strAnsatz à utiliserNon"real_amplitudes"
multiple_passmanager**boolActive la sous-routine multiple passmanager (non disponible pour l'ansatz Tailored)NonFalse
dd_enableboolAjoute le découplage dynamiqueNonFalse

* Ansatzes disponibles

  • real_amplitudes
  • cyclic
  • optimized_real_amplitudes
  • tailored (Uniquement pour le backend ibm_torino, 7 actifs, 4 pas de temps et 4 qubits de résolution)

** Si multiple_passmanager est réglé sur False, la fonction utilise le pass manager Qiskit par défaut avec optimization_level=3. S'il est réglé sur True, la sous-routine multiple_passmanager compare trois pass managers : le pass manager Qiskit par défaut précédent, un pass manager mappant les qubits sur la chaîne de premiers voisins du QPU, et les services du transpileur IA. Le pass manager dont l'erreur cumulée estimée est la plus faible est ensuite sélectionné.

optimizer_settings

Ce paramètre est un dictionnaire avec certaines options configurables du processus d'optimisation.

NomTypeDescriptionRequisDéfaut
primitive_optionsjsonParamètres de la primitiveNon-
optimizerstrOptimiseur classique sélectionnéNon"differential_evolution"
optimizer_optionsjsonConfiguration de l'optimiseurNon-
Note

Actuellement, le seul optimiseur disponible est "differential_evolution".

Sous les clés primitive_options et optimizer_options, on définit des dictionnaires avec les paramètres suivants :

primitive_options

NomTypeDescriptionRequisDéfautExemple
sampler_shotsintNombre de shots du Sampler.Non100000-
estimator_shotsintNombre de shots de l'Estimator.Non25000-
estimator_precisionfloatPrécision souhaitée de la valeur attendue. Si spécifiée, la précision sera utilisée à la place de estimator_shots.NonNone0.015625 · (1 / sqrt(4096))
max_timeint or strDurée maximale pendant laquelle une session Runtime peut rester ouverte avant d'être fermée de force. Peut être donné en secondes (int) ou sous forme de chaîne, comme "2h 30m 40s". Doit être inférieur au maximum imposé par le système.NonNone"1h 15m"

optimizer_options

NomTypeDescriptionRequisDéfaut
num_generationsintNombre de générationsNon20
population_sizeintTaille de la populationNon20
mutation_rangelistFacteur de mutation maximum et minimumNon[0, 0.25]
recombinationfloatFacteur de recombinaisonNon0.4
max_parallel_jobsintNombre maximum de jobs QPU exécutés en parallèleNon3
max_batchsizeintTaille maximale des lotsNon200
Note
  • Le nombre de générations évaluées par l'évolution différentielle est num_generations + 1, car la population initiale est incluse.

  • Le nombre total de circuits est calculé comme (num_generations + 1) * population_size.

  • Utiliser une population plus grande et davantage de générations améliore généralement la qualité des résultats d'optimisation. Cependant, il est déconseillé de dépasser une taille de population de 120 et un nombre de générations supérieur à 20 (par exemple, 120 * 21 = 2520 circuits au total), car cela générerait un nombre excessif de circuits, coûteux en calcul et en temps.

  • La fonction permet de reprendre une optimisation précédente, et il est toujours possible d'augmenter le nombre de générations (en fournissant les mêmes entrées, sauf pour previous_session_id et un num_generations augmenté).

Note

Assure-toi de respecter les limites de jobs Qiskit Runtime.

  • Sampler : sampler_shots <= 10_000_000.
  • Estimator : max_batchsize * estimator_shots * observable_size <= 10_000_000 (pour cette fonction, tous les termes de l'observable commutent, donc observable_size=1).

Consulte le guide Limites de jobs pour plus d'informations.

Sortie

La fonction retourne deux dictionnaires : le dictionnaire "result", qui contient les meilleurs résultats d'optimisation, y compris la solution optimale et son coût objectif minimal associé ; et "metadata", avec les données de tous les résultats obtenus au cours du processus d'optimisation, ainsi que leurs métriques respectives.

Le premier dictionnaire se concentre sur la solution la plus performante, tandis que le second fournit des informations détaillées sur toutes les solutions, notamment les coûts objectifs et d'autres métriques pertinentes.

Dictionnaires de sortie :

NomTypeDescriptionExemple
resultdict[str, dict[str, float]]Contient la stratégie d'investissement dans le temps, chaque horodatage étant associé aux poids d'investissement par actif (chaque poids est le montant investi normalisé par le montant total investi).{'time_1': {'asset_1': 0.2, 'asset_2': 0.3, ...\}, ...\}
metadatadict[str, Any]Données générées pendant l'analyse, incluant les solutions, les coûts et les métriques.Voir les exemples ci-dessous

Description du dictionnaire metadata

NomTypeDescriptionExemple
session_idstrIdentifiant unique de la session IBM Quantum."d0h30qjvpqf00084fgw0"
all_samples_metricsdictDictionnaire contenant diverses métriques pour chaque échantillon post-traité, telles que les coûts ou les contraintes.Voir la description ci-dessous
sampler_countsdict[str, int]Dictionnaire dont les clés sont des représentations binaires des solutions échantillonnées et les valeurs sont leurs comptages.{"101010": 3, "111000": 1\}
asset_orderlist[str]Liste indiquant l'ordre d'investissement des actifs à chaque pas de temps dans les stratégies d'investissement.["Asset_0", "Asset_1", "Asset_3"]
QUBOlist[list[float]]Matrice QUBO du problème.[[-6.96e-01, 5.81e-01, -1.26e-02, 0.00e+00], ...]
resource_summarydict[str, dict[str, float]]Résumé des temps d'utilisation CPU et QPU (en secondes) à différentes étapes du processus.{'RUNNING: EXECUTING_QPU': {'CPU_TIME': 412.84, 'QPU_TIME': 87.22\}, ...\}

Description du dictionnaire all_samples_metrics

NomTypeDescriptionExemple
investment_trajectorieslist[list]Stratégies d'investissement dérivées des états quantiques décodés.[[1, 2, 2], [1, 2, 1]]

| counts | list[int] | Nombre de fois que chaque trajectoire d'investissement a été échantillonnée. L'index correspond à investment_trajectories. | [5, 3] | | objective_costs | list[float] | Valeur de la fonction objectif pour chaque trajectoire d'investissement, triée du plus bas au plus élevé. | [0.98, 1.25] | | sharpe_ratios | list[float] | Performance ajustée au risque (ratio de Sharpe) pour chaque trajectoire d'investissement. Alignée par index. | [1.1, 0.7] | | returns | list[float] | Rendement attendu pour chaque trajectoire d'investissement. Aligné par index. | [0.15, 0.10] | | rest_breaches | list[float] | Déviation maximale de la contrainte au sein de chaque trajectoire d'investissement. Alignée par index. | [0.0, 0.25] | | transaction_costs | list[float] | Coût de transaction estimé associé à chaque trajectoire d'investissement. Aligné par index. | [0.01, 0.02] |

Prise en main

Authentifie-toi avec ta clé API et sélectionne la Qiskit Function comme suit. (Cet extrait suppose que tu as déjà enregistré ton compte dans ton environnement local.)

from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Access function
dpo_solver = catalog.load("global-data-quantum/quantum-portfolio-optimizer")

Exemple : optimisation dynamique de portefeuille avec sept actifs

Cet exemple montre comment exécuter la fonction d'optimisation dynamique de portefeuille (DPO) et ajuster ses paramètres pour des performances optimales. Il inclut des étapes détaillées pour affiner les paramètres et atteindre les résultats souhaités.

Ce cas implique sept actifs, quatre pas de temps et quatre qubits de résolution, pour un besoin total de 112 qubits.

1. Lire les actifs inclus dans le portefeuille.

Si tous les actifs du portefeuille sont stockés dans un dossier à un chemin spécifique, tu peux les charger dans un pandas.DataFrame et le convertir en objet dict à l'aide de la fonction suivante.

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()

Pour cet exemple, nous avons utilisé les actifs 8801.T, CLF, GBPJPY, ITX.MC, META, TMBMKDE-10Y et XS2239553048. La figure suivante illustre les données utilisées dans cet exemple, montrant l'évolution du prix de clôture journalier des actifs du 1er janvier au 1er septembre 2023.

Dans cet exemple, pour garantir l'uniformité entre les dates, nous avons comblé les jours non ouvrés avec le prix de clôture de la dernière date disponible. Cette étape est nécessaire car les actifs sélectionnés proviennent de différents marchés avec des jours de bourse variables, et il est essentiel de standardiser le jeu de données pour assurer la cohérence. Visualisation des données historiques des actifs

2. Définir le problème.

Définis les spécifications du problème en configurant les paramètres du dictionnaire 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. Définir les paramètres de l'optimiseur et de l'ansatz. (Optionnel)

Définis optionnellement des exigences spécifiques pour le processus d'optimisation, notamment le choix de l'optimiseur et de ses paramètres, ainsi que la spécification de la primitive et de ses configurations.

Pour l'ansatz Tailored, la taille de population choisie est basée sur des expériences précédentes montrant que cette valeur produit une optimisation stable et efficace.

Dans le cas de l'ansatz Real Amplitudes, tu peux suivre une relation linéaire entre la population_size et le nombre de qubits dans le circuit. À titre de règle empirique approximative, il est recommandé d'utiliser une population_size minimale ~ 0.8 * n_qubits pour l'ansatz real_amplitudes.

On s'attend à ce que l'Optimized Real Amplitudes offre de meilleures performances d'optimisation que l'ansatz Real Amplitudes. Cependant, le nombre de variables à optimiser dans cet ansatz augmente bien plus vite que dans le cas Real Amplitudes (voir le manuscrit). Ainsi, pour les grands problèmes, l'Optimized Real Amplitudes nécessite davantage d'exécutions de circuits. Il est susceptible d'être utile pour des problèmes jusqu'à 100 qubits, mais il est recommandé d'être attentif lors du réglage des paramètres population_size. À titre d'exemple de cette mise à l'échelle de population_size, le tableau précédent montre que pour un problème à 84 qubits, l'Optimized Real Amplitudes requiert une population_size de 120, tandis que pour un problème à 56 qubits, une population_size de 40 suffit.

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,
},
}

Il est également possible de choisir un ansatz spécifique. L'exemple suivant utilise l'ansatz 'Tailored'.

ansatz_settings = {
"ansatz": "tailored",
"multiple_passmanager": False,
}

4. Exécuter le problème.

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. Récupérer les résultats.

Comme mentionné dans la section Sortie, la fonction retourne un dictionnaire avec les trajectoires d'investissement triées du plus bas au plus élevé selon leur valeur de fonction objectif. Cet ensemble de résultats permet d'identifier la trajectoire au coût le plus bas et ses évaluations d'investissement correspondantes. De plus, il permet d'analyser différentes trajectoires, facilitant la sélection de celles qui correspondent le mieux à des besoins ou objectifs spécifiques. Cette flexibilité garantit que les choix peuvent être adaptés à une grande variété de préférences ou de scénarios. Commence par présenter la stratégie résultante ayant atteint le coût objectif le plus bas trouvé au cours du processus.

# Get the results of the job
dpo_result = dpo_job.result()

# Show the solution strategy
dpo_result["result"]
{'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}}

Ensuite, grâce aux métadonnées, tu peux accéder aux résultats de toutes les stratégies échantillonnées. Tu peux ainsi analyser plus en détail les trajectoires alternatives retournées par l'optimiseur. Pour ce faire, lis le dictionnaire stocké dans dpo_result['metadata']['all_samples_metrics'], qui contient non seulement des informations supplémentaires sur la stratégie optimale, mais aussi des détails sur les autres stratégies candidates évaluées durant l'optimisation.

L'exemple suivant montre comment lire ces informations avec pandas pour extraire les métriques clés associées à la stratégie optimale. Celles-ci comprennent la déviation de contrainte, le ratio de Sharpe et le rendement d'investissement correspondant.

# 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']}")
Minimum Objective Cost Found: -3.78
Best Solution:
- Restriction Deviation: 40.0
- Sharpe Ratio: 24.82
- Return: 0.46

6. Analyse des performances

Enfin, analyse les performances de ton application d'optimisation. Compare notamment tes résultats, obtenus dans l'exemple précédent, à une base de référence aléatoire pour évaluer l'efficacité de l'approche. Si l'algorithme quantique produit de manière démontrable et cohérente des résultats avec des valeurs de coût plus basses, cela indique un processus d'optimisation efficace.

La figure présente les distributions de probabilité des coûts objectifs. Pour générer ces distributions, on prend la liste des coûts objectifs issus du résultat de la fonction et on compte les occurrences de chaque valeur de coût (valeurs arrondies au deuxième décimal). On met ensuite à jour la colonne de comptage en regroupant les occurrences de valeurs arrondies identiques. Note que, pour une meilleure comparaison visuelle, les nombres d'occurrences ont été normalisés de sorte que chaque distribution soit affichée entre 0 et 1. Visualisation de la solution de l&#39;optimisation Comme le montre la figure (ligne bleue continue), la distribution des coûts pour notre approche Variational Quantum Eigensolver (post-traité avec SQD) est fortement concentrée sur des valeurs de coût objectif plus faibles, ce qui indique de bonnes performances d'optimisation. En revanche, la ligne de base bruitée présente une distribution plus large, centrée sur des valeurs de coût plus élevées. La ligne verticale grise en pointillés représente la valeur moyenne de la distribution aléatoire, soulignant davantage la cohérence de la fonction dans le retour de stratégies d'investissement optimisées. Pour une comparaison supplémentaire, la ligne noire en pointillés dans la figure correspond à la solution obtenue avec l'optimiseur Gurobi (version gratuite). Tous ces résultats sont explorés plus en détail dans les benchmarks ci-dessous pour l'exemple « Mixed Assets » évalué avec l'ansatz « Tailored ».

Benchmarks

Cette fonction a été testée sous différentes configurations de qubits de résolution, de circuits ansatz et de regroupements d'actifs issus de divers secteurs : un mélange d'actifs différents (Ensemble 1), des dérivés pétroliers (Ensemble 2) et l'IBEX35 (Ensemble 3). Voir plus de détails dans le tableau suivant.

EnsembleDateActifs
Ensemble 101/01/20238801.T, CL=F, GBPJPY=X, ITX.MC, META, TMBMKDE-10Y, XS2239553048
Ensemble 201/06/2023CL=F, BZ=F, HO=F, NG=F, XOM, RB=F, 2222.SR
Ensemble 301/11/2022ACS.MC, ITX.MC, FER.MC, ELE.MC, SCYR.MC, AENA.MC, AMS.MC

Deux métriques clés ont été utilisées pour évaluer la qualité des solutions.

  1. Le coût objectif, qui mesure l'efficacité de l'optimisation en comparant la valeur de la fonction de coût de chaque expérience aux résultats de Gurobi (version gratuite).
  2. Le ratio de Sharpe, qui capture le rendement ajusté au risque de chaque portefeuille, offrant un aperçu des performances financières des solutions.

Ensemble, ces métriques évaluent les aspects computationnels et financiers des portefeuilles générés par le quantique.

ExempleQubitsAnsatzProfondeurUtilisation Runtime (s)Utilisation totale (s)Coût objectifSharpeCoût objectif GurobiSharpe Gurobi
Mixed Assets (Ensemble 1, 4 pas, 4-bit)112Tailored831273513095-3.7824.82-4.2524.71
Mixed Assets (Ensemble 1, 4 pas, 4-bit)112Real Amplitudes3591173911903-3.3923.64-4.2524.71
Oil Derivatives (Ensemble 2, 4 pas, 3-bit)84Optimized Real Amplitudes7861806350-3.7319.13-4.1921.71
IBEX35 (Ensemble 3, 4 pas, 2-bit)56Optimized Real Amplitudes9633143523-3.6714.48-4.1116.44

Les résultats montrent que l'optimiseur quantique, avec des ansatzes spécifiques au problème, identifie efficacement des stratégies d'investissement performantes pour différents types de portefeuilles. Nous détaillons ci-dessous la taille de population et le nombre de générations spécifiés dans le dictionnaire optimizer_options. Tous les autres paramètres ont été laissés à leurs valeurs par défaut.

Exemplepopulation_sizenum_generations
Portefeuille Mixed Assets9020
Portefeuille Mixed Assets9220
Portefeuille Oil Derivatives12020
Portefeuille IBEX354020

Le nombre de générations a été fixé à 20, cette valeur s'étant avérée suffisante pour atteindre la convergence. De plus, les valeurs par défaut des paramètres internes de l'optimiseur ont été conservées telles quelles, car elles fournissent systématiquement de bonnes performances et sont généralement recommandées par la littérature et les directives d'implémentation.

Obtenir de l'aide

Si tu as besoin d'aide, tu peux envoyer un e-mail à qpo.support@globaldataquantum.com. Dans ton message, indique l'identifiant du job de la fonction.

Étapes suivantes

Recommandations