Math-Business-BlackscholesMerton

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

lib/Math/Business/BlackScholesMerton/Binaries.pm
lib/Math/Business/BlackScholesMerton/NonBinaries.pm
t/00-check-deps.t
t/00-compile.t
t/00-report-prereqs.dd
t/00-report-prereqs.t
t/BlackScholes.t
t/barrier_infinity.t
t/barrier_zero.t
t/benchmark.t
t/get_min_iterations_pelsser.t
t/get_stability_constant_pelsser_1997.t
t/lib/Roundnear.pm
t/min_accuracy_pelsser.t
t/negative_rate.t
t/price_test.t
t/pricing_params.csv
t/rc/.perlcriticrc
t/rc/.perltidyrc
t/small_value_mu.t
t/smalltime.t

lib/Math/Business/BlackScholesMerton/Binaries.pm  view on Meta::CPAN

    # one barrier is already hit (can happen due to shift markup):
    if ($S >= $U or $S <= $D) {
        return $w ? exp(-$t * $r_q) : 1;
    }

#
# SANITY CHECKS
#
# For extreme cases, the price will be wrong due the values in the
# infinite series getting too large or too small, which causes
# roundoff errors in the computer. Thus no matter how many iterations
# you make, the errors will never go away.
#
# For example try this:
#
#   my ($S, $U, $D, $t, $r, $q, $vol, $w)
#       = (100.00, 118.97, 99.00, 30/365, 0.1, 0.02, 0.01, 1);
#   $up_price = Math::Business::BlackScholesMerton::Binaries::ot_up_ko_down_pelsser_1997(
#       $S,$U,$D,$t,$r,$q,$vol,$w);
#   $down_price= Math::Business::BlackScholesMerton::Binaries::ot_down_ko_up_pelsser_1997(
#       $S,$U,$D,$t,$r,$q,$vol,$w);

lib/Math/Business/BlackScholesMerton/Binaries.pm  view on Meta::CPAN

    my $mu_dash = sqrt(max(0, ($mu_new * $mu_new) + (2 * $sigma * $sigma * $r_q * (1 - $w))));

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

    # These constants will determine whether or not this contract can be
    # evaluated to a predefined accuracy. It is VERY IMPORTANT because
    # if these conditions are not met, the prices can be complete nonsense!!
    my $stability_constant = get_stability_constant_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $eta, 1);

    # The number of iterations is important when recommending the
    # range of the upper/lower barriers on our site. If we recommend
    # a range that is too big and our iteration is too small, the
    # price will be wrong! We must know the rate of convergence of
    # the formula used.
    my $iterations_required = get_min_iterations_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w);

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

        my $phi = ($sigma * $sigma) / ($h * $h) * exp(-$lambda_k_dash * $t) * $k / $lambda_k_dash;

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

        #
        # Note that greeks may also call this function, and their
        # stability constant will differ. However, for simplicity
        # we will not bother (else the code will get messy), and

lib/Math/Business/BlackScholesMerton/Binaries.pm  view on Meta::CPAN


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

    my $mu_new = $mu - (0.5 * $sigma * $sigma);
    my $x = log($S / $D);

    return exp(-$mu_new * $x / ($sigma * $sigma)) * common_function_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, 0);
}

=head2 get_min_iterations_pelsser_1997

    USAGE
    my $min = get_min_iterations_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy)

    DESCRIPTION
    An estimate of the number of iterations required to achieve a certain
    level of accuracy in the price.

=cut

sub get_min_iterations_pelsser_1997 {
    my ($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy) = @_;

    if (not defined $accuracy) {
        $accuracy = $MIN_ACCURACY_UPORDOWN_PELSSER_1997;
    }

    if ($accuracy > $MIN_ACCURACY_UPORDOWN_PELSSER_1997) {
        $accuracy = $MIN_ACCURACY_UPORDOWN_PELSSER_1997;
    } elsif ($accuracy <= 0) {
        $accuracy = $MIN_ACCURACY_UPORDOWN_PELSSER_1997;
    }

    my $it_up = _get_min_iterations_ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy);
    my $it_down = _get_min_iterations_ot_down_ko_up_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy);

    my $min = max($it_up, $it_down);

    return $min;
}

=head2 _get_min_iterations_ot_up_ko_down_pelsser_1997

    USAGE
    my $k_min = _get_min_iterations_ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy)

    DESCRIPTION
    An estimate of the number of iterations required to achieve a certain
    level of accuracy in the price for ONETOUCH-UP-KNOCKOUT-DOWN.

=cut

