Nota
Esta página foi gerada, a partir de tutorials/finance/08_fixed_income_pricing.ipynb.
Execute interativamente no IBM Quantum lab.
Precificando ativos de renda fixa¶
Introdução¶
Buscamos precificar um ativo de renda fixa sabendo as distribuições, que descrevem as taxas de juros relevantes. Os fluxos de caixa \(c_t\) do ativo e as datas em que ocorrem são conhecidos. O valor total \(V\) do ativo é, assim, o valor esperado de:
Cada fluxo de caixa é tratado como um título de cupom zero, com uma taxa de juros correspondente \(r_t\) que depende de seu vencimento. O usuário deve especificar a distribuição, que modela a incerteza em cada \(r_t\) (possivelmente correlacionadas), assim como o número de qubits, que deseja utilizar para amostrar cada distribuição. Neste exemplo, expandimos o valor do ativo para primeira ordem nas taxas de juros \(r_t\). Isto corresponde a estudar o ativo, em termos de sua duração. A aproximação da função objetivo segue o seguinte artigo: Quantum Risk Analysis. Woerner, Egger. 2018.
[1]:
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
from qiskit import Aer, QuantumCircuit
from qiskit.aqua.algorithms import IterativeAmplitudeEstimation
from qiskit.circuit.library import NormalDistribution
[2]:
backend = Aer.get_backend('statevector_simulator')
Modelo de incerteza¶
Construímos uma fábrica de circuitos para carregar uma distribuição aleatória normal multivariada em \(d\) dimensões em um estado quântico. A distribuição é truncada para uma determinada caixa \(\otimes_{i=1}^d [low_i, high_i]\) e discretizada usando \(2^{n_i}\) pontos de grade, onde \(n_i\) denota o número de qubits utilizados para a dimensão \(i = 1,\ldots, d\). O operador unitário correspondente à fábrica de circuitos implementa o seguinte:
onde \(p_{i_1, ..., i_d}\) denotam as probabilidades correspondentes à distribuição truncada e discretizada e onde \(i_j\) é mapeado para o intervalo correto \([low_j, high_j]\) utilizando o mapeamento afim:
Além do modelo de incerteza, podemos também aplicar um mapeamento afim, por exemplo, resultante de uma análise de componentes principais. As taxas de juros utilizadas são então dadas por:
onde \(\vec{x} \in \otimes_{i=1}^d [low_i, high_i]\) segue a distribuição aleatória dada.
[3]:
# can be used in case a principal component analysis has been done to derive the uncertainty model, ignored in this example.
A = np.eye(2)
b = np.zeros(2)
# specify the number of qubits that are used to represent the different dimenions of the uncertainty model
num_qubits = [2, 2]
# specify the lower and upper bounds for the different dimension
low = [0, 0]
high = [0.12, 0.24]
mu = [0.12, 0.24]
sigma = 0.01*np.eye(2)
# construct corresponding distribution
bounds = list(zip(low, high))
u = NormalDistribution(num_qubits, mu, sigma, bounds)
[4]:
# plot contour of probability density function
x = np.linspace(low[0], high[0], 2**num_qubits[0])
y = np.linspace(low[1], high[1], 2**num_qubits[1])
z = u.probabilities.reshape(2**num_qubits[0], 2**num_qubits[1])
plt.contourf(x, y, z)
plt.xticks(x, size=15)
plt.yticks(y, size=15)
plt.grid()
plt.xlabel('$r_1$ (%)', size=15)
plt.ylabel('$r_2$ (%)', size=15)
plt.colorbar()
plt.show()

Fluxo de caixa, função payoff e valor esperado exato¶
A seguir, definimos o fluxo de caixa por período, a função payoff resultante e avaliamos o valor esperado exato.
Para a função de payoff, usamos primeiro a aproximação de primeira ordem e em seguida, aplicamos a mesma técnica de aproximação para a parte linear da função de pagamento da Opção de Chamada Europeia.
[5]:
# specify cash flow
cf = [1.0, 2.0]
periods = range(1, len(cf) + 1)
# plot cash flow
plt.bar(periods, cf)
plt.xticks(periods, size=15)
plt.yticks(size=15)
plt.grid()
plt.xlabel('periods', size=15)
plt.ylabel('cashflow ($)', size=15)
plt.show()

[6]:
# estimate real value
cnt = 0
exact_value = 0.0
for x1 in np.linspace(low[0], high[0], pow(2, num_qubits[0])):
for x2 in np.linspace(low[1], high[1], pow(2, num_qubits[1])):
prob = u.probabilities[cnt]
for t in range(len(cf)):
# evaluate linear approximation of real value w.r.t. interest rates
exact_value += prob * (cf[t]/pow(1 + b[t], t+1) - (t+1)*cf[t]*np.dot(A[:, t], np.asarray([x1, x2]))/pow(1 + b[t], t+2))
cnt += 1
print('Exact value: \t%.4f' % exact_value)
Exact value: 2.1942
[7]:
# specify approximation factor
c_approx = 0.125
# get fixed income circuit appfactory
from qiskit.finance.applications import FixedIncomeExpectedValue
fixed_income = FixedIncomeExpectedValue(num_qubits, A, b, cf, c_approx, bounds)
[8]:
fixed_income.draw()
[8]:
q_0: ───────────────────■────────────────────────────────────────────────── │ q_1: ───────────────────┼─────────────■──────────────────────────────────── │ │ q_2: ───────────────────┼─────────────┼─────────────■────────────────────── │ │ │ q_3: ───────────────────┼─────────────┼─────────────┼─────────────■──────── ┌───────────┐┌─────┴──────┐┌─────┴──────┐┌─────┴─────┐┌──────┴───────┐ q_4: ┤ RY(9π/16) ├┤ RY(-π/216) ├┤ RY(-π/108) ├┤ RY(-π/27) ├┤ RY(-0.23271) ├ └───────────┘└────────────┘└────────────┘└───────────┘└──────────────┘
[9]:
state_preparation = QuantumCircuit(fixed_income.num_qubits)
# load probability distribution
state_preparation.append(u, range(u.num_qubits))
# apply function
state_preparation.append(fixed_income, range(fixed_income.num_qubits))
state_preparation.draw()
[9]:
┌───────┐┌────┐ q_0: ┤0 ├┤0 ├ │ ││ │ q_1: ┤1 ├┤1 ├ │ P(X) ││ │ q_2: ┤2 ├┤2 F ├ │ ││ │ q_3: ┤3 ├┤3 ├ └───────┘│ │ q_4: ─────────┤4 ├ └────┘
[10]:
# set target precision and confidence level
epsilon = 0.01
alpha = 0.05
# set objective qubit
objective = u.num_qubits
# construct amplitude estimation
ae = IterativeAmplitudeEstimation(epsilon=epsilon, alpha=alpha,
state_preparation=state_preparation,
objective_qubits=[objective],
post_processing=fixed_income.post_processing)
[11]:
result = ae.run(quantum_instance=Aer.get_backend('qasm_simulator'), shots=100)
[12]:
conf_int = np.array(result['confidence_interval'])
print('Exact value: \t%.4f' % exact_value)
print('Estimated value: \t%.4f' % (result['estimation']))
print('Confidence interval:\t[%.4f, %.4f]' % tuple(conf_int))
Exact value: 2.1942
Estimated value: 2.3404
Confidence interval: [2.3094, 2.3714]
[13]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.23.3 |
Terra | 0.16.2 |
Aer | 0.7.3 |
Ignis | 0.5.1 |
Aqua | 0.8.1 |
IBM Q Provider | 0.11.1 |
System information | |
Python | 3.8.5 (default, Sep 4 2020, 07:30:14) [GCC 7.3.0] |
OS | Linux |
CPUs | 2 |
Memory (Gb) | 3.736370086669922 |
Thu Jan 28 13:33:57 2021 IST |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
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.
[ ]: