def test_multidimensional_constrained_optimiser(self): tolerance = 1e-7 def equality_constraint(x): # x[0] - 1 = 0 return x[0] - 1 def inequality_constraint(x): # x_i > 0 for all i return x optimiser = Optimiser(0, tolerance, 1, self.multidimensional_merit_function) initial_point_i = [1, 1, 1, 1, 1] lower_bound_i = [-1, -2, -3, -4, -5] upper_bound_i = [1, 2, 3, 4, 5] [_, obj] = optimiser.multidimensional_optimiser( lower_bound_i, upper_bound_i, initial_point_i, inequality_constraint, equality_constraint) target_obj = 1.0 / 5 self.assertTrue( abs(obj - target_obj) < tolerance, "MDO didn't work, OBJ = " + str(obj))
def test_brent(self): """ Calculates sqrt(2) numerically by means of Brent method :return: """ optimiser = Optimiser(2, 1e-8, 100, self.single_dimensional_merit_function) sqrt_2 = optimiser.brent_method(0, 5) self.assertTrue(abs(sqrt_2 / sqrt(2) - 1) < 1e-7, "Brent didn't work")
def test_newton(self): """ Calculates sqrt(2) numerically by means of Newton-Raphson method :return: """ optimiser = Optimiser(2, 1e-8, 100, self.single_dimensional_merit_function) sqrt_2 = optimiser.newton_method(3) self.assertTrue( abs(sqrt_2 / sqrt(2) - 1) < 1e-15, "Newton didn't work")
def test_root_bracketing(self): """ Launch Brent with a non-bracketing interval :return: """ optimiser = Optimiser(2, 1e-8, 100, self.single_dimensional_merit_function) sqrt_2 = optimiser.brent_method(0, 1) self.assertTrue( abs(sqrt_2 / sqrt(2) - 1) < 1e-7, "Monotonic root bracketing didn't work") self.assertRaises(Exception, optimiser.brent_method, -1, 1)
def test_multidimensional_optimiser(self): tolerance = 1e-7 optimiser = Optimiser(0, tolerance, 1, self.multidimensional_merit_function) initial_point_i = [1, 1, 1, 1, 1] lower_bound_i = [-1, -2, -3, -4, -5] upper_bound_i = [1, 2, 3, 4, 5] [_, obj] = optimiser.multidimensional_optimiser(lower_bound_i, upper_bound_i, initial_point_i) target_obj = 0 self.assertTrue( abs(obj - target_obj) < tolerance, "MDO didn't work, OBJ = " + str(obj)) self.assertTrue(obj < tolerance, "MDO didn't work, OBJ = " + str(obj))
def _binary_search(self, random_number, t): from NumericalLibrary.COptimiser import Optimiser vector = self.model.total_cumulative_stochastic_kernels[t][ self.model.x0, :] x = Optimiser.binary_search(vector, random_number) return x
def calculate_implied_volatility(underlying, strike, annuity, domestic_short_rate, foreign_short_rate, price, days_to_maturity, pay_rec): """ Find sigma s.t. P_t = A_t * (S_t * N(d_1(sigma)) - k * e^(- (r_d - r_f) * T) * N(d_2(sigma))) :param domestic_short_rate: :param foreign_short_rate: :param underlying: :param strike: :param annuity: :param price: :param days_to_maturity: :param pay_rec: :return: """ from NumericalLibrary.COptimiser import Optimiser from math import exp sigma_min = 0.0001 sigma_max = 10 tolerance = 1e-7 iteration_max = 100 # --- Sanity checks --- # r = domestic_short_rate - foreign_short_rate year_fraction = float(days_to_maturity) / 365 df = exp(-r * year_fraction) price_lb = 1e9 price_ub = 0 if pay_rec == "Payer" or pay_rec == "Call": price_lb = annuity * (underlying - strike * df) price_ub = annuity * underlying else: if pay_rec == "Receiver" or pay_rec == "Put": price_lb = annuity * (strike - underlying) price_ub = annuity * strike # P_t / A_t \in [i_s - i_k, i_s] if price < price_lb or price > price_ub: raise ValueError("Price not allowed in the Black model") if abs(price - price_lb) <= tolerance: raise ValueError("Price hits its lower bound. Impossible to calculate the implied vol") if abs(price - price_ub) <= tolerance: raise ValueError("Price hits its upper bound. Impossible to calculate the implied vol") # --- --- # def internal_calculate_price(sigma): return calculate_price(underlying, strike, annuity, domestic_short_rate, foreign_short_rate, sigma, days_to_maturity, pay_rec) optimiser = Optimiser(price, tolerance, iteration_max, internal_calculate_price) implied_vol = optimiser.brent_method(sigma_min, sigma_max) if abs(implied_vol - sigma_min) <= tolerance: raise ValueError("Hit lower bound. Algorithm might have not converged") if abs(implied_vol - sigma_max) <= tolerance: raise ValueError("Hit upper bound. Algorithm might have not converged") return implied_vol