Vai al contenuto principale

Quantum Portfolio Optimizer: Una Qiskit Function di Global Data Quantum

nota

Le Qiskit Functions sono una funzionalità sperimentale disponibile solo per gli utenti dei piani IBM Quantum® Premium, Flex e On-Prem (tramite IBM Quantum Platform API). Sono in stato di anteprima e soggette a modifiche.

Panoramica

Il Quantum Portfolio Optimizer è una Qiskit Function che affronta il problema dell'ottimizzazione dinamica del portafoglio, un problema standard in finanza che mira a ribilanciare periodicamente gli investimenti su un insieme di asset, massimizzando i rendimenti e minimizzando i rischi. Grazie all'impiego di tecniche di ottimizzazione quantistica all'avanguardia, questa funzione semplifica il processo in modo che gli utenti, anche senza competenze nel calcolo quantistico, possano beneficiare dei suoi vantaggi nella ricerca di traiettorie di investimento ottimali. Ideale per gestori di portafoglio, ricercatori in finanza quantitativa e investitori individuali, questo strumento consente il back-testing di strategie di trading nell'ottimizzazione del portafoglio.

Descrizione della funzione

La funzione Quantum Portfolio Optimizer utilizza l'algoritmo Variational Quantum Eigensolver (VQE) per risolvere un problema di ottimizzazione binaria quadratica non vincolata (QUBO), affrontando i problemi di ottimizzazione dinamica del portafoglio. Gli utenti devono semplicemente fornire i dati sui prezzi degli asset e definire il vincolo di investimento; la funzione esegue quindi il processo di ottimizzazione quantistica che restituisce un insieme di traiettorie di investimento ottimizzate.

Il processo si articola in quattro fasi principali. Prima di tutto, i dati di input vengono mappati su un problema compatibile con il calcolo quantistico, costruendo il QUBO del problema di ottimizzazione dinamica del portafoglio e trasformandolo in un operatore quantistico (Hamiltoniano di Ising). Successivamente, il problema di input e l'algoritmo VQE vengono adattati per essere eseguiti sull'hardware quantistico. L'algoritmo VQE viene poi eseguito sull'hardware quantistico e, infine, i risultati vengono post-elaborati per fornire le traiettorie di investimento ottimali. Il sistema include anche un post-processing noise-aware (basato su SQD) per massimizzare la qualità dell'output.

Questa Qiskit Function è basata sul manoscritto pubblicato da Global Data Quantum. Visualizzazione del flusso di lavoro della funzione

Input

Gli argomenti di input della funzione sono descritti nella tabella seguente. I dati degli asset e le altre specifiche del problema devono essere forniti; è inoltre possibile includere le impostazioni VQE per personalizzare il processo di ottimizzazione.

NomeTipoDescrizioneObbligatorioDefaultEsempio
assetsjsonDizionario con i prezzi degli assetSì--
qubo_settingsjsonImpostazioni del QUBOSì-Vedi gli esempi nella tabella seguente
ansatz_settingsjsonImpostazioni dell'ansatzNoNoneVedi gli esempi nella tabella seguente.
optimizer_settingsjsonImpostazioni dell'ottimizzatoreNoNoneVedi gli esempi nella tabella seguente.
backendstrNome del backend QPUNo-"ibm_torino"
previous_session_idlist of strLista degli ID di sessione per recuperare dati da esecuzioni precedenti(*)NoLista vuota["session_id_1", "session_id_2"]
apply_postprocessboolApplica il post-processing SQD noise-awareNoTrueTrue
tagslist of stringsLista di tag per identificare l'esperimentoNoLista vuota["optimization", "quantum_computing"]

*Per riprendere un'esecuzione o recuperare job elaborati in una o più sessioni precedenti, la lista degli ID di sessione deve essere passata nel parametro previous_session_id. Ciò è particolarmente utile nei casi in cui un'attività di ottimizzazione non è riuscita a completarsi a causa di un errore nel processo e l'esecuzione deve terminare. Per farlo, devi fornire gli stessi argomenti usati nell'esecuzione iniziale, insieme alla lista previous_session_id come descritto.

Attenzione

Il caricamento dei dati per le sessioni precedenti (per riprendere un'ottimizzazione) può richiedere fino a un'ora.

assets​

I dati devono essere strutturati come un oggetto JSON che memorizza informazioni sui prezzi di chiusura degli asset finanziari in date specifiche. Il formato è il seguente:

  • Chiave primaria (stringa): Il nome o il simbolo ticker dell'asset finanziario (ad esempio, "8801.T").
  • Chiave secondaria (stringa): La data nel formato YYYY-MM-DD.
  • Valore (numero): Il prezzo di chiusura dell'asset nella data specificata. I prezzi possono essere inseriti normalizzati o non normalizzati.

Nota: tutti i dizionari devono avere la stessa chiave secondaria (date). Se un asset specifico non ha una data presente negli altri, i dati devono essere completati per garantire la coerenza. Ad esempio, questo può essere fatto usando l'ultimo prezzo di chiusura registrato per quell'asset.

Esempio​

{
"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,
...
},
...
}
Nota

I dati degli asset devono contenere almeno i prezzi di chiusura in (nt+1) * dt (vedi la sezione di input qubo_settings) timestamp (ad esempio, giorni).

qubo_settings​

La tabella seguente descrive le chiavi del dizionario qubo_settings. Costruisci il dizionario specificando il numero di step temporali nt, il numero di qubit di risoluzione nq e il max_investment, oppure modifica gli altri valori predefiniti.

NomeTipoDescrizioneObbligatorioDefaultEsempio
ntintNumero di step temporaliSì-4
nqintNumero di qubit di risoluzioneSì-4
max_investmentfloatNumero massimo di unità di valuta investite su tutti gli assetSì-10
dt*intFinestra temporale considerata in ogni step. L'unità corrisponde agli intervalli temporali tra le chiavi nei dati degli assetNo30-
risk_aversionfloatCoefficiente di avversione al rischioNo1000-
transaction_feefloatCoefficiente della commissione di transazioneNo0.01-
restriction_coefffloatMoltiplicatore di Lagrange usato per imporre il vincolo del problema nella formulazione QUBONo1-

ansatz_settings​

Per modificare le opzioni predefinite, crea un dizionario per il parametro ansatz_settings con le seguenti chiavi. Per default, l'ansatz è impostato su "real_amplitudes" e entrambe le opzioni aggiuntive (vedi la tabella seguente) sono impostate su False.

NomeTipoDescrizioneObbligatorioDefault
ansatz*strAnsatz da utilizzareNo"real_amplitudes"
multiple_passmanager**boolAbilita la subroutine multiple passmanager (non disponibile per l'ansatz Tailored)NoFalse
dd_enableboolAggiunge il dynamical decouplingNoFalse

* Ansatz disponibili

  • real_amplitudes
  • cyclic
  • optimized_real_amplitudes
  • tailored (Solo per il backend ibm_torino, 7 asset, 4 step temporali e 4 qubit di risoluzione)

** Se multiple_passmanager è impostato su False, la funzione usa il pass manager predefinito di Qiskit con optimization_level=3. Se impostato su True, la subroutine multiple_passmanager confronta tre pass manager: il precedente pass manager predefinito di Qiskit, un pass manager che mappa i qubit sulla catena di vicini più prossimi del QPU, e i servizi AI transpiler. Viene quindi selezionato il pass manager con il minore errore cumulativo stimato.

optimizer_settings​

Questo parametro è un dizionario con alcune opzioni configurabili del processo di ottimizzazione.

NomeTipoDescrizioneObbligatorioDefault
primitive_optionsjsonImpostazioni della primitivaNo-
optimizerstrOttimizzatore classico selezionatoNo"differential_evolution"
optimizer_optionsjsonConfigurazione dell'ottimizzatoreNo-
Nota

Attualmente, l'unica opzione di ottimizzatore disponibile è "differential_evolution".

Nelle chiavi primitive_options e optimizer_options si impostano dizionari con i seguenti parametri:

primitive_options​

NomeTipoDescrizioneObbligatorioDefaultEsempio
sampler_shotsintNumero di shot del Sampler.No100000-
estimator_shotsintNumero di shot dell'Estimator.No25000-
estimator_precisionfloatPrecisione desiderata del valore atteso. Se specificata, verrà usata al posto di estimator_shots.NoNone0.015625 · (1 / sqrt(4096))
max_timeint or strDurata massima durante la quale una sessione di runtime può rimanere aperta prima di essere chiusa forzatamente. Può essere espressa in secondi (int) o come stringa, ad esempio "2h 30m 40s". Deve essere inferiore al massimo imposto dal sistema.NoNone"1h 15m"

optimizer_options​

NomeTipoDescrizioneObbligatorioDefault
num_generationsintNumero di generazioniNo20
population_sizeintDimensione della popolazioneNo20
mutation_rangelistFattore di mutazione massimo e minimoNo[0, 0.25]
recombinationfloatFattore di ricombinazioneNo0.4
max_parallel_jobsintNumero massimo di job QPU eseguiti in paralleloNo3
max_batchsizeintDimensione massima del batchNo200
Nota
  • Il numero di generazioni valutate dall'evoluzione differenziale è num_generations + 1, poiché la popolazione iniziale è inclusa.

  • Il numero totale di circuito è calcolato come (num_generations + 1) * population_size.

  • Usare una popolazione più grande e un maggior numero di generazioni migliora generalmente la qualità dei risultati dell'ottimizzazione. Tuttavia, non è consigliabile superare una dimensione di popolazione di 120 e un numero di generazioni maggiore di 20 (ad esempio, 120 * 21 = 2520 circuito totali), poiché ciò genererebbe un numero eccessivo di circuito, che può essere computazionalmente costoso e richiedere molto tempo.

  • La funzione ti consente di riprendere ottimizzazioni precedenti, ed è sempre possibile aumentare il numero di generazioni (fornendo lo stesso input ad eccezione di previous_session_id e un valore aumentato di num_generations).

Nota

Assicurati di rispettare i limiti dei job di Qiskit Runtime.

  • Sampler: sampler_shots <= 10_000_000.
  • Estimator: max_batchsize * estimator_shots * observable_size <= 10_000_000 (per questa funzione, tutti i termini dell'osservabile commutano, quindi observable_size=1).

Consulta la guida sui limiti dei job per ulteriori informazioni.

Output

La funzione restituisce due dizionari: il dizionario "result", che contiene i migliori risultati dell'ottimizzazione, inclusa la soluzione ottimale e il suo costo obiettivo minimo associato; e "metadata", con i dati di tutti i risultati ottenuti durante il processo di ottimizzazione, insieme alle rispettive metriche.

Il primo dizionario si concentra sulla soluzione con le migliori prestazioni, mentre il secondo fornisce informazioni dettagliate su tutte le soluzioni, inclusi i costi obiettivo e altre metriche rilevanti.

Dizionari di output:​

NomeTipoDescrizioneEsempio
resultdict[str, dict[str, float]]Contiene la strategia di investimento nel tempo, con ogni timestamp che mappa i pesi di investimento specifici per asset (ogni peso è l'importo di investimento normalizzato rispetto all'importo totale investito).{'time_1': {'asset_1': 0.2, 'asset_2': 0.3, ...\}, ...\}
metadatadict[str, Any]Dati generati durante l'analisi, inclusi soluzioni, costi e metriche.Vedi gli esempi di seguito

Descrizione del dizionario metadata​

NomeTipoDescrizioneEsempio
session_idstrIdentificatore univoco della sessione IBM Quantum."d0h30qjvpqf00084fgw0"
all_samples_metricsdictDizionario contenente varie metriche per ogni campione post-elaborato, come costi o vincoli.Vedi la descrizione di seguito
sampler_countsdict[str, int]Dizionario in cui le chiavi sono rappresentazioni in formato bitstring delle soluzioni campionate e i valori sono i loro conteggi.{"101010": 3, "111000": 1\}
asset_orderlist[str]Lista con l'ordine di investimento corrispondente degli asset per ogni step temporale all'interno delle strategie di investimento.["Asset_0", "Asset_1", "Asset_3"]
QUBOlist[list[float]]Matrice QUBO del problema.[[-6.96e-01, 5.81e-01, -1.26e-02, 0.00e+00], ...]
resource_summarydict[str, dict[str, float]]Riepilogo dei tempi di utilizzo CPU e QPU (in secondi) nelle diverse fasi del processo.{'RUNNING: EXECUTING_QPU': {'CPU_TIME': 412.84, 'QPU_TIME': 87.22\}, ...\}

Descrizione del dizionario all_samples_metrics​

NomeTipoDescrizioneEsempio
investment_trajectorieslist[list]Strategie di investimento derivate dagli stati quantistici decodificati.[[1, 2, 2], [1, 2, 1]]

| counts | list[int] | Numero di volte in cui ogni traiettoria di investimento è stata campionata. L'indice corrisponde a investment_trajectories. | [5, 3] | | objective_costs | list[float] | Valore della funzione obiettivo per ogni traiettoria di investimento, ordinato dal valore più basso al più alto. | [0.98, 1.25] | | sharpe_ratios | list[float] | Rendimento corretto per il rischio (indice di Sharpe) per ogni traiettoria di investimento. Allineato per indice. | [1.1, 0.7] | | returns | list[float] | Rendimento atteso per ogni traiettoria di investimento. Allineato per indice. | [0.15, 0.10] | | rest_breaches | list[float] | Deviazione massima dal vincolo all'interno di ogni traiettoria di investimento. Allineato per indice. | [0.0, 0.25] | | transaction_costs | list[float] | Costo di transazione stimato associato a ogni traiettoria di investimento. Allineato per indice. | [0.01, 0.02] |

Per iniziare

Autenticati usando la tua chiave API e seleziona la Qiskit Function come segue. (Questo snippet presuppone che tu abbia già salvato il tuo account nell'ambiente locale.)

from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

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

Esempio: ottimizzazione dinamica del portafoglio con sette asset​

Questo esempio mostra come eseguire la funzione di ottimizzazione dinamica del portafoglio (DPO) e regolare le sue impostazioni per ottenere le prestazioni ottimali. Include passaggi dettagliati per la messa a punto dei parametri al fine di ottenere i risultati desiderati.

Questo caso prevede sette asset, quattro step temporali e quattro qubit di risoluzione, per un requisito totale di 112 qubit.

1. Leggi gli asset inclusi nel portafoglio.​

Se tutti gli asset del portafoglio sono memorizzati in una cartella a un percorso specifico, puoi caricarli in un pandas.DataFrame e convertirlo in un oggetto in formato dict usando la seguente funzione.

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

Per questo esempio, abbiamo utilizzato gli asset 8801.T, CLF, GBPJPY, ITX.MC, META, TMBMKDE-10Y e XS2239553048. La figura seguente illustra i dati usati in questo esempio, mostrando l'evoluzione giornaliera del prezzo di chiusura degli asset dal 1° gennaio al 1° settembre 2023.

In questo esempio, per garantire l'uniformità tra le date, abbiamo compilato i giorni non di negoziazione con il prezzo di chiusura della data precedente disponibile. Applichiamo questo passaggio perché gli asset selezionati provengono da mercati diversi con giorni di negoziazione variabili, rendendo essenziale standardizzare il dataset per coerenza. Visualizzazione dei dati storici degli asset

2. Definisci il problema.​

Definisci le specifiche del problema configurando i parametri nel dizionario 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. Definisci le impostazioni dell'ottimizzatore e dell'ansatz. (Facoltativo)​

Facoltativamente, definisci i requisiti specifici per il processo di ottimizzazione, inclusa la selezione dell'ottimizzatore e dei suoi parametri, nonché la specifica della primitiva e delle sue configurazioni.

Per il Tailored Ansatz, la dimensione della popolazione scelta si basa su esperimenti precedenti che hanno dimostrato che questo valore produce un'ottimizzazione stabile ed efficiente.

Nel caso del Real Amplitudes Ansatz, puoi seguire una relazione lineare tra population_size e il numero di qubit nel circuito. Come regola empirica approssimativa, si consiglia di usare un population_size minimo ~ 0.8 * n_qubits per l'ansatz real_amplitudes.

Si prevede che l'Optimized Real Amplitudes abbia prestazioni di ottimizzazione migliori rispetto all'ansatz Real Amplitudes. Tuttavia, il numero di variabili da ottimizzare in questo ansatz cresce molto più rapidamente rispetto al caso Real Amplitudes (vedi il manoscritto). Pertanto, per problemi di grandi dimensioni, l'Optimized Real Amplitudes richiede più esecuzioni di circuito. L'Optimized Real Amplitudes è probabilmente utile per problemi fino a 100 qubit, ma si consiglia di essere prudenti nell'impostare i parametri population_size. Come esempio di questo aumento di scala in population_size, la tabella precedente mostra che per un problema a 84 qubit, l'Optimize Real Amplitudes richiede 120 di population_size, mentre per un problema a 56 qubit è sufficiente un population_size di 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,
},
}

È anche possibile scegliere un ansatz specifico. Il seguente usa l'ansatz 'Tailored'.

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

4. Esegui il 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. Recupera i risultati.​

Come indicato nella sezione Output, la funzione restituisce un dizionario con le traiettorie di investimento ordinate dalla più bassa alla più alta in base al valore della funzione obiettivo. Questo insieme di risultati consente di identificare la traiettoria con il costo più basso e le relative valutazioni di investimento. Inoltre, permette l'analisi di diverse traiettorie, facilitando la selezione di quelle più adatte alle esigenze o agli obiettivi specifici. Questa flessibilità garantisce che le scelte possano essere personalizzate per adattarsi a una varietà di preferenze o scenari. Inizia presentando la strategia risultante che ha raggiunto il costo obiettivo più basso trovato durante il processo.

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

Successivamente, usando i metadati, puoi accedere ai risultati di tutte le strategie campionate. Puoi quindi analizzare ulteriormente le traiettorie alternative restituite dall'ottimizzatore. Per farlo, leggi il dizionario memorizzato in dpo_result['metadata']['all_samples_metrics'], che contiene non solo informazioni aggiuntive sulla strategia ottimale, ma anche i dettagli delle altre strategie candidate valutate durante l'ottimizzazione.

Il seguente esempio mostra come leggere queste informazioni usando pandas per estrarre le metriche chiave associate alla strategia ottimale. Queste includono la Deviazione dal Vincolo, il Rapporto di Sharpe e il rendimento di investimento corrispondente.

# 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. Analisi delle prestazioni​

Infine, analizza le prestazioni della tua applicazione di ottimizzazione. In particolare, confronta i tuoi risultati, ottenuti nell'esempio precedente, con una baseline casuale per valutare l'efficacia del nostro approccio. Se l'algoritmo quantistico produce in modo dimostrabile e coerente risultati con valori di costo inferiori, ciò indica un processo di ottimizzazione efficace.

La figura presenta le distribuzioni di probabilità dei costi obiettivo. Per generare queste distribuzioni, prendi la lista dei costi obiettivo dal risultato della funzione e conta le occorrenze di ogni valore di costo (valori arrotondati alla seconda cifra decimale). Quindi, aggiorna la colonna dei conteggi di conseguenza unendo i conteggi dei valori arrotondati identici. Nota che, per una migliore comparazione visiva, i conteggi delle occorrenze sono stati normalizzati in modo che ogni distribuzione sia visualizzata tra 0 e 1. Visualizzazione della soluzione dell&#39;ottimizzazione Come mostrato nella figura (linea continua blu), la distribuzione dei costi per il nostro approccio Variational Quantum Eigensolver (post-elaborato con SQD) è concentrata nettamente su valori di costo obiettivo più bassi, indicando buone prestazioni di ottimizzazione. Al contrario, la baseline rumorosa mostra una distribuzione più ampia, centrata intorno a valori di costo più elevati. La linea verticale tratteggiata grigia rappresenta il valore medio della distribuzione casuale, evidenziando ulteriormente la coerenza della funzione nel restituire strategie di investimento ottimizzate. Come confronto aggiuntivo, la linea tratteggiata nera nella figura corrisponde alla soluzione ottenuta con l'ottimizzatore Gurobi (versione gratuita). Tutti questi risultati vengono ulteriormente esplorati nei benchmark seguenti per l'esempio "Mixed Assets" valutato con l'ansatz "Tailored".

Benchmark

Questa funzione è stata testata in diverse configurazioni di qubit di risoluzione, circuito ansatz e raggruppamenti di asset di vari settori: una combinazione di asset diversi (Set 1), derivati del petrolio (Set 2) e IBEX35 (Set 3). Vedi ulteriori dettagli nella tabella seguente.

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

Sono state utilizzate due metriche chiave per valutare la qualità della soluzione.

  1. Il costo obiettivo, che misura l'efficienza dell'ottimizzazione confrontando il valore della funzione di costo di ogni esperimento con i risultati di Gurobi (versione gratuita).
  2. L'indice di Sharpe, che cattura il rendimento corretto per il rischio di ogni portafoglio, offrendo una visione delle prestazioni finanziarie delle soluzioni.

Insieme, queste metriche confrontano sia gli aspetti computazionali che quelli finanziari dei portafogli generati con il metodo quantistico.

EsempioqubitAnsatzDepthUtilizzo Runtime (s)Utilizzo totale (s)Costo obiettivoSharpeCosto obiettivo GurobiSharpe Gurobi
Mixed Assets (Set 1, 4 step temporali, 4-bit)112Tailored831273513095-3.7824.82-4.2524.71
Mixed Assets (Set 1, 4 step temporali, 4 step temporali, 4-bit)112Real Amplitudes3591173911903-3.3923.64-4.2524.71
Oil Derivatives (Set 2, 4 step temporali, 3-bit)84Optimized Real Amplitudes7861806350-3.7319.13-4.1921.71
IBEX35 (Set 3, 4 step temporali, 2-bit)56Optimized Real Amplitudes9633143523-3.6714.48-4.1116.44

I risultati mostrano che l'ottimizzatore quantistico, con ansatz specifici per il problema, identifica efficacemente strategie di investimento efficienti in diversi tipi di portafoglio. Di seguito sono riportati i dettagli relativi alla dimensione della popolazione e al numero di generazioni specificati nel dizionario optimizer_options. Tutti gli altri parametri sono stati impostati ai valori predefiniti.

Esempiopopulation_sizenum_generations
Mixed Assets Portfolio9020
Mixed Assets Portfolio9220
Oil Derivatives Portfolio12020
IBEX35 Portfolio4020

Il numero di generazioni è stato impostato a 20, poiché questo valore è risultato sufficiente per raggiungere la convergenza. Inoltre, i valori predefiniti per i parametri interni dell'ottimizzatore sono stati lasciati invariati, poiché forniscono costantemente buone prestazioni e sono generalmente raccomandati dalla letteratura e dalle linee guida di implementazione.

Supporto

Se hai bisogno di aiuto, puoi inviare un'e-mail a qpo.support@globaldataquantum.com. Nel messaggio, fornisci l'ID del job della funzione.

Passi successivi​

Raccomandazioni