French
Langues
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

Note

Cette page a été générée à partir de tutorials/finance/1_portfolio_optimization.ipynb.

Exécuter en mode interactif dans le IBM Quantum lab.

Optimisation de portefeuille

Introduction

Ce tutoriel montre comment résoudre le problème d’optimisation du portefeuille de variance moyenne suivant pour :math:` n ` actifs:

\(\begin{aligned} \min_{x \in \{0, 1\}^n} q x^T \Sigma x - \mu^T x\\ \text{subject to: } 1^T x = B \end{aligned}\)

où nous utilisons la notation suivante:

  • \(x \in \{0, 1\}^n\) représente le vecteur des décisions binaires, qui indiquent les actifs à sélectionner (\(x[i] = 1\)) et ceux qui ne sont pas à sélectionner (\(x[i] = 0\)),

  • \(\mu \in \mathbb{R}^n\) définit les retours attendus des actifs,

  • \(\Sigma \in \mathbb{R}^{n \times n}\) spécifie les covariances entre les actifs,

  • \(q > 0\) contrôle la propension au risque du décideur,

  • et \(B\) représente le budget, c’est-à-dire le nombre d’actifs à sélectionner parmi les \(n\).

Nous supposons les simplifications suivantes: - tous les actifs ont le même prix (normalisé à 1), - le budget total \(B\) doit être dépensé, c’est-à-dire qu’il faut sélectionner exactement \(B\) actifs.

La contrainte d’égalité \(1^T x = B\) correspond à un term de pénalité \((1^T x - B)^2\) qui est paramétré par un facteur de proportionnalité, et soustrait de la fonction objectif. Le problème ainsi décrit peut être mis en correspondance avec un hamiltonien dont l’état fondamental correspond à la solution optimale. Ce bloc-notes montre comment utiliser le VQE (Variational Quantum Eigensolver) ou l’algorithme QAOA (Quantum Approximate Optimization Algorithm) pour trouver la solution optimale pour un ensemble donné de paramètres.

Des expériences sur les machines quantiques réelles pour ce problème sont rapportées par exemple dans le document suivant: Improving Variational Quantum Optimization using CVaR. Barkoutsos et al. 2019.

[1]:
from qiskit import Aer
from qiskit.circuit.library import TwoLocal
from qiskit.aqua import QuantumInstance
from qiskit.finance.applications.ising import portfolio
from qiskit.optimization.applications.ising.common import sample_most_likely
from qiskit.finance.data_providers import RandomDataProvider
from qiskit.aqua.algorithms import VQE, QAOA, NumPyMinimumEigensolver
from qiskit.aqua.components.optimizers import COBYLA
import numpy as np
import matplotlib.pyplot as plt
import datetime

[Optional] Préparation du jeton d’accès pour exécuter l’expérimentation sur un backend réel

Si vous souhaitez exécuter l’expérience sur un backend réel, vous devez d’abord configurer votre compte.

Note: Si vous n’aviez pas encore sauvegardé votre jeton, utilisez IBMQ.save_account ('MY_API_TOKEN') pour le stocker en premier.

Définir d’une instance du problème

Ici, une instance d’opérateur est créée pour notre hamiltonien. Dans ce cas, les paulis proviennent d’un hamiltonien Ising traduit du problème du portefeuille. Nous utilisons un problème de portefeuille aléatoire pour ce bloc-notes. Il est tout à fait possible de l’étendre à l’utilisation de données financières réelles telles qu’illustrées ici: Chargement et Traitement des séries temporelles de données du marché d’action <11_time_series.ipynb> __

[2]:
# set number of assets (= number of qubits)
num_assets = 4

# Generate expected return and covariance matrix from (random) time-series
stocks = [("TICKER%s" % i) for i in range(num_assets)]
data = RandomDataProvider(tickers=stocks,
                 start=datetime.datetime(2016,1,1),
                 end=datetime.datetime(2016,1,30))
data.run()
mu = data.get_period_return_mean_vector()
sigma = data.get_period_return_covariance_matrix()
[3]:
# plot sigma
plt.imshow(sigma, interpolation='nearest')
plt.show()
../../_images/tutorials_finance_01_portfolio_optimization_6_0.png
[4]:
q = 0.5                   # set risk factor
budget = num_assets // 2  # set budget
penalty = num_assets      # set parameter to scale the budget penalty term

qubitOp, offset = portfolio.get_operator(mu, sigma, q, budget, penalty)

Nous définissons quelques méthodes utilitaires pour imprimer les résultats dans un format élégant.

[5]:
def index_to_selection(i, num_assets):
    s = "{0:b}".format(i).rjust(num_assets)
    x = np.array([1 if s[i]=='1' else 0 for i in reversed(range(num_assets))])
    return x

def print_result(result):
    selection = sample_most_likely(result.eigenstate)
    value = portfolio.portfolio_value(selection, mu, sigma, q, budget, penalty)
    print('Optimal: selection {}, value {:.4f}'.format(selection, value))

    eigenvector = result.eigenstate if isinstance(result.eigenstate, np.ndarray) else result.eigenstate.to_matrix()
    probabilities = np.abs(eigenvector)**2
    i_sorted = reversed(np.argsort(probabilities))
    print('\n----------------- Full result ---------------------')
    print('selection\tvalue\t\tprobability')
    print('---------------------------------------------------')
    for i in i_sorted:
        x = index_to_selection(i, num_assets)
        value = portfolio.portfolio_value(x, mu, sigma, q, budget, penalty)
        probability = probabilities[i]
        print('%10s\t%.4f\t\t%.4f' %(x, value, probability))

NumPyMinimumEigensolver (en tant que référence classique)