sub _get_min_iterations_ot_up_ko_down_pelsser_1997 {
    my ($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy) = @_;

    if (!defined $accuracy) {
        die "accuracy required";
    }

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

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

lib/Math/Business/BlackScholesMerton/Binaries.pm  view on Meta::CPAN

    my $mu_dash = sqrt(max(0, ($mu_new * $mu_new) + (2 * $sigma * $sigma * $r_q * (1 - $w))));

    my $A = ($mu_dash * $mu_dash) / (2 * $sigma * $sigma);
    my $B = ($pi * $pi * $sigma * $sigma) / (2 * $h * $h);

    my $delta_dash = $accuracy;
    my $delta = $delta_dash * exp(-$mu_new * ($h - $x) / ($sigma * $sigma)) * (($h * $h) / ($pi * $sigma * $sigma));

    # This can happen when stability condition fails
    if ($delta * $B <= 0) {
        die "(_get_min_iterations_ot_up_ko_down_pelsser_1997) Cannot "
            . "evaluate minimum iterations because too many iterations "
            . "required!! delta=$delta, B=$B for input parameters S=$S, "
            . "U=$U, D=$D, t=$t, r_q=$r_q, mu=$mu, sigma=$sigma, w=$w, "
            . "accuracy=$accuracy";
    }

    # Check that condition is satisfied
    my $condition = max(exp(-$A * $t) / ($B * $delta), 1);

    my $k_min = log($condition) / ($B * $t);
    $k_min = sqrt($k_min);

lib/Math/Business/BlackScholesMerton/Binaries.pm  view on Meta::CPAN


        return $MIN_ITERATIONS_UPORDOWN_PELSSER_1997;
    } elsif ($k_min > $MAX_ITERATIONS_UPORDOWN_PELSSER_1997) {

        return $MAX_ITERATIONS_UPORDOWN_PELSSER_1997;
    }

    return int($k_min);
}

=head2 _get_min_iterations_ot_down_ko_up_pelsser_1997

    USAGE

    DESCRIPTION
    An estimate of the number of iterations required to achieve a certain
    level of accuracy in the price for ONETOUCH-UP-KNOCKOUT-UP.

=cut

sub _get_min_iterations_ot_down_ko_up_pelsser_1997 {
    my ($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy) = @_;

    my $h = log($U / $D);
    my $mu_new = $mu - (0.5 * $sigma * $sigma);

    $accuracy = $accuracy * exp($mu_new * $h / ($sigma * $sigma));

    return _get_min_iterations_ot_up_ko_down_pelsser_1997($S, $U, $D, $t, $r_q, $mu, $sigma, $w, $accuracy);
}

=head2 range

    USAGE
    my $price = range($S, $U, $D, $t, $r_q, $mu, $sigma, $w)

    PARAMS
    $S stock price
    $t time (1 = 1 year)

t/get_min_iterations_pelsser.t  view on Meta::CPAN

use Roundnear;

my $S         = 1.35;
my $barrier_u = 1.36;
my $barrier_l = 1.34;
my $t         = 7 / 365;
my $sigma     = 0.11;
my $r         = 0.002;
my $q         = 0.001;

my $min_iterations =
    Math::Business::BlackScholesMerton::Binaries::get_min_iterations_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q, $sigma, 0,);
ok($min_iterations == 16, 'min_iterations (no accuracy specified)');

$min_iterations =
    Math::Business::BlackScholesMerton::Binaries::get_min_iterations_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q, $sigma, 0, 1);
ok($min_iterations == 16, 'min_iterations (accuracy 1)');

$min_iterations =
    Math::Business::BlackScholesMerton::Binaries::get_min_iterations_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q, $sigma, 0, -1);
ok($min_iterations == 16, 'min_iterations (accuracy 1)');

throws_ok {
    $min_iterations =
        Math::Business::BlackScholesMerton::Binaries::_get_min_iterations_ot_up_ko_down_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q,
        $sigma, 0);
}
qr/accuracy required/, 'accuracy required';

throws_ok {
    $min_iterations =
        Math::Business::BlackScholesMerton::Binaries::_get_min_iterations_ot_up_ko_down_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q,
        $sigma, 0, -1);
}
qr/too many iterations required/, 'too many iterations required';

$Math::Business::BlackScholesMerton::Binaries::MIN_ITERATIONS_UPORDOWN_PELSSER_1997 = -1;
$Math::Business::BlackScholesMerton::Binaries::MAX_ITERATIONS_UPORDOWN_PELSSER_1997 = -1;
$min_iterations =
    Math::Business::BlackScholesMerton::Binaries::_get_min_iterations_ot_up_ko_down_pelsser_1997($S, $barrier_u, $barrier_l, $t, $r, $r - $q, $sigma,
    0, 1);
ok($min_iterations == -1, 'min_iterations (accuracy 1)');

Test::NoWarnings::had_no_warnings();
done_testing();

xt/author/eol.t  view on Meta::CPAN

    'lib/Math/Business/BlackScholesMerton/Binaries.pm',
    'lib/Math/Business/BlackScholesMerton/NonBinaries.pm',
    't/00-check-deps.t',
    't/00-compile.t',
    't/00-report-prereqs.dd',
    't/00-report-prereqs.t',
    't/BlackScholes.t',
    't/barrier_infinity.t',
    't/barrier_zero.t',
    't/benchmark.t',
    't/get_min_iterations_pelsser.t',
    't/get_stability_constant_pelsser_1997.t',
    't/lib/Roundnear.pm',
    't/min_accuracy_pelsser.t',
    't/negative_rate.t',
    't/price_test.t',
    't/pricing_params.csv',
    't/rc/.perlcriticrc',
    't/rc/.perltidyrc',
    't/small_value_mu.t',
    't/smalltime.t',



( run in 1.621 second using v1.01-cache-2.11-cpan-71847e10f99 )