def normal_histogram(mu, var, sz): nd = dist.NormalDistribution(mu, var) ####### ### transform the uniform sample ####### sample = [nd.inverse_cdf(u) for u in getUniformSample(sz)] num_bins = 60 hp = pu.PlotUtilities( "Histogram of Normal Sample with Mean={0}, Variance={1}".format( mu, var), 'Outcome', 'Rel. Occurrence') hp.plotHistogram(sample, num_bins)
def plot_bachelier_option_price(start, vol): lower_bound = start - 10. upper_bound = start + 10. step = 0.01 n_steps = int((upper_bound - lower_bound) / step) nd = dist.NormalDistribution(0., 1.) knock_out = 5 x_ax = [lower_bound + k * step for k in range(n_steps)] y_ax = [ vol * nd.pdf( (max(x,knock_out) - start) / vol ) - (x - start) * nd.cdf( (start - max(x, knock_out)) / vol ) for x in x_ax] # poisson distribution mp = pu.PlotUtilities("Bachelier Option Value as Function of Strike", "Option Strike", "Option Value") mp.multiPlot(x_ax, [y_ax], '-')
def lognormal_histogram(mu, var, sz): uniform_sample = getUniformSample(sz) nd = dist.NormalDistribution(0, var) ####### ### transform the uniform sample ####### ### strike = 70. sample = [''] * 2 sample[0] = [ mu * np.exp(nd.inverse_cdf(u) - 0.5 * var) for u in uniform_sample ] sample[1] = [max(s - strike, 0.) for s in sample[0]] num_bins = 75 hp = pu.PlotUtilities( "Histogram of Lognormal Sample with Mean={0}, Variance={1}".format( mu, var), 'Outcome', 'Rel. Occurrence') hp.plotHistogram([sample[0]], num_bins)
def moment_matching(p, sz_basket): ##### ## create a basket with random weights of size sz_basket ##### lower_bound = 0. upper_bound = 1. weights = np.random.uniform(lower_bound, upper_bound, sz_basket) ## calculate mean and variance of the basket expectation = 0 variance = 0 for k in range(sz_basket): expectation = expectation + weights[k] variance = variance + weights[k] * weights[k] expectation = expectation * dist.symmetric_binomial_expectation(p) variance = variance * dist.symmetric_binomial_variance(p) simulation = 50000 outcome = [0] * simulation for k in range(simulation): uni_sample = np.random.uniform(lower_bound, upper_bound, sz_basket) ####### ### transform the uniform sample ####### sample = range(sz_basket) for j in range(sz_basket): sample[j] = dist.symmetric_binomial_inverse_cdf(p, uni_sample[j]) for m in range(sz_basket): outcome[k] = outcome[k] + weights[m] * sample[m] num_bins = 50 plt.subplot(2,1,1) plt.title("Moment Matching of Binomial Basket of Size={0}".format(sz_basket)) # the histogram of the data n, bins, _hist = plt.hist(outcome, num_bins, normed=True, facecolor='blue', alpha=0.75) pdf_approx = [0.] * (num_bins+1) call_option_sampled = [0.] * (num_bins+1) call_option_approx = [0.] * (num_bins+1) nd = dist.NormalDistribution(expectation, variance) ###### overlay the moment matched pdf for i in range(0,num_bins+1): pdf_approx[i] = nd.pdf(bins[i]) call_option_approx[i] = nd.call_option(bins[i]) call_option_sampled[i] = 0. for k in range(simulation): if (outcome[k] >= bins[i]): call_option_sampled[i] = call_option_sampled[i] + (outcome[k] - bins[i]) / float(simulation) plt.xlabel('Outcome') plt.ylabel('Rel. Occurrence') plt.plot(bins, pdf_approx, 'r*') plt.subplot(2,1,2) plt.xlabel('Call Option Strike') plt.ylabel('Call Option Price') plt.plot(bins, call_option_sampled, 'b-') plt.plot(bins, call_option_approx, 'r*') plt.show()
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()
def conditional_default_prob(rho, p, z): nd = dist.NormalDistribution(0., 1.) y = (nd.inverse_cdf(p) - np.sqrt(rho) * z) / np.sqrt(1 - rho) return nd.cdf(y)
mp = pu.PlotUtilities('Probability Density Functions', 'x', 'PDF Value') mp.multiPlot(x_ax, y_ax) if __name__ == '__main__': m = 5 d = [0.] * m version = 1 if (version == 1): ### example of normal distributions with different $\sigma$ and $\mu = 0$. min_val = -5. max_val = 5. for k in range(m): d[k] = dist.NormalDistribution(0., 1. * (1. + float(k)) ) if (version == 2): min_val = -5. max_val = 5. ### example of normal distributions with different $\mu$ and $\sigma = 1$. for k in range(m): d[k] = dist.NormalDistribution(-2. + float(k), 1.) if (version == 3): ## example of Exponential distributions min_val = 0. max_val = 4. for k in range(m): d[k] = dist.ExponentialDistribution(0.5 * (1. + float(k))) plotMultiDistributions(d, min_val, max_val, 100)
def vasicek_large_portfolio_cdf(rho, p, x): nd = dist.NormalDistribution(0., 1.) y = (nd.inverse_cdf(x) * np.sqrt(1 - rho) - nd.inverse_cdf(p)) / np.sqrt(rho) return nd.cdf(y)
def u(self, _t, _x): nd = dist.NormalDistribution(_x, _t) return nd.excess_probability(self._strike)
def u(self, _t, _x): mean = (self.a - 0.5 * self.b * self.b) * _t variance = self.b * self.b * _t nd = dist.NormalDistribution(mean, variance) strk = np.log(self.strike / _x) return 1 - nd.cdf(strk)
def u(self, _t, _x): nd = dist.NormalDistribution(_x, _t) return nd.second_moment()
def u(self, _t, _x): nd = dist.NormalDistribution(_x, _t) return nd.expected_positive_exposure()
def u(self, _t, _x): nd = dist.NormalDistribution(_x, _t) return nd.pdf(self._start)
def moment_matching(p, sz_basket): ##### ## create a basket with random weights of size sz_basket ##### lower_bound = 0. upper_bound = 1. weights = np.random.uniform(lower_bound, upper_bound, sz_basket) ## calculate mean and variance of the basket expectation = sum(weights) * dist.symmetric_binomial_expectation(p) variance = sum([w * w for w in weights]) * dist.symmetric_binomial_variance(p) simulation = 50000 outcome = [0] * simulation for k in range(simulation): ####### ### sample the basket constituents and determine the outcome for each trial ####### uni_sample = np.random.uniform(lower_bound, upper_bound, sz_basket) sample = [ dist.symmetric_binomial_inverse_cdf(p, u) for u in uni_sample ] outcome[k] = sum([w * s for w, s in zip(weights, sample)]) num_bins = 50 plt.subplot(2, 1, 1) plt.title( "Moment Matching of Binomial Basket of Size={0}".format(sz_basket)) # the histogram of the data n, bins, _hist = plt.hist(outcome, num_bins, normed=True, facecolor='blue', alpha=0.75) nd = dist.NormalDistribution(expectation, variance) mc_weight = 1. / float(simulation) pdf_approx = [nd.pdf(b) for b in bins] call_option_approx = [nd.call_option(b) for b in bins] call_option_sampled = [ mc_weight * sum([max(oc - b, 0.) for oc in outcome]) for b in bins ] plt.xlabel('Outcome') plt.ylabel('Rel. Occurrence') plt.plot(bins, pdf_approx, 'r*') plt.subplot(2, 1, 2) plt.xlabel('Call Option Strike') plt.ylabel('Call Option Price') plt.plot(bins, call_option_sampled, 'b-') plt.plot(bins, call_option_approx, 'r*') plt.show()
if __name__ == '__main__': n_plots = 5 versions = [k for k in range(1, 5)] plotCDF = True for version in versions: title = '' if (version == 1): ### example of normal distributions with different $\sigma$ and $\mu = 0$. min_val = -5. max_val = 5. title = 'Normal Distribution with fixed $\mu$' d = [dist.NormalDistribution(0., 1. * (1. + float(k))) for k in range(n_plots)] elif (version == 2): ### example of normal distributions with different $\mu$ and $\sigma = 1$. min_val = -5. max_val = 5. title = 'Normal Distribution with fixed $\sigma$' d = [dist.NormalDistribution(-2. + float(k), 1.) for k in range(n_plots)] elif (version == 3): ## example of Exponential distributions min_val = 0. max_val = 10. title = 'Exponential Distribution' d = [dist.ExponentialDistribution(0.5 * (1. + float(k))) for k in range(n_plots)] elif (version == 4): min_val = -1. max_val = n_plots + 1