Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions ql/pricingengines/lookback/analyticcontinuousfixedlookback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <ql/exercise.hpp>
#include <ql/pricingengines/lookback/analyticcontinuousfixedlookback.hpp>
#include <cmath>
#include <utility>

namespace QuantLib {
Expand Down Expand Up @@ -123,9 +124,7 @@ namespace QuantLib {
Real powss = std::pow(ss, -lambda);
return eta*(underlying() * dividendDiscount() * N1 -
minmax() * riskFreeDiscount() * N2 -
underlying() * riskFreeDiscount() *
(powss * N3 - dividendDiscount()* N4/riskFreeDiscount())/
lambda);
underlying() * riskFreeDiscount() * ratio(lambda, d1, N3, N4, powss, eta));
}

Real AnalyticContinuousFixedLookbackEngine::B(Real eta) const {
Expand All @@ -141,9 +140,16 @@ namespace QuantLib {
Real powss = std::pow(ss, -lambda);
return eta*(underlying() * dividendDiscount() * N1 -
strike() * riskFreeDiscount() * N2 -
underlying() * riskFreeDiscount() *
(powss * N3 - dividendDiscount()* N4/riskFreeDiscount())/
lambda);
underlying() * riskFreeDiscount() * ratio(lambda, d1, N3, N4, powss, eta));
}

Real AnalyticContinuousFixedLookbackEngine::ratio(Real lambda, Real d1, Real N3, Real N4,
Real powss, Real eta) const {
// with no carry lambda vanishes and the ratio is 0/0; its limit
// is -stdDev * (d1 * N(eta * d1) + eta * n(d1))
if (std::fabs(lambda) < 1.0e-7)
return -stdDeviation() * (d1 * N4 + eta * f_.derivative(d1));
return (powss * N3 - dividendDiscount() * N4 / riskFreeDiscount()) / lambda;
}

Real AnalyticContinuousFixedLookbackEngine::C(Real eta) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ namespace QuantLib {
Real A(Real eta) const;
Real B(Real eta) const;
Real C(Real eta) const;
Real ratio(Real lambda, Real d1, Real N3, Real N4, Real powss, Real eta) const;
};

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <ql/exercise.hpp>
#include <ql/pricingengines/lookback/analyticcontinuousfloatinglookback.hpp>
#include <cmath>
#include <utility>

namespace QuantLib {
Expand Down Expand Up @@ -100,11 +101,14 @@ namespace QuantLib {
Real n3 = f_(eta*(-d1+lambda*stdDeviation()));
Real n4 = f_(eta*-d1);
Real pow_s = std::pow(s, -lambda);
// with no carry lambda vanishes and the ratio below is 0/0; its limit
// is stdDev * (eta * n(d1) - d1 * N(-eta * d1))
Real ratio = std::fabs(lambda) < 1.0e-7
? stdDeviation() * (eta * f_.derivative(d1) - d1 * n4)
: (pow_s * n3 - dividendDiscount() * n4 / riskFreeDiscount()) / lambda;
return eta*((underlying() * dividendDiscount() * n1 -
minmax() * riskFreeDiscount() * n2) +
(underlying() * riskFreeDiscount() *
(pow_s * n3 - dividendDiscount()* n4/riskFreeDiscount())/
lambda));
underlying() * riskFreeDiscount() * ratio);
}

}
Expand Down
86 changes: 86 additions & 0 deletions test-suite/lookbackoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,92 @@ BOOST_AUTO_TEST_CASE(testAnalyticContinuousFixedLookback) {
}
}

BOOST_AUTO_TEST_CASE(testAnalyticContinuousLookbackZeroCarry) {

BOOST_TEST_MESSAGE(
"Testing analytic continuous lookback options with zero carry...");

// with r equal to q the formulas are 0/0; the expected values are their
// limit, evaluated in 50-digit arithmetic

LookbackOptionData floatingValues[] = {
// type, strike, minmax, s, q, r, t, v, l, t1, result, tol
{ Option::Call, 0, 90, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 21.817075601551579, 1.0e-8},
{ Option::Put, 0, 110, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 26.407720137984153, 1.0e-8},
};

LookbackOptionData fixedValues[] = {
// type, strike, minmax, s, q, r, t, v, l, t1, result, tol
{ Option::Call, 95, 110, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 31.163867260487723, 1.0e-8},
{ Option::Call, 105, 100, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 20.604933499041011, 1.0e-8},
{ Option::Put, 105, 90, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 26.573222724055149, 1.0e-8},
{ Option::Put, 95, 100, 100.0, 0.05, 0.05, 1.00, 0.30, 0, 0, 16.226584162874658, 1.0e-8},
};

DayCounter dc = Actual360();
Date today = Date::todaysDate();

ext::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0));
ext::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0));
ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc);
ext::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0));
ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc);
ext::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0));
ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc);

ext::shared_ptr<BlackScholesMertonProcess> stochProcess(
new BlackScholesMertonProcess(
Handle<Quote>(spot),
Handle<YieldTermStructure>(qTS),
Handle<YieldTermStructure>(rTS),
Handle<BlackVolTermStructure>(volTS)));

for (auto& value : floatingValues) {
ext::shared_ptr<Exercise> exercise(
new EuropeanExercise(today + timeToDays(value.t)));
spot->setValue(value.s);
qRate->setValue(value.q);
rRate->setValue(value.r);
vol->setValue(value.v);

ext::shared_ptr<FloatingTypePayoff> payoff(new FloatingTypePayoff(value.type));
ContinuousFloatingLookbackOption option(value.minmax, payoff, exercise);
option.setPricingEngine(ext::shared_ptr<PricingEngine>(
new AnalyticContinuousFloatingLookbackEngine(stochProcess)));

Real calculated = option.NPV();
Real error = std::fabs(calculated - value.result);
if (!(error <= value.tol)) {
REPORT_FAILURE_FLOATING("value", value.minmax, payoff, exercise, value.s, value.q,
value.r, today, value.v, value.result, calculated, error,
value.tol);
}
}

for (auto& value : fixedValues) {
ext::shared_ptr<Exercise> exercise(
new EuropeanExercise(today + timeToDays(value.t)));
spot->setValue(value.s);
qRate->setValue(value.q);
rRate->setValue(value.r);
vol->setValue(value.v);

ext::shared_ptr<StrikedTypePayoff> payoff(
new PlainVanillaPayoff(value.type, value.strike));
ContinuousFixedLookbackOption option(value.minmax, payoff, exercise);
option.setPricingEngine(ext::shared_ptr<PricingEngine>(
new AnalyticContinuousFixedLookbackEngine(stochProcess)));

Real calculated = option.NPV();
Real error = std::fabs(calculated - value.result);
if (!(error <= value.tol)) {
REPORT_FAILURE_FIXED("value", value.minmax, payoff, exercise, value.s, value.q,
value.r, today, value.v, value.result, calculated, error,
value.tol);
}
}
}

BOOST_AUTO_TEST_CASE(testAnalyticContinuousPartialFloatingLookback) {

BOOST_TEST_MESSAGE(
Expand Down
Loading