def get_pdf(qu, S0, sig, r, T): """ Function to extract probability distribution functions :param qu: Number of qubits :param S0: Initial price :param sig: Volatility :param r: Interest rate :param T: Maturity date :return: uncertainty models, (values, pdf), (mu, mean, variance) """ mu = ((r - 0.5 * sig**2) * T + np.log(S0) ) # parameters for the log_normal distribution sigma = sig * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # S = np.linspace(low, high, samples) # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(min(16, qu), mu=mu, sigma=sigma, low=low, high=high) values = uncertainty_model.values pdf = uncertainty_model.probabilities return uncertainty_model, (values, pdf), (mu, mean, variance)
def load_payoff_quantum_sim(qu, S0, sig, r, T, K, error=0.05): """ Function to create quantum circuit to return an approximate probability distribution. This function is thought to be the prelude of run_payoff_quantum_sim :param qu: Number of qubits :param S0: Initial price :param sig: Volatility :param r: Interest rate :param T: Maturity date :param K: strike :return: quantum circuit, backend, prices """ mu = ((r - 0.5 * sig**2) * T + np.log(S0) ) # parameters for the log_normal distribution sigma = sig * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # S = np.linspace(low, high, samples) # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(qu, mu=mu, sigma=sigma, low=low, high=high) # values = uncertainty_model.values # pdf = uncertainty_model.probabilities qr = QuantumRegister(2 * qu + 2) cr = ClassicalRegister(1) qc = QuantumCircuit(qr, cr) uncertainty_model.build(qc, qr) k, c = payoff_circuit(qc, qu, K, high, low, error=error) return c, k, high, low, qc
def test_expected_value(self, simulator): # number of qubits to represent the uncertainty num_uncertainty_qubits = 3 # parameters for considered random distribution S = 2.0 # initial spot price vol = 0.4 # volatility of 40% r = 0.05 # annual interest rate of 4% T = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution mu = ((r - 0.5 * vol**2) * T + np.log(S)) sigma = vol * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(num_uncertainty_qubits, mu=mu, sigma=sigma, low=low, high=high) # set the strike price (should be within the low and the high value of the uncertainty) strike_price = 2 # set the approximation scaling for the payoff function c_approx = 0.5 # construct circuit factory for payoff function european_call = EuropeanCallExpectedValue(uncertainty_model, strike_price=strike_price, c_approx=c_approx) # set number of evaluation qubits (samples) m = 3 # construct amplitude estimation ae = AmplitudeEstimation(m, european_call) # run simulation quantum_instance = QuantumInstance(BasicAer.get_backend(simulator), circuit_caching=False) result = ae.run(quantum_instance=quantum_instance) # compare to precomputed solution self.assertEqual( 0.0, np.round(result['estimation'] - 0.045705353233, decimals=4))
def load_Q_operator(qu, depth, S0, sig, r, T, K, error=0.05): """ Function to create quantum circuit for the unary representation to return an approximate probability distribution. This function is thought to be the prelude of run_payoff_quantum_sim :param qu: Number of qubits :param S0: Initial price :param depth: Number of implementations of Q :param sig: Volatility :param r: Interest rate :param T: Maturity date :param K: strike :return: quantum circuit, backend, prices """ depth = int(depth) mu = ((r - 0.5 * sig**2) * T + np.log(S0) ) # parameters for the log_normal distribution sigma = sig * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev #S = np.linspace(low, high, samples) # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(qu, mu=mu, sigma=sigma, low=low, high=high) qr = QuantumRegister(2 * qu + 2) cr = ClassicalRegister(1) qc = QuantumCircuit(qr, cr) uncertainty_model.build(qc, qr) (k, c) = payoff_circuit(qc, qu, K, high, low, error=error, measure=False) for i in range(depth): oracle_operator(qc, qu) payoff_circuit_inv(qc, qu, K, high, low, error=error, measure=False) uncertainty_model.build_inverse(qc, qr) diffusion_operator(qc, qu) uncertainty_model.build(qc, qr) payoff_circuit(qc, qu, K, high, low, error=error, measure=False) qc.measure([2 * qu + 1], [0]) return qc, (k, c, high, low)
def load_quantum_sim(qu, S0, sig, r, T): """ Function to create quantum circuit for the binary representation to return an approximate probability distribution. This function is thought to be the prelude of run_quantum_sim :param qu: Number of qubits :param S0: Initial price :param sig: Volatility :param r: Interest rate :param T: Maturity date :return: quantum circuit, backend, (values of prices, prob. distri. function), (mu, mean, variance) """ mu = ((r - 0.5 * sig**2) * T + np.log(S0) ) # parameters for the log_normal distribution sigma = sig * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # S = np.linspace(low, high, samples) # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(qu, mu=mu, sigma=sigma, low=low, high=high) values = uncertainty_model.values pdf = uncertainty_model.probabilities qr = QuantumRegister(qu) cr = ClassicalRegister(qu) qc = QuantumCircuit(qr, cr) uncertainty_model.build(qc, qr) qc.measure(np.arange(0, qu), np.arange(0, qu)) return qc, (values, pdf), (mu, mean, variance)
def setUp(self): super().setUp() # number of qubits to represent the uncertainty num_uncertainty_qubits = 3 # parameters for considered random distribution s_p = 2.0 # initial spot price vol = 0.4 # volatility of 40% r = 0.05 # annual interest rate of 4% t_m = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution m_u = ((r - 0.5 * vol**2) * t_m + np.log(s_p)) sigma = vol * np.sqrt(t_m) mean = np.exp(m_u + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * m_u + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; # in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(num_uncertainty_qubits, mu=m_u, sigma=sigma, low=low, high=high) # set the strike price (should be within the low and the high value of the uncertainty) strike_price = 1.896 # set the approximation scaling for the payoff function c_approx = 0.1 # setup piecewise linear objective function breakpoints = [uncertainty_model.low, strike_price] slopes = [0, 1] offsets = [0, 0] f_min = 0 f_max = uncertainty_model.high - strike_price european_call_objective = PwlObjective( uncertainty_model.num_target_qubits, uncertainty_model.low, uncertainty_model.high, breakpoints, slopes, offsets, f_min, f_max, c_approx) # construct circuit factory for payoff function self.european_call = UnivariateProblem(uncertainty_model, european_call_objective) # construct circuit factory for payoff function self.european_call_delta = EuropeanCallDelta( uncertainty_model, strike_price=strike_price, ) self._statevector = QuantumInstance( backend=BasicAer.get_backend('statevector_simulator'), seed_simulator=2, seed_transpiler=2) self._qasm = QuantumInstance( backend=BasicAer.get_backend('qasm_simulator'), shots=100, seed_simulator=2, seed_transpiler=2)
def __init__(self, value, spot_price, volatility, int_rate, days, strike_price): self.value = value # Number of qubits to represent the uncertainty num_uncertainty_qubits = 3 # Parameters try: S = float(spot_price) vol = float(volatility) r = float(int_rate) T = int(days) / 365 strike_price = float(strike_price) except ValueError: print("Some parameters wrong !!! ") mu = ((r - 0.5 * vol**2) * T + np.log(S)) sigma = vol * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # Circuit factory for uncertainty model self.uncertainty_model = LogNormalDistribution(num_uncertainty_qubits, mu=mu, sigma=sigma, low=low, high=high) try: self.strike_price = float(strike_price) except ValueError: print("Some parameters wrong !!! ") # The approximation scaling for the payoff function c_approx_payoff = 0.25 #abs(S-self.strike_price) print(c_approx_payoff) breakpoints = [self.uncertainty_model.low, self.strike_price] if self.value == str("call"): slopes_payoff = [0, 1] else: slopes_payoff = [-1, 0] if self.value == str("call"): offsets_payoff = [0, 0] else: offsets_payoff = [ self.strike_price - self.uncertainty_model.low, 0 ] f_min_payoff = 0 if self.value == str("call"): f_max_payoff = self.uncertainty_model.high - self.strike_price else: f_max_payoff = self.strike_price - self.uncertainty_model.low european_objective = PwlObjective( self.uncertainty_model.num_target_qubits, self.uncertainty_model.low, self.uncertainty_model.high, breakpoints, slopes_payoff, offsets_payoff, f_min_payoff, f_max_payoff, c_approx_payoff) # Circuit factory for payoff function self.european_payoff = UnivariateProblem(self.uncertainty_model, european_objective) slopes_delta = [0, 0] if self.value == str("call"): offsets_delta = [0, 1] else: offsets_delta = [1, 0] f_min_delta = 0 f_max_delta = 1 c_approx_delta = 1 european_delta_objective = PwlObjective( self.uncertainty_model.num_target_qubits, self.uncertainty_model.low, self.uncertainty_model.high, breakpoints, slopes_delta, offsets_delta, f_min_delta, f_max_delta, c_approx_delta) self.european_delta = UnivariateProblem(self.uncertainty_model, european_delta_objective)
for i in sortedkeys: for j in counts: if (i == j): sortedcounts.append(counts.get(j)) plt.suptitle('Uniform Distribution') plt.plot(sortedcounts) plt.show() print("\n Log-Normal Distribution") print("-----------------") circuit = QuantumCircuit(q, c) lognorm = LogNormalDistribution(num_target_qubits=5, mu=0, sigma=1, low=0, high=1) lognorm.build(circuit, q) circuit.measure(q, c) circuit.draw(output='mpl', filename='log.png') job = execute(circuit, backend, shots=8192) job_monitor(job) counts = job.result().get_counts() print(counts) sortedcounts = [] sortedkeys = sorted(counts)
# resulting parameters for log-normal distribution mu = ((r - 0.5 * vol**2) * T + np.log(S)) sigma = vol * np.sqrt(T) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(num_uncertainty_qubits, mu=mu, sigma=sigma, low=low, high=high) # plot probability distribution x = uncertainty_model.values y = uncertainty_model.probabilities plt.bar(x, y, width=0.2) plt.xticks(x, size=15, rotation=90) plt.yticks(size=15) plt.grid() plt.xlabel('Spot Price at Maturity $S_T$ (\$)', size=15) plt.ylabel('Probability ($\%$)', size=15) # should show graph plt.show()