def test_asian_barrier_spread(self): """Test the asian barrier spread model.""" try: from qiskit.aqua.circuits import WeightedSumOperator, FixedValueComparator as Comparator from qiskit.aqua.components.uncertainty_problems import ( UnivariatePiecewiseLinearObjective as PwlObjective, MultivariateProblem) from qiskit.aqua.components.uncertainty_models import MultivariateLogNormalDistribution except ImportError: import warnings warnings.warn( 'Qiskit Aqua is not installed, skipping the application test.') return # number of qubits per dimension to represent the uncertainty num_uncertainty_qubits = 2 # parameters for considered random distribution spot_price = 2.0 # initial spot price volatility = 0.4 # volatility of 40% interest_rate = 0.05 # annual interest rate of 5% time_to_maturity = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution # pylint: disable=invalid-name mu = ((interest_rate - 0.5 * volatility**2) * time_to_maturity + np.log(spot_price)) sigma = volatility * np.sqrt(time_to_maturity) 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 # map to higher dimensional distribution # for simplicity assuming dimensions are independent and identically distributed) dimension = 2 num_qubits = [num_uncertainty_qubits] * dimension low = low * np.ones(dimension) high = high * np.ones(dimension) mu = mu * np.ones(dimension) cov = sigma**2 * np.eye(dimension) # construct circuit factory distribution = MultivariateLogNormalDistribution(num_qubits=num_qubits, low=low, high=high, mu=mu, cov=cov) # determine number of qubits required to represent total loss weights = [] for n in num_qubits: for i in range(n): weights += [2**i] num_sum_qubits = WeightedSumOperator.get_required_sum_qubits(weights) # create circuit factoy agg = WeightedSumOperator(sum(num_qubits), weights) # set the strike price (should be within the low and the high value of the uncertainty) strike_price_1 = 3 strike_price_2 = 4 # set the barrier threshold barrier = 2.5 # map strike prices and barrier threshold from [low, high] to {0, ..., 2^n-1} max_value = 2**num_sum_qubits - 1 low_ = low[0] high_ = high[0] mapped_strike_price_1 = (strike_price_1 - dimension*low_) / \ (high_ - low_) * (2**num_uncertainty_qubits - 1) mapped_strike_price_2 = (strike_price_2 - dimension*low_) / \ (high_ - low_) * (2**num_uncertainty_qubits - 1) mapped_barrier = (barrier - low) / (high - low) * (2**num_uncertainty_qubits - 1) conditions = [] for i in range(dimension): # target dimension of random distribution and corresponding condition conditions += [(i, Comparator(num_qubits[i], mapped_barrier[i] + 1, geq=False))] # set the approximation scaling for the payoff function c_approx = 0.25 # setup piecewise linear objective fcuntion breakpoints = [0, mapped_strike_price_1, mapped_strike_price_2] slopes = [0, 1, 0] offsets = [0, 0, mapped_strike_price_2 - mapped_strike_price_1] f_min = 0 f_max = mapped_strike_price_2 - mapped_strike_price_1 bull_spread_objective = PwlObjective(num_sum_qubits, 0, max_value, breakpoints, slopes, offsets, f_min, f_max, c_approx) # define overall multivariate problem asian_barrier_spread = MultivariateProblem(distribution, agg, bull_spread_objective, conditions=conditions) num_req_qubits = asian_barrier_spread.num_target_qubits num_req_ancillas = asian_barrier_spread.required_ancillas() qr = QuantumRegister(num_req_qubits, name='q') qr_ancilla = QuantumRegister(num_req_ancillas, name='q_a') qc = QuantumCircuit(qr, qr_ancilla) asian_barrier_spread.build(qc, qr, qr_ancilla) job = execute(qc, backend=BasicAer.get_backend('statevector_simulator')) # evaluate resulting statevector value = 0 for i, amplitude in enumerate(job.result().get_statevector()): b = ('{0:0%sb}' % asian_barrier_spread.num_target_qubits ).format(i)[-asian_barrier_spread.num_target_qubits:] prob = np.abs(amplitude)**2 if prob > 1e-4 and b[0] == '1': value += prob # all other states should have zero probability due to ancilla qubits if i > 2**num_req_qubits: break # map value to original range mapped_value = asian_barrier_spread.value_to_estimation(value) / ( 2**num_uncertainty_qubits - 1) * (high_ - low_) expected = 0.83188 self.assertAlmostEqual(mapped_value, expected, places=5)
def test_conditional_value_at_risk(self, simulator): """ conditional value at risk test """ # define backend to be used backend = BasicAer.get_backend(simulator) # set problem parameters n_z = 2 z_max = 2 # z_values = np.linspace(-z_max, z_max, 2 ** n_z) p_zeros = [0.15, 0.25] rhos = [0.1, 0.05] lgd = [1, 2] k_l = len(p_zeros) # alpha = 0.05 # set var value var = 2 var_prob = 0.961940 # determine number of qubits required to represent total loss # n_s = WeightedSumOperator.get_required_sum_qubits(lgd) # create circuit factory (add Z qubits with weight/loss 0) agg = WeightedSumOperator(n_z + k_l, [0] * n_z + lgd) # define linear objective breakpoints = [0, var] slopes = [0, 1] offsets = [0, 0] # subtract VaR and add it later to the estimate f_min = 0 f_max = 3 - var c_approx = 0.25 # construct circuit factory for uncertainty model (Gaussian Conditional Independence model) gci = GCI(n_z, z_max, p_zeros, rhos) cvar_objective = PwlObjective( agg.num_sum_qubits, 0, 2**agg.num_sum_qubits - 1, # max value that can be reached by the qubit register breakpoints, slopes, offsets, f_min, f_max, c_approx) multivariate_cvar = MultivariateProblem(gci, agg, cvar_objective) num_qubits = multivariate_cvar.num_target_qubits num_ancillas = multivariate_cvar.required_ancillas() q = QuantumRegister(num_qubits, name='q') q_a = QuantumRegister(num_ancillas, name='q_a') qc = QuantumCircuit(q, q_a) multivariate_cvar.build(qc, q, q_a) job = execute(qc, backend=backend) # evaluate resulting statevector value = 0 for i, a_i in enumerate(job.result().get_statevector()): b = ('{0:0%sb}' % multivariate_cvar.num_target_qubits).\ format(i)[-multivariate_cvar.num_target_qubits:] a_m = np.round(np.real(a_i), decimals=4) if np.abs(a_m) > 1e-6 and b[0] == '1': value += a_m**2 # normalize and add VaR to estimate value = multivariate_cvar.value_to_estimation(value) normalized_value = value / (1.0 - var_prob) + var # compare to precomputed solution self.assertEqual(0.0, np.round(normalized_value - 3.3796, decimals=4))
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)
# In[10]: # define linear objective function breakpoints = [0] slopes = [1] offsets = [0] f_min = 0 f_max = sum(lgd) c_approx = 0.25 objective = PwlObjective( agg.num_sum_qubits, 0, 2**agg.num_sum_qubits - 1, # max value that can be reached by the qubit register (will not always be reached) breakpoints, slopes, offsets, f_min, f_max, c_approx) # define overall multivariate problem multivariate = MultivariateProblem(u, agg, objective) # In[11]: num_qubits = multivariate.num_target_qubits num_ancillas = multivariate.required_ancillas() q = QuantumRegister(num_qubits, name='q')
### Payoff Function # set the strike price (should be within the low and the high value of the uncertainty) strike_price_1 = 1.438 strike_price_2 = 2.584 # set the approximation scaling for the payoff function c_approx = 0.25 # setup piecewise linear objective fcuntion breakpoints = [uncertainty_model.low, strike_price_1, strike_price_2] slopes = [0, 1, 0] offsets = [0, 0, strike_price_2 - strike_price_1] f_min = 0 f_max = strike_price_2 - strike_price_1 bull_spread_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 bull_spread = UnivariateProblem(uncertainty_model, bull_spread_objective) # plot exact payoff function (evaluated on the grid of the uncertainty model) x = uncertainty_model.values y = np.minimum(np.maximum(0, x - strike_price_1), strike_price_2 - strike_price_1) plt.plot(x, y, 'ro-') plt.grid() plt.title('Payoff Function', size=15) plt.xlabel('Spot Price', size=15) plt.ylabel('Payoff', size=15) plt.xticks(x, size=15, rotation=90)