Math-Business-BlackScholes-Binaries-Greeks

 view release on metacpan or  search on metacpan

lib/Math/Business/BlackScholes/Binaries/Greeks/Volga.pm  view on Meta::CPAN

    # $w = 0, paid at hit
    # $w = 1, paid at end
    if (not defined $w) { $w = 0; }

    return ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w) + ot_down_ko_up_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w);
}

sub w_common_function_pelsser_1997 {
    my ($S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta) = @_;

    my $pi = Math::Trig::pi;

    my $h = log($U / $D);
    my $x = log($S / $D);

    # $eta = 1, onetouch up knockout down
    # $eta = 0, onetouch down knockout up
    # This variable used to check stability
    if (not defined $eta) {
        die
            "$0: (w_common_function_pelsser_1997) Wrong usage of this function for S=$S, U=$U, D=$D, t=$t, r_q=$r_q, mu=$mu, vol=$vol, w=$w. eta not defined.";
    }
    if ($eta == 0) { $x = $h - $x; }

    my $mu_new = $mu - (0.5 * $vol * $vol);
    my $mu_dash = sqrt(max($Math::Business::BlackScholesMerton::Binaries::SMALL_VALUE_MU, ($mu_new * $mu_new) + (2 * $vol * $vol * $r_q * (1 - $w))));

    my $r_dash = $r_q * (1 - $w);
    my $omega = ($vol * $vol);

    my $series_part = 0;
    my $hyp_part    = 0;

    my $stability_constant =
        Math::Business::BlackScholesMerton::Binaries::get_stability_constant_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, $eta, 1);

    my $iterations_required = Math::Business::BlackScholesMerton::Binaries::get_min_iterations_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w);

    for (my $k = 1; $k < $iterations_required; $k++) {
        my $lambda_k_dash = (0.5 * (($mu_dash * $mu_dash) / ($vol * $vol) + ($k * $k * $pi * $pi * $vol * $vol) / ($h * $h)));

        # d{lambda_k}/dw
        my $dlambdak_domega = 0.5 * (-($mu_new / $omega) - (($mu_new * $mu_new) / ($omega * $omega)) + (($k * $k * $pi * $pi) / ($h * $h)));
        my $d2lambdak_domega2 = 0.5 * ($omega + 2 * $mu_new) / (2 * $omega * $omega);
        $d2lambdak_domega2 *= (1 + (2 * $mu_new / $omega));

        # d{beta_k}/d{lambda_k}
        my $dbetak_dlambdak = -exp(-$lambda_k_dash * $t) * (($t * $lambda_k_dash + 1) / ($lambda_k_dash**2));
        my $d2betak_dlambdak2 = -($t * $dbetak_dlambdak) + exp(-$lambda_k_dash * $t) * (($t / ($lambda_k_dash**2)) + (2 / ($lambda_k_dash**3)));

        # d{beta_k}/dw
        my $dbetak_domega = $dlambdak_domega * $dbetak_dlambdak;
        my $d2betak_domega2 = ($dlambdak_domega * $dlambdak_domega * $d2betak_dlambdak2) + ($dbetak_dlambdak * $d2lambdak_domega2);

        my $phi = (1.0 / ($h * $h)) * ($omega * $d2betak_domega2 + 2 * $dbetak_domega) * $k;

        $series_part += $phi * $pi * sin($k * $pi * ($h - $x) / $h);

        if ($k == 1 and (not(abs(4 * $vol * $vol * $phi) < $stability_constant))) {
            die
                "$0: PELSSER VOLGA formula for S=$S, U=$U, D=$D, t=$t, r_q=$r_q, mu=$mu, vol=$vol, w=$w, eta=$eta cannot be evaluated because PELSSER VOLGA stability conditions (4 * $vol * $vol * $phi less than $stability_constant) not met. This coul...
        }
    }

    my $alpha = $mu_dash / ($vol * $vol);
    my $dalpha_domega = -(($mu_new * $omega) + (2 * $mu_new * $mu_new) + (2 * $r_dash * $omega)) / (2 * $alpha * $omega * $omega * $omega);

    my $d2alpha_domega2 = $alpha * ($omega**3) * (2 * $mu_new + $omega - 4 * $r_dash);
    $d2alpha_domega2 +=
        (($mu_new * $omega) + (2 * $mu_new * $mu_new) + (2 * $r_dash * $omega)) *
        ((6 * $alpha * $omega * $omega) + (2 * $omega * $omega * $omega * $dalpha_domega));
    $d2alpha_domega2 = $d2alpha_domega2 / (4 * $alpha * $alpha * ($omega**6));

    # We have to handle the special case where the denominator approaches 0, see our documentation in
    # quant/Documents/Breakout_bet.tex under the SVN "quant" module.
    my $hyp_part1;
    if ((Math::Trig::sinh($alpha * $h)**3) == 0) {
        $hyp_part1 = 0;
    } else {
        $hyp_part1 =
            Math::Trig::sinh($alpha * $h) *
            ($h**2 - $x**2) *
            (Math::Trig::cosh($alpha * ($h - $x)) - Math::Trig::cosh($alpha * ($h + $x))) -
            (2 * $h * Math::Trig::cosh($alpha * $h)) *
            ((($h + $x) * Math::Trig::sinh($alpha * ($h - $x))) - (($h - $x) * Math::Trig::sinh($alpha * ($h + $x))));
        $hyp_part1 *= ($dalpha_domega**2) / (2 * (Math::Trig::sinh($alpha * $h)**3));
    }

    my $hyp_part2;
    if ((Math::Trig::sinh($alpha * $h)**2) == 0) {
        $hyp_part2 = 0;
    } else {
        $hyp_part2 =
            ($d2alpha_domega2 / (2 * (Math::Trig::sinh($alpha * $h)**2))) *
            (($h + $x) * Math::Trig::sinh($alpha * ($h - $x)) - ($h - $x) * Math::Trig::sinh($alpha * ($h + $x)));
    }

    $hyp_part = $hyp_part1 + $hyp_part2;

    my $d2c_domega2 = ($hyp_part - $series_part) * exp(-$r_q * $w * $t);

    return $d2c_domega2;
}

sub ot_up_ko_down_pelsser_1997 {
    my ($S, $U, $D, $t, $r_q, $mu, $vol, $w) = @_;

    my $mu_new = $mu - (0.5 * $vol * $vol);
    my $h      = log($U / $D);
    my $x      = log($S / $D);
    my $omega  = ($vol * $vol);

    my $c = Math::Business::BlackScholesMerton::Binaries::common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 1);
    my $dc_domega = Math::Business::BlackScholes::Binaries::Greeks::Vega::w_common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 1);
    my $d2c_domega2 = w_common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w, 1);

    my $Vu = Math::Business::BlackScholesMerton::Binaries::ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $vol, $w);
    my $dVu_domega = -((0.5 * $omega + $mu_new) * ($h - $x) / ($omega * $omega)) * $c;
    $dVu_domega += $dc_domega;
    $dVu_domega *= exp($mu_new * ($h - $x) / $omega);



( run in 2.050 seconds using v1.01-cache-2.11-cpan-d80b1682f3f )