English
Languages
English
Japanese
German
Korean
Portuguese, Brazilian
Shortcuts

Note

This page was generated from tutorials/finance/08_fixed_income_pricing.ipynb.

Run interactively in the IBM Quantum lab.

Pricing Fixed-Income Assets

Introduction

We seek to price a fixed-income asset knowing the distributions describing the relevant interest rates. The cash flows \(c_t\) of the asset and the dates at which they occur are known. The total value \(V\) of the asset is thus the expectation value of:

\[V = \sum_{t=1}^T \frac{c_t}{(1+r_t)^t}\]

Each cash flow is treated as a zero coupon bond with a corresponding interest rate \(r_t\) that depends on its maturity. The user must specify the distribution modeling the uncertainty in each \(r_t\) (possibly correlated) as well as the number of qubits he wishes to use to sample each distribution. In this example we expand the value of the asset to first order in the interest rates \(r_t\). This corresponds to studying the asset in terms of its duration. The approximation of the objective function follows the following paper: 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')

Uncertainty Model

We construct a circuit factory to load a multivariate normal random distribution in \(d\) dimensions into a quantum state. The distribution is truncated to a given box \(\otimes_{i=1}^d [low_i, high_i]\) and discretized using \(2^{n_i}\) grid points, where \(n_i\) denotes the number of qubits used for dimension \(i = 1,\ldots, d\). The unitary operator corresponding to the circuit factory implements the following:

\[\big|0\rangle_{n_1}\ldots\big|0\rangle_{n_d} \mapsto \big|\psi\rangle = \sum_{i_1=0}^{2^n_-1}\ldots\sum_{i_d=0}^{2^n_-1} \sqrt{p_{i_1,...,i_d}}\big|i_1\rangle_{n_1}\ldots\big|i_d\rangle_{n_d},\]

where \(p_{i_1, ..., i_d}\) denote the probabilities corresponding to the truncated and discretized distribution and where \(i_j\) is mapped to the right interval \([low_j, high_j]\) using the affine map:

\[\{0, \ldots, 2^{n_{j}}-1\} \ni i_j \mapsto \frac{high_j - low_j}{2^{n_j} - 1} * i_j + low_j \in [low_j, high_j].\]

In addition to the uncertainty model, we can also apply an affine map, e.g. resulting from a principal component analysis. The interest rates used are then given by:

\[\vec{r} = A * \vec{x} + b,\]

where \(\vec{x} \in \otimes_{i=1}^d [low_i, high_i]\) follows the given random distribution.

[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()
../../_images/tutorials_finance_08_fixed_income_pricing_6_0.png

Cash flow, payoff function, and exact expected value

In the following we define the cash flow per period, the resulting payoff function and evaluate the exact expected value.

For the payoff function we first use a first order approximation and then apply the same approximation technique as for the linear part of the payoff function of the European Call Option.

[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()
../../_images/tutorials_finance_08_fixed_income_pricing_8_0.png
[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.3356
Confidence interval:    [2.3046, 2.3667]
[13]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.24.0
Terra0.16.4
Aer0.7.6
Ignis0.5.2
Aqua0.8.2
IBM Q Provider0.12.1
System information
Python3.8.8 (default, Feb 19 2021, 19:42:00) [GCC 9.3.0]
OSLinux
CPUs2
Memory (Gb)6.7913818359375
Thu Mar 04 21:21:25 2021 UTC

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.

[ ]: