Lakukan pengoptimuman portfolio dinamik dengan Portfolio Optimizer daripada Global Data Quantum
Qiskit Functions adalah ciri eksperimental yang hanya tersedia untuk pengguna pelan IBM Quantum® Premium Plan, Flex Plan, dan On-Prem (melalui IBM Quantum Platform API). Ia berada dalam status keluaran pratonton dan tertakluk kepada perubahan.
Anggaran penggunaan: Lebih kurang 55 minit pada pemproses Heron r2. (NOTA: Ini hanyalah anggaran sahaja. Masa sebenar mungkin berbeza.)
Latar Belakang
Masalah pengoptimuman portfolio dinamik bertujuan untuk mencari strategi pelaburan terbaik merentasi pelbagai tempoh masa bagi memaksimumkan pulangan portfolio yang dijangkakan dan meminimumkan risiko, selalunya di bawah kekangan tertentu seperti bajet, kos transaksi, atau penolakan risiko. Berbeza dengan pengoptimuman portfolio standard yang hanya mempertimbangkan satu masa untuk menyeimbangkan semula portfolio, versi dinamik mengambil kira sifat aset yang sentiasa berubah dan menyesuaikan pelaburan berdasarkan perubahan prestasi aset dari semasa ke semasa.
Tutorial ini menunjukkan cara untuk melakukan pengoptimuman portfolio dinamik menggunakan Fungsi Qiskit Quantum Portfolio Optimizer. Secara khususnya, kami menjelaskan cara menggunakan fungsi aplikasi ini untuk menyelesaikan masalah peruntukan pelaburan merentasi pelbagai langkah masa.
Pendekatan ini melibatkan pemformulasian pengoptimuman portfolio sebagai masalah Quadratic Unconstrained Binary Optimization (QUBO) berbilang objektif. Secara khususnya, kami memformulasikan fungsi QUBO untuk mengoptimumkan empat objektif berbeza secara serentak:
- Memaksimumkan fungsi pulangan
- Meminimumkan risiko pelaburan
- Meminimumkan kos transaksi
- Mematuhi sekatan pelaburan, dirumuskan dalam sebutan tambahan untuk diminimumkan .
Ringkasnya, bagi menangani objektif-objektif ini kami memformulasikan fungsi QUBO sebagai di mana ialah pekali penolakan risiko dan ialah pekali pengukuhan sekatan (pendarab Lagrange). Formulasi eksplisit boleh didapati dalam Pers. (15) manuskrip kami [1].
Kami menyelesaikan masalah ini menggunakan kaedah kuantum-klasik hibrid berdasarkan Variational Quantum Eigensolver (VQE). Dalam tetapan ini, Circuit kuantum menganggarkan fungsi kos, manakala pengoptimuman klasik dilakukan menggunakan algoritma Differential Evolution, membolehkan navigasi lanskap penyelesaian yang cekap. Bilangan Qubit yang diperlukan bergantung kepada tiga faktor utama: bilangan aset na, bilangan tempoh masa nt, dan resolusi bit yang digunakan untuk mewakili pelaburan nq. Khususnya, bilangan minimum Qubit dalam masalah kami ialah na*nt*nq.
Untuk tutorial ini, kami menumpukan pada pengoptimuman portfolio serantau berdasarkan indeks IBEX 35 Sepanyol. Khususnya, kami menggunakan portfolio tujuh aset seperti yang ditunjukkan dalam jadual di bawah:
| Portfolio IBEX 35 | ACS.MC | ITX.MC | FER.MC | ELE.MC | SCYR.MC | AENA.MC | AMS.MC |
|---|
Kami menyeimbangkan semula portfolio kami dalam empat langkah masa, setiap satu dipisahkan oleh selang 30 hari bermula 1 November 2022. Setiap pemboleh ubah pelaburan dikodkan menggunakan dua bit. Ini menghasilkan masalah yang memerlukan 56 Qubit untuk diselesaikan.
Kami menggunakan ansatz Optimized Real Amplitudes, satu adaptasi perkakasan yang disesuaikan dan cekap daripada ansatz Real Amplitudes standard, khusus direka untuk meningkatkan prestasi bagi jenis masalah pengoptimuman kewangan ini.
Pelaksanaan kuantum dilakukan pada Backend ibm_torino. Untuk penjelasan terperinci tentang formulasi masalah, metodologi, dan penilaian prestasi, rujuk manuskrip yang diterbitkan [1].
Keperluan
# Added by doQumentation — required packages for this notebook
!pip install -q numpy
!pip install qiskit-ibm-catalog
!pip install pandas
!pip install matplotlib
!pip install yfinance
Persediaan
Untuk menggunakan Quantum Portfolio Optimizer, pilih fungsi melalui Katalog Fungsi Qiskit. Anda memerlukan akaun IBM Quantum Premium Plan atau Flex Plan dengan lesen daripada Global Data Quantum untuk menjalankan fungsi ini.
Pertama, sahkan diri dengan kunci API anda. Kemudian, muatkan fungsi yang dikehendaki dari Katalog Fungsi Qiskit. Di sini, anda mengakses fungsi quantum_portfolio_optimizer dari katalog menggunakan kelas QiskitFunctionsCatalog. Fungsi ini membolehkan kami menggunakan penyelesai Quantum Portfolio Optimization yang telah ditetapkan.
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(
channel="ibm_quantum_platform",
instance="INSTANCE_CRN",
token="YOUR_API_KEY", # Use the 44-character API_KEY you created and saved from the IBM Quantum Platform Home dashboard
)
# Access function
dpo_solver = catalog.load("global-data-quantum/quantum-portfolio-optimizer")
Langkah 1: Baca portfolio input
Dalam langkah ini, kami memuatkan data sejarah untuk tujuh aset yang dipilih daripada indeks IBEX 35, khususnya dari 1 November 2022 hingga 1 April 2023.
Kami mendapatkan data menggunakan API Yahoo Finance, dengan fokus pada harga penutupan. Data kemudian diproses untuk memastikan semua aset mempunyai bilangan hari data yang sama. Sebarang data yang hilang (hari bukan dagangan) dikendalikan dengan sewajarnya, memastikan semua aset diselaraskan pada tarikh yang sama.
Data distrukturkan dalam DataFrame dengan format yang konsisten merentasi semua aset.
import yfinance as yf
import pandas as pd
# List of IBEX 35 symbols
symbols = [
"ACS.MC",
"ITX.MC",
"FER.MC",
"ELE.MC",
"SCYR.MC",
"AENA.MC",
"AMS.MC",
]
start_date = "2022-11-01"
end_date = "2023-4-01"
series_list = []
symbol_names = [symbol.replace(".", "_") for symbol in symbols]
# Create a full date index including weekends
full_index = pd.date_range(start=start_date, end=end_date, freq="D")
for symbol, name in zip(symbols, symbol_names):
print(f"Downloading data for {symbol}...")
data = yf.download(symbol, start=start_date, end=end_date)["Close"]
data.name = name
# Reindex to include weekends
data = data.reindex(full_index)
# Fill missing values (for example, weekends or holidays) by forward/backward fill
data.ffill(inplace=True)
data.bfill(inplace=True)
series_list.append(data)
# Combine all series into a single DataFrame
df = pd.concat(series_list, axis=1)
# Convert index to string for consistency
df.index = df.index.astype(str)
# Convert DataFrame to dictionary
assets = df.to_dict()
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
Downloading data for ACS.MC...
Downloading data for ITX.MC...
Downloading data for FER.MC...
Downloading data for ELE.MC...
Downloading data for SCYR.MC...
Downloading data for AENA.MC...
Downloading data for AMS.MC...
Langkah 2: Tentukan input masalah
Parameter yang diperlukan untuk mentakrifkan masalah QUBO dikonfigurasi dalam kamus qubo_settings. Kami menentukan bilangan langkah masa (nt), bilangan bit untuk spesifikasi pelaburan (nq), dan tetingkap masa bagi setiap langkah masa (dt). Selain itu, kami menetapkan pelaburan maksimum setiap aset, pekali penolakan risiko, yuran transaksi, dan pekali sekatan (lihat kertas kerja kami untuk butiran tentang formulasi masalah). Tetapan ini membolehkan kami menyesuaikan masalah QUBO kepada senario pelaburan tertentu.
qubo_settings = {
"nt": 4,
"nq": 2,
"dt": 30,
"max_investment": 5, # maximum investment per asset is 2**nq/max_investment = 80%
"risk_aversion": 1000.0,
"transaction_fee": 0.01,
"restriction_coeff": 1.0,
}
Kamus optimizer_settings mengkonfigurasi proses pengoptimuman, termasuk parameter seperti num_generations untuk bilangan lelaran dan population_size untuk bilangan calon penyelesaian setiap generasi. Tetapan lain mengawal aspek seperti kadar rekombinasi, kerja selari, saiz kelompok, dan julat mutasi. Selain itu, tetapan primitif seperti estimator_shots, estimator_precision, dan sampler_shots menentukan konfigurasi Estimator dan Sampler kuantum untuk proses pengoptimuman.
optimizer_settings = {
"de_optimizer_settings": {
"num_generations": 20,
"population_size": 40,
"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,
},
}
Jumlah bilangan Circuit bergantung kepada parameter optimizer_settings dan dikira sebagai (num_generations + 1) * population_size.
Kamus ansatz_settings mengkonfigurasi ansatz Circuit kuantum. Parameter ansatz menentukan penggunaan pendekatan "optimized_real_amplitudes", iaitu ansatz cekap perkakasan yang direka untuk masalah pengoptimuman kewangan. Selain itu, tetapan multiple_passmanager didayakan untuk membenarkan pelbagai pass manager (termasuk pass manager Qiskit tempatan lalai dan perkhidmatan transpiler berkuasa AI Qiskit) semasa proses pengoptimuman, meningkatkan prestasi keseluruhan dan kecekapan pelaksanaan Circuit.
ansatz_settings = {
"ansatz": "optimized_real_amplitudes",
"multiple_passmanager": False,
}
Akhirnya, kami melaksanakan pengoptimuman dengan menjalankan fungsi dpo_solver.run(), menghantar input yang telah disediakan. Ini termasuk kamus data aset (assets), konfigurasi QUBO (qubo_settings), parameter pengoptimuman (optimizer_settings), dan tetapan ansatz Circuit kuantum (ansatz_settings). Selain itu, kami menentukan butiran pelaksanaan seperti Backend, dan sama ada hendak menggunakan pasca-pemprosesan pada keputusan. Ini memulakan proses pengoptimuman portfolio dinamik pada Backend kuantum yang dipilih.
dpo_job = dpo_solver.run(
assets=assets,
qubo_settings=qubo_settings,
optimizer_settings=optimizer_settings,
ansatz_settings=ansatz_settings,
backend_name="ibm_torino",
previous_session_id=[],
apply_postprocess=True,
)
Langkah 3: Analisis keputusan pengoptimuman
Dalam bahagian ini, kita ekstrak dan paparkan penyelesaian dengan kos objektif paling rendah daripada keputusan pengoptimuman. Selain kos objektif minimum, kita juga bentangkan metrik utama yang berkaitan dengan penyelesaian tersebut, termasuk sisihan sekatan, nisbah Sharpe, dan pulangan pelaburan.
# Get the results of the job
dpo_result = dpo_job.result()
# Show the solution strategy
dpo_result["result"]
{'time_step_0': {'ACS.MC': 0.11764705882352941,
'ITX.MC': 0.20588235294117646,
'FER.MC': 0.38235294117647056,
'ELE.MC': 0.058823529411764705,
'SCYR.MC': 0.0,
'AENA.MC': 0.058823529411764705,
'AMS.MC': 0.17647058823529413},
'time_step_1': {'ACS.MC': 0.11428571428571428,
'ITX.MC': 0.14285714285714285,
'FER.MC': 0.2,
'ELE.MC': 0.02857142857142857,
'SCYR.MC': 0.42857142857142855,
'AENA.MC': 0.0,
'AMS.MC': 0.08571428571428572},
'time_step_2': {'ACS.MC': 0.0,
'ITX.MC': 0.09375,
'FER.MC': 0.3125,
'ELE.MC': 0.34375,
'SCYR.MC': 0.0,
'AENA.MC': 0.0,
'AMS.MC': 0.25},
'time_step_3': {'ACS.MC': 0.3939393939393939,
'ITX.MC': 0.09090909090909091,
'FER.MC': 0.12121212121212122,
'ELE.MC': 0.18181818181818182,
'SCYR.MC': 0.0,
'AENA.MC': 0.0,
'AMS.MC': 0.21212121212121213}}
import pandas as pd
# Get results from the job
dpo_result = dpo_job.result()
# Convert metadata to a DataFrame, excluding 'session_id'
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']:.2f}")
Minimum Objective Cost Found: -3.67
Best Solution:
- Restriction Deviation: 40.0%
- Sharpe Ratio: 14.54
- Return: 0.28
Kod berikut menunjukkan cara memvisualisasikan dan membandingkan taburan kos algoritma pengoptimuman dengan taburan pensampelan rawak. Begitu juga, kita terokai landskap fungsi objektif QUBO (yang boleh dimuatkan dari output fungsi) dengan menilainya menggunakan pelaburan rawak. Kita plot kedua-dua taburan yang dinormalkan dalam amplitud untuk memudahkan perbandingan bagaimana proses pengoptimuman berbeza daripada pensampelan rawak dari segi kos. Selain itu, keputusan yang diperoleh menggunakan DOCPlex disertakan sebagai garis rujukan menegak berbentuk putus-putus sebagai penanda aras klasik. Kita gunakan versi percuma DOCPlex — perpustakaan sumber terbuka IBM® untuk pengoptimuman matematik dalam Python — bagi menyelesaikan masalah yang sama secara klasik.
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import matplotlib.patheffects as patheffects
def plot_normalized(dpo_x, dpo_y_normalized, random_x, random_y_normalized):
"""
Plots normalized results for two sampling results.
Parameters:
dpo_x (array-like): X-values for the VQE Post-processed curve.
dpo_y_normalized (array-like): Y-values (normalized) for the VQE Post-processed curve.
random_x (array-like): X-values for the Noise (Random) curve.
random_y_normalized (array-like): Y-values (normalized) for the Noise (Random) curve.
"""
plt.figure(figsize=(6, 3))
plt.tick_params(axis="both", which="major", labelsize=12)
# Define custom colors
colors = ["#4823E8", "#9AA4AD"]
# Plot DPO results
(line1,) = plt.plot(
dpo_x, dpo_y_normalized, label="VQE Postprocessed", color=colors[0]
)
line1.set_path_effects(
[patheffects.withStroke(linewidth=3, foreground="white")]
)
# Plot Random results
(line2,) = plt.plot(
random_x, random_y_normalized, label="Noise (Random)", color=colors[1]
)
line2.set_path_effects(
[patheffects.withStroke(linewidth=3, foreground="white")]
)
# Set X-axis ticks to increment by 5 units
plt.gca().xaxis.set_major_locator(MultipleLocator(5))
# Axis labels and legend
plt.xlabel("Objective cost", fontsize=14)
plt.ylabel("Normalized Counts", fontsize=14)
# Add DOCPLEX reference line
plt.axvline(
x=-4.11, color="black", linestyle="--", linewidth=1, label="DOCPlex"
) # DOCPlex value
plt.ylim(bottom=0)
plt.legend()
# Adjust layout
plt.tight_layout()
plt.show()
import numpy as np
from collections import defaultdict
# ================================
# STEP 1: DPO COST DISTRIBUTION
# ================================
# Extract data from DPO results
counts_list = dpo_result["metadata"]["all_samples_metrics"][
"objective_costs"
] # List of how many times each solution occurred
cost_list = dpo_result["metadata"]["all_samples_metrics"][
"counts"
] # List of corresponding objective function values (costs)
# Round costs to one decimal and accumulate counts for each unique cost
dpo_counter = defaultdict(int)
for cost, count in zip(cost_list, counts_list):
rounded_cost = round(cost, 1)
dpo_counter[rounded_cost] += count
# Prepare data for plotting
dpo_x = sorted(dpo_counter.keys()) # Sorted list of cost values
dpo_y = [dpo_counter[c] for c in dpo_x] # Corresponding counts
# Normalize the counts to the range [0, 1] for better comparison
dpo_min = min(dpo_y)
dpo_max = max(dpo_y)
dpo_y_normalized = [
(count - dpo_min) / (dpo_max - dpo_min) for count in dpo_y
]
# ================================
# STEP 2: RANDOM COST DISTRIBUTION
# ================================
# Read the QUBO matrix
qubo = np.array(dpo_result["metadata"]["qubo"])
bitstring_length = qubo.shape[0]
num_random_samples = 100_000 # Number of random samples to generate
random_cost_counter = defaultdict(int)
# Generate random bitstrings and calculate their cost
for _ in range(num_random_samples):
x = np.random.randint(0, 2, size=bitstring_length)
cost = float(x @ qubo @ x.T)
rounded_cost = round(cost, 1)
random_cost_counter[rounded_cost] += 1
# Prepare random data for plotting
random_x = sorted(random_cost_counter.keys())
random_y = [random_cost_counter[c] for c in random_x]
# Normalize the random cost distribution
random_min = min(random_y)
random_max = max(random_y)
random_y_normalized = [
(count - random_min) / (random_max - random_min) for count in random_y
]
# ================================
# STEP 3: PLOTTING
# ================================
plot_normalized(dpo_x, dpo_y_normalized, random_x, random_y_normalized)
Graf ini menunjukkan bagaimana pengoptimum portfolio kuantum secara konsisten menghasilkan strategi pelaburan yang dioptimumkan.
Rujukan
Tinjauan tutorial
Sila luangkan masa sebentar untuk memberi maklum balas tentang tutorial ini. Pandangan anda akan membantu kami menambah baik kandungan dan pengalaman pengguna kami.
Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.