def correlated_defaults_scatter(lambda_1, lambda_2, rhos, size): tau_2 = [0] * len(rhos) sns = np.random.standard_normal(2 * size) x = [sns[k] for k in range(size)] tau_1 = [ dist.exponential_inverse_cdf(lambda_1, dist.standard_normal_cdf(x1)) for x1 in x ] index = 0 for rho in rhos: y = [ rho * sns[k] + np.sqrt(1 - rho * rho) * sns[k + size] for k in range(size) ] tau_2[index] = [ dist.exponential_inverse_cdf(lambda_2, dist.standard_normal_cdf(y1)) for y1 in y ] index = index + 1 ### scatter plot of the simulated defaults colors = ['blue', 'green', 'orange', 'red', 'yellow'] mp = pu.PlotUtilities('Default Times with Correlations={0}'.format(rhos), 'x', 'y') mp.scatterPlot(tau_1, tau_2, rhos, colors)
def plot_bachelier_digital_option(_time, _timestep, _strike): ####### ## call helper function to generate sufficient symmetric binomials ####### size = int(_time / _timestep) sample = np.random.normal(0, np.sqrt(_timestep), size) path_bm = [sum(sample[0:n]) for n in range(size)] x = [_timestep * k for k in range(size)] remaining_time = [np.sqrt(_time - x_i) for x_i in x] ## theoretical option value over time on a single path path_digital_option = [ 1 - dist.standard_normal_cdf((_strike - bm) / rt) for (bm, rt) in zip(path_bm, remaining_time) ] hedge_proportion = [0] * (size) path_digital_option_hedge = [0] * (size) #### ## plot the trajectory of the process #### _t_remain = remaining_time[0] path_digital_option_hedge[0] = path_digital_option[0] hedge_proportion[0] = dist.standard_normal_pdf( (_strike - path_bm[0]) / _t_remain) / _t_remain for j in range(1, size): _t_remain = remaining_time[j] hedge_proportion[j] = dist.standard_normal_pdf( (_strike - path_bm[j - 1]) / _t_remain) / _t_remain path_digital_option_hedge[j] = path_digital_option_hedge[ j - 1] + sample[j] * hedge_proportion[j] mp = pu.PlotUtilities("Paths of Digital Option Value", 'Time', "Option Value") trackHedgeOnly = True if (trackHedgeOnly): mp.multiPlot(x, [path_digital_option, path_digital_option_hedge]) else: arg = [ 'Option Value', 'Hedge Proportion', 'Underlying Brownian Motion' ] colors = ['green', 'red', 'blue'] mp = pu.PlotUtilities("Paths of Digital Option Value", 'Time', "Option Value") mp.subPlots(x, [path_digital_option, hedge_proportion, path_bm], arg, colors)
def plot_maximising_goal_probability(_time, _timestep, _initial_capital, _target, _b, _r, _sigma): ####### ## call helper function to generate sufficient symmetric binomials ####### size = int(_time / _timestep) - 1 sample = np.random.normal(0, np.sqrt(_timestep), size) path_underlying = [1.] * (size) path_wealth = [_initial_capital] * (size) path_portfolio = [0] * (size) x = [_timestep * k for k in range(size)] _theta = (_b - _r) / _sigma _y0 = np.sqrt(_time) * dist.standard_normal_inverse_cdf( _initial_capital * np.exp(_r * _time) / _target) #### ## create the various paths for plotting #### bm = 0 _y = path_wealth[0] * np.exp(_r * _time) / _target path_portfolio[0] = dist.standard_normal_pdf( dist.standard_normal_inverse_cdf(_y)) / (_y * _sigma * np.sqrt(_time)) for j in range(1, size): _t_remain = _time - x[j] _t_sq_remain = np.sqrt(_t_remain) path_underlying[j] = path_underlying[j - 1] * (1. + _b * _timestep + _sigma * sample[j]) bm = bm + sample[j] + _theta * _timestep path_wealth[j] = _target * np.exp( - _r * _t_remain ) * \ dist.standard_normal_cdf((bm + _y0) / _t_sq_remain) _y = path_wealth[j] * np.exp(_r * _t_remain) / _target path_portfolio[j] = dist.standard_normal_pdf( dist.standard_normal_inverse_cdf(_y)) / (_y * _sigma * _t_sq_remain) mp = pu.PlotUtilities("Maximising Probability of Reaching a Goal", 'Time', "None") labels = ['Stock Price', 'Wealth Process', 'Portfolio Value'] mp.subPlots(x, [path_underlying, path_wealth, path_portfolio], labels, ['red', 'blue', 'green'])
def variance_normal_digital(strike): x_label = 'shift' y_label = 'Variance' chart_title = 'Sample Variance Under Exponential Tilting (Normal)' min_val = strike - 2. max_val = strike + 2. steps = 1000 step = (max_val - min_val) / steps x_ax = [min_val + step * k for k in range(steps)] y_ax = [ np.exp(x * x) * dist.standard_normal_cdf(-strike - x) for x in x_ax ] mp = pu.PlotUtilities(chart_title, x_label, y_label) mp.multiPlot(x_ax, [y_ax])
def excess_probability_payoff(_strike, _mean, _variance): return 1 - dist.standard_normal_cdf((_strike - _mean) / np.sqrt(_variance))
def expected_positive_exposure(_mean, _variance): y = _mean / np.sqrt(_variance) return _mean * dist.standard_normal_cdf(y) + np.sqrt(_variance) * dist.standard_normal_pdf(y)
def malliavin_greeks(start, vol, strike, digitalPayout = False): ## we calculate the option value of a call option $(X-K)^+$ where the underlying is of the form $X = x_0 + sigma W$ with $W$ standard normal ## the aim is to calculate the sensitivities of the option price with respect to the x_0 both in bump and reval and with logarithmic Malliavin weights nd = dist.NormalDistribution(start, vol * vol) y = (start - strike) / vol if (digitalPayout): theo_option_price = nd.cdf(y) act_delta = dist.standard_normal_pdf(y) / vol act_gamma = - y * dist.standard_normal_pdf(y) / vol / vol else: theo_option_price = nd.call_option(strike) act_delta = dist.standard_normal_cdf(y) act_gamma = dist.standard_normal_pdf(y) / vol perturbation = 1.e-08 # print (str("Theoretical Price: ") + str(theo_option_price)) # print (str("Theoretical Delta: ") + str(act_delta)) # print (str("Theoretical Gamma: ") + str(act_gamma)) repeats = 500 sample_delta = [0.] * 2 sample_delta[0] = [0] * repeats # this is the sample for the delta with B&R approach sample_delta[1] = [0] * repeats # this is the sample for the delta with Malliavin logarithmic trick sample_gamma = [0.] * 2 sample_gamma[0] = [0] * repeats # this is the sample for the gamma with B&R approach sample_gamma[1] = [0] * repeats # this is the sample for the gamma with Malliavin logarithmic sz = 5000 total_sz = sz * repeats normal_sample = np.random.normal(0, 1, total_sz) for z in range(repeats): thisNormalSample = normal_sample[z * sz : (z+1) * sz] if (digitalPayout): option_value = sum([(0 if start + vol * ns < strike else 1.) for ns in thisNormalSample]) malliavin_delta = sum([(0 if start + vol * ns < strike else 1.) * ns / vol for ns in thisNormalSample]) malliavin_gamma = sum([(0 if start + vol * ns < strike else 1.) * (ns * ns - 1) / (vol * vol) for ns in thisNormalSample]) option_value_pert = sum([(0 if start + perturbation + vol * ns < strike else 1.) for ns in thisNormalSample]) option_value_pert_down = sum([(0 if start - perturbation + vol * ns < strike else 1.) for ns in thisNormalSample]) else: option_value = sum([max(start + vol * ns - strike, 0.) for ns in thisNormalSample]) malliavin_delta = sum([max(start + vol * ns - strike, 0.) * (ns) / (vol) for ns in thisNormalSample]) malliavin_gamma = sum([max(start + vol * ns - strike, 0.) * (ns * ns - 1) / (vol * vol) for ns in thisNormalSample]) option_value_pert = sum([max(start + perturbation + vol * ns - strike, 0.) for ns in thisNormalSample]) option_value_pert_down = sum([max(start - perturbation + vol * ns - strike, 0.) for ns in thisNormalSample]) sample_delta[0][z] = (option_value_pert - option_value) / sz / perturbation sample_delta[1][z] = malliavin_delta / sz sample_gamma[0][z] = ( option_value_pert - 2 * option_value + option_value_pert_down) / sz / perturbation / perturbation sample_gamma[1][z] = malliavin_gamma / sz ####### ### prepare and show plot ### num_bins = 25 print (np.var(sample_delta[0])) print (np.var(sample_delta[1])) plotGamma = False totalPlots = (2 if plotGamma else 1) ### Subplot for Delta Calculation plt.subplot(totalPlots, 1, 1) plt.xlabel('Outcome') plt.ylabel('Rel. Occurrence') plt.title("B + R vs Malliavin Delta (Value={0})".format(act_delta)) n, bins, _hist = plt.hist(sample_delta[0], num_bins, normed=True, facecolor='orange', alpha=0.5) n, bins, _hist = plt.hist(sample_delta[1], num_bins, normed=True, facecolor='blue', alpha=0.75) ### Subplot for Gamma Calculation if (plotGamma): plt.subplot(totalPlots, 1, 2) plt.xlabel('Outcome') plt.ylabel('Rel. Occurrence') plt.title("B + R vs Malliavin Gamma (Value={0})".format(act_gamma)) n, bins, _hist = plt.hist(sample_gamma[0], num_bins, normed=True, facecolor='orange', alpha=0.55) n, bins, _hist = plt.hist(sample_gamma[1], num_bins, normed=True, facecolor='blue', alpha=0.75) plt.show()