Résolvons le problème. D’abord de manière classique…

Nous pouvons maintenant utiliser l’opérateur que nous avons construit ci-dessus sans tenir compte des détails de la façon dont il a été créé. Nous avons défini l’algorithme pour le NumPyMinimumEigensolver afin que nous puissions avoir une référence classique. Le problème est préparé pour le modèle de “ising”. Le backend n’est pas requis car ce calcul est classique et n’utilise aucun calcul quantique. Le résultat est renvoyé sous forme de dictionnaire.

[6]:
exact_eigensolver = NumPyMinimumEigensolver(qubitOp)
result = exact_eigensolver.run()

print_result(result)
Optimal: selection [0 1 0 1], value -0.0005

----------------- Full result ---------------------
selection       value           probability
---------------------------------------------------
 [0 1 0 1]      -0.0005         1.0000
 [1 1 1 1]      16.0040         0.0000
 [0 1 1 1]      4.0013          0.0000
 [1 0 1 1]      4.0052          0.0000
 [0 0 1 1]      0.0025          0.0000
 [1 1 0 1]      4.0023          0.0000
 [1 0 0 1]      0.0034          0.0000
 [0 0 0 1]      4.0007          0.0000
 [1 1 1 0]      4.0033          0.0000
 [0 1 1 0]      0.0007          0.0000
 [1 0 1 0]      0.0045          0.0000
 [0 0 1 0]      4.0018          0.0000
 [1 1 0 0]      0.0016          0.0000
 [0 1 0 0]      3.9988          0.0000
 [1 0 0 0]      4.0027          0.0000
 [0 0 0 0]      16.0000         0.0000

Solution utilisant VQE

Nous pouvons maintenant utiliser le Variational Quantum Eigensolver (VQE) pour résoudre le problème. Nous préciserons l’optimiseur et la forme variationnelle à utiliser.

Note: Vous pouvez basculer vers différents backends en fournissant le nom du backend.

[7]:
backend = Aer.get_backend('statevector_simulator')
seed = 50

cobyla = COBYLA()
cobyla.set_options(maxiter=500)
ry = TwoLocal(qubitOp.num_qubits, 'ry', 'cz', reps=3, entanglement='full')
vqe = VQE(qubitOp, ry, cobyla)
vqe.random_seed = seed

quantum_instance = QuantumInstance(backend=backend, seed_simulator=seed, seed_transpiler=seed)

result = vqe.run(quantum_instance)

print_result(result)
Optimal: selection [0. 0. 1. 1.], value 0.0025

----------------- Full result ---------------------
selection       value           probability
---------------------------------------------------
 [0 0 1 1]      0.0025          0.7519
 [0 1 1 0]      0.0007          0.2480
 [1 1 0 1]      4.0023          0.0000
 [1 1 0 0]      0.0016          0.0000
 [1 0 0 1]      0.0034          0.0000
 [0 1 0 1]      -0.0005         0.0000
 [1 1 1 0]      4.0033          0.0000
 [1 0 0 0]      4.0027          0.0000
 [1 0 1 1]      4.0052          0.0000
 [1 0 1 0]      0.0045          0.0000
 [0 0 1 0]      4.0018          0.0000
 [0 1 0 0]      3.9988          0.0000
 [0 0 0 1]      4.0007          0.0000
 [0 1 1 1]      4.0013          0.0000
 [0 0 0 0]      16.0000         0.0000
 [1 1 1 1]      16.0040         0.0000

Solution utilisant QAOA

Nous montrons également ici un résultat obtenu à l’aide de l’algorithme QAOA (Quantum Approximate Optimization Algorithm). Il s’agit d’un autre algorithme variationnel qui utilise une forme variationnelle interne qui est créé en fonction du problème.

[8]:
backend = Aer.get_backend('statevector_simulator')
seed = 50

cobyla = COBYLA()
cobyla.set_options(maxiter=250)
qaoa = QAOA(qubitOp, cobyla, 3)

qaoa.random_seed = seed

quantum_instance = QuantumInstance(backend=backend, seed_simulator=seed, seed_transpiler=seed)

result = qaoa.run(quantum_instance)

print_result(result)
Optimal: selection [0. 1. 0. 1.], value -0.0005

----------------- Full result ---------------------
selection       value           probability
---------------------------------------------------
 [0 1 0 1]      -0.0005         0.1673
 [0 1 1 0]      0.0007          0.1670
 [1 1 0 0]      0.0016          0.1668
 [0 0 1 1]      0.0025          0.1666
 [1 0 0 1]      0.0034          0.1663
 [1 0 1 0]      0.0045          0.1661
 [1 1 1 1]      16.0040         0.0000
 [0 0 0 0]      16.0000         0.0000
 [0 1 1 1]      4.0013          0.0000
 [0 1 0 0]      3.9988          0.0000
 [1 1 0 1]      4.0023          0.0000
 [1 0 1 1]      4.0052          0.0000
 [1 0 0 0]      4.0027          0.0000
 [1 1 1 0]      4.0033          0.0000
 [0 0 0 1]      4.0007          0.0000
 [0 0 1 0]      4.0018          0.0000
[9]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.19.1
Terra0.14.1
Aer0.5.1
Ignis0.3.0
Aqua0.7.0
IBM Q Provider0.7.0
System information
Python3.7.4 (default, Aug 13 2019, 15:17:50) [Clang 4.0.1 (tags/RELEASE_401/final)]
OSDarwin
CPUs6
Memory (Gb)16.0
Fri Jul 17 17:36:55 2020 CEST

This code is a part of Qiskit

© Copyright IBM 2017, 2020.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.

[ ]: