Sari la conținutul principal

Quantum Portfolio Optimizer: O Funcție Qiskit de la Global Data Quantum

Vezi referința API

notă

Funcțiile Qiskit sunt o funcționalitate experimentală disponibilă doar utilizatorilor planurilor IBM Quantum® Premium, Flex și On-Prem (prin API-ul IBM Quantum Platform). Acestea se află în stadiu de previzualizare și pot suferi modificări.

Prezentare generală

Quantum Portfolio Optimizer este o Funcție Qiskit care abordează problema optimizării dinamice a portofoliului, o problemă standard în finanțe ce urmărește reechilibrarea periodică a investițiilor într-un set de active, pentru a maximiza randamentele și a minimiza riscurile. Prin aplicarea tehnicilor de vârf din optimizarea cuantică, această funcție simplifică procesul astfel încât utilizatorii, fără expertiză în calculul cuantic, să poată beneficia de avantajele sale în identificarea traiectoriilor optime de investiție. Ideală pentru managerii de portofoliu, cercetătorii în finanțe cantitative și investitorii individuali, acest instrument permite back-testarea strategiilor de tranzacționare în optimizarea portofoliului.

Descrierea funcției

Funcția Quantum Portfolio Optimizer folosește algoritmul Variational Quantum Eigensolver (VQE) pentru a rezolva o problemă de Optimizare Binară Neconstrasă Pătratică (QUBO), abordând probleme de optimizare dinamică a portofoliului. Utilizatorii trebuie doar să furnizeze datele privind prețurile activelor și să definească constrângerea de investiție, după care funcția rulează procesul de optimizare cuantică ce returnează un set de traiectorii de investiție optimizate.

Procesul constă în patru etape principale. Mai întâi, datele de intrare sunt mapate într-o problemă compatibilă cu calculul cuantic, construindu-se qubo-ul problemei de optimizare dinamică a portofoliului și transformându-l într-un operator cuantic (Hamiltonianul Ising). Apoi, problema de intrare și algoritmul VQE sunt adaptate pentru a fi rulate pe hardware cuantic. Algoritmul VQE este apoi rulat pe hardware cuantic, iar în final, rezultatele sunt post-procesate pentru a furniza traiectoriile optime de investiție. Sistemul include, de asemenea, o post-procesare conștientă de zgomot (bazată pe SQD) pentru a maximiza calitatea rezultatelor.

Această Funcție Qiskit se bazează pe manuscrisul publicat de Global Data Quantum. Vizualizarea fluxului de lucru al funcției

Începe

Autentifică-te folosind cheia ta API și selectează Qiskit Function-ul după cum urmează. (Acest fragment presupune că ți-ai salvat deja contul în mediul tău local.)

# Added by doQumentation — required packages for this notebook
!pip install -q pandas qiskit-ibm-catalog
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

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

Exemplu: Optimizarea dinamică a portofoliului cu șapte active

Acest exemplu demonstrează cum să execuți funcția de optimizare dinamică a portofoliului (DPO) și cum să îi ajustezi setările pentru performanță optimă. Include pași detaliați pentru reglarea fină a parametrilor în vederea obținerii rezultatelor dorite.

Acest caz implică șapte active, patru pași de timp și patru qubiți de rezoluție, rezultând un total de 112 qubiți necesari.

1. Citește activele incluse în portofoliu.

Dacă toate activele din portofoliu sunt stocate într-un folder la o cale specifică, le poți încărca într-un pandas.DataFrame și le poți converti în obiect de tip dict folosind funcția de mai jos.

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

Pentru acest exemplu, am utilizat activele 8801.T, CLF, GBPJPY, ITX.MC, META, TMBMKDE-10Y și XS2239553048. Figura de mai jos ilustrează datele utilizate în acest exemplu, prezentând evoluția zilnică a prețului de închidere al activelor în perioada 1 ianuarie – 1 septembrie 2023.

În acest exemplu, pentru a asigura uniformitatea datelor, am completat zilele fără tranzacționare cu prețul de închidere din ziua disponibilă anterioară. Aplicăm acest pas deoarece activele selectate provin din piețe diferite cu zile de tranzacționare variate, fiind esențial să standardizăm setul de date pentru consistență. Visualization of the historical data of the assets

2. Definește problema.

Definește specificațiile problemei configurând parametrii din dicționarul 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. Definește setările Optimizer-ului și ale ansatz-ului (Opțional)

Opțional, poți defini cerințe specifice pentru procesul de optimizare, inclusiv alegerea Optimizer-ului și a parametrilor acestuia, precum și specificarea primitivei și a configurațiilor sale.

Pentru Tailored Ansatz, dimensiunea populației aleasă s-a bazat pe experimente anterioare care au arătat că această valoare produce o optimizare stabilă și eficientă.

În cazul Real Amplitudes Ansatz, poți urma o relație liniară între population_size și numărul de qubiți din Circuit. Ca regulă aproximativă orientativă, se recomandă utilizarea unui population_size minim ~ 0.8 * n_qubits pentru ansatz-ul real_amplitudes.

Se preconizează că Optimized Real Amplitudes va avea o performanță de optimizare mai bună decât ansatz-ul Real Amplitudes. Totuși, numărul de variabile de optimizat în acest ansatz crește mult mai rapid decât în cazul Real Amplitudes (a se vedea manuscrisul). Prin urmare, pentru probleme de mari dimensiuni, Optimized Real Amplitudes necesită mai multe execuții de circuit. Optimized Real Amplitudes este probabil util pentru probleme care necesită până la 100 de qubiți, însă se recomandă precauție la setarea parametrilor population_size. Ca exemplu al acestei scalări a population_size, tabelul anterior arată că pentru o problemă cu 84 de qubiți, Optimized Real Amplitudes necesită un population_size de 120, în timp ce pentru o problemă cu 56 de qubiți, un population_size de 40 este suficient.

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

De asemenea, este posibil să alegi un ansatz specific. Exemplul de mai jos folosește ansatz-ul 'Tailored'.

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

4. Rulează 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. Obține rezultatele

Funcția returnează un dicționar cu traiectoriile de investiții ordonate de la cea mai mică la cea mai mare valoare a funcției obiectiv (vezi secțiunea Output din referința API). Acest set de rezultate permite identificarea traiectoriei cu cel mai mic cost și a evaluărilor corespunzătoare ale investițiilor. În plus, oferă posibilitatea de a analiza diferite traiectorii, facilitând selectarea celor care se aliniază cel mai bine cu nevoile sau obiectivele specifice. Această flexibilitate asigură că alegerile pot fi adaptate pentru a corespunde unei varietăți de preferințe sau scenarii. Începe prin a prezenta strategia rezultată care a obținut cel mai mic cost obiectiv găsit în timpul procesului.

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

Ulterior, folosind metadatele, poți accesa rezultatele tuturor strategiilor eșantionate. Astfel, poți analiza în continuare traiectoriile alternative returnate de Optimizer. Pentru a face acest lucru, citește dicționarul stocat în dpo_result['metadata']['all_samples_metrics'], care conține nu doar informații suplimentare despre strategia optimă, ci și detalii despre celelalte strategii candidate evaluate în timpul optimizării.

Următorul exemplu arată cum să citești aceste informații folosind pandas pentru a extrage valorile cheie asociate strategiei optime. Acestea includ Deviația de Restricție, Raportul Sharpe și rentabilitatea corespunzătoare a investiției.

# 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. Analiza performanței

În final, analizează performanța aplicației tale de optimizare. Mai concret, compară rezultatele tale, obținute în exemplul anterior, cu o linie de bază aleatorie pentru a evalua eficacitatea abordării noastre. Dacă algoritmul cuantic produce în mod demonstrabil și consistent rezultate cu valori de cost mai mici, acest lucru indică un proces de optimizare eficient.

Figura prezintă distribuțiile de probabilitate ale costurilor obiectiv. Pentru a genera aceste distribuții, ia lista costurilor obiectiv din rezultatul funcției și numără aparițiile fiecărei valori de cost (valori rotunjite la a doua zecimală). Apoi, actualizează coloana de numărare în mod corespunzător, combinând numărătorile valorilor rotunjite identice. Rețineți că, pentru o mai bună comparație vizuală, numărătorile de apariții au fost normalizate astfel încât fiecare distribuție să fie afișată între 0 și 1. Vizualizarea soluției optimizării Așa cum se arată în figură (linia albastră continuă), distribuția costurilor pentru abordarea noastră bazată pe Variational Quantum Eigensolver (post-procesată cu SQD) este puternic concentrată la valori de cost obiectiv mai mici, indicând o bună performanță de optimizare. În contrast, linia de bază cu zgomot prezintă o distribuție mai largă, centrată în jurul unor valori de cost mai mari. Linia verticală gri punctată reprezintă valoarea medie a distribuției aleatoare, evidențiind și mai mult consistența funcției în returnarea strategiilor de investiții optimizate. Ca o comparație suplimentară, linia neagră punctată din figură corespunde soluției obținute cu optimizatorul Gurobi (versiunea gratuită). Toate aceste rezultate sunt explorate mai detaliat în benchmark-urile de mai jos pentru exemplul „Active Mixte" evaluat cu ansatz-ul „Tailored".

Benchmark-uri

Această funcție a fost testată în diferite configurații de qubiți de rezoluție, circuite ansatz și grupări de active din diverse sectoare: un mix de active diferite (Setul 1), derivative petroliere (Setul 2) și IBEX35 (Setul 3). Vezi mai multe detalii în tabelul următor.

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

Au fost utilizate două metrici cheie pentru a evalua calitatea soluției.

  1. Costul obiectiv, care măsoară eficiența optimizării comparând valoarea funcției de cost din fiecare experiment cu rezultatele din Gurobi (versiunea gratuită).
  2. Indicele Sharpe, care surprinde randamentul ajustat la risc al fiecărui portofoliu, oferind o perspectivă asupra performanței financiare a soluțiilor.

Împreună, aceste metrici servesc drept benchmark atât pentru aspectele computaționale, cât și pentru cele financiare ale portofoliilor generate cuantic.

ExempluQubițiAnsatzAdâncimeUtilizare Runtime (s)Utilizare totală (s)Cost obiectivSharpeCost obiectiv GurobiSharpe Gurobi
Active Mixte (Setul 1, 4 pași de timp, 4 biți)112Tailored831273513095-3.7824.82-4.2524.71
Active Mixte (Setul 1, 4 pași de timp, 4 pași de timp, 4 biți)112Real Amplitudes3591173911903-3.3923.64-4.2524.71
Derivative Petroliere (Setul 2, 4 pași de timp, 3 biți)84Optimized Real Amplitudes7861806350-3.7319.13-4.1921.71
IBEX35 (Setul 3, 4 pași de timp, 2 biți)56Optimized Real Amplitudes9633143523-3.6714.48-4.1116.44

Rezultatele arată că Optimizer-ul cuantic, cu ansatz-uri specifice problemei, identifică eficient strategii de investiții eficiente pentru diverse tipuri de portofolii. Mai jos detaliem atât dimensiunea populației, cât și numărul de generații specificate în dicționarul optimizer_options. Toți ceilalți parametri au fost setați la valorile lor implicite.

Exemplupopulation_sizenum_generations
Portofoliu Active Mixte9020
Portofoliu Active Mixte9220
Portofoliu Derivative Petroliere12020
Portofoliu IBEX354020

Numărul de generații a fost setat la 20, deoarece s-a constatat că această valoare este suficientă pentru a atinge convergența. În plus, valorile implicite pentru parametrii interni ai optimizatorului au rămas neschimbate, deoarece acestea au furnizat în mod constant performanțe bune și sunt în general recomandate de literatura de specialitate și ghidurile de implementare.

Obține suport

Dacă ai nevoie de ajutor, poți trimite un e-mail la qpo.support@globaldataquantum.com. În mesajul tău, furnizează ID-ul jobului funcției.

Pașii următori

Recomandări