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'])
Esempio n. 3
0
def binomial_clt_hist(sample_size, repeats, p):

    ### plot histogram of Average value of normalised Binomial Distributions

    sample_value = [0.] * repeats
    num_bins = 35
    for i in range(repeats):

        ######
        ## Step 1 - create sample of independent uniform random variables

        lower_bound = 0.
        upper_bound = 1.
        uni_sample = np.random.uniform(lower_bound, upper_bound, sample_size)

        ######
        ## Step 2 - transform them to $B(1,p)$ distribution

        sample = [dist.binomial_inverse_cdf(p, u) for u in uni_sample]
        sample_value[i] = (sum(sample) - sample_size * p) / np.sqrt(
            sample_size * p * (1 - p))

    plt.xlabel('Outcome')
    plt.ylabel('Relative Occurrence')
    plt.title(
        "Histogram of Normalised Binomial Average For Sample of Size={0}".
        format(sample_size))

    _n, bins, _hist = plt.hist(sample_value,
                               num_bins,
                               normed=True,
                               facecolor='green',
                               alpha=0.75)

    y = [dist.standard_normal_pdf(b) for b in bins]
    plt.plot(bins, y, 'r--')
    plt.show()
    plt.close()
Esempio n. 4
0
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()