21#include <ql/exercise.hpp>
22#include <ql/math/comparison.hpp>
23#include <ql/math/distributions/normaldistribution.hpp>
24#include <ql/pricingengines/blackcalculator.hpp>
25#include <ql/pricingengines/blackformula.hpp>
26#include <ql/pricingengines/vanilla/baroneadesiwhaleyengine.hpp>
32 ext::shared_ptr<GeneralizedBlackScholesProcess> process)
33 : process_(
std::move(process)) {
40 const ext::shared_ptr<StrikedTypePayoff>& payoff,
46 Real n= 2.0*std::log(dividendDiscount/riskFreeDiscount)/(variance);
47 Real m=-2.0*std::log(riskFreeDiscount)/(variance);
48 Real bT = std::log(dividendDiscount/riskFreeDiscount);
51 switch (payoff->optionType()) {
53 qu = (-(n-1.0) + std::sqrt(((n-1.0)*(n-1.0)) + 4.0*m))/2.0;
54 Su = payoff->strike() / (1.0 - 1.0/qu);
55 h = -(bT + 2.0*std::sqrt(variance)) * payoff->strike() /
56 (Su - payoff->strike());
57 Si = payoff->strike() + (Su - payoff->strike()) *
61 qu = (-(n-1.0) - std::sqrt(((n-1.0)*(n-1.0)) + 4.0*m))/2.0;
62 Su = payoff->strike() / (1.0 - 1.0/qu);
63 h = (bT - 2.0*std::sqrt(variance)) * payoff->strike() /
64 (payoff->strike() - Su);
65 Si = Su + (payoff->strike() - Su) * std::exp(h);
68 QL_FAIL(
"unknown option type");
74 Real forwardSi = Si * dividendDiscount / riskFreeDiscount;
75 Real d1 = (std::log(forwardSi/payoff->strike()) + 0.5*variance) /
78 Real K = (!
close(riskFreeDiscount, 1.0, 1000))
79 ?
Real(-2.0*std::log(riskFreeDiscount)
80 / (variance*(1.0-riskFreeDiscount)))
83 forwardSi, std::sqrt(variance))*riskFreeDiscount;
84 switch (payoff->optionType()) {
86 Q = (-(n-1.0) + std::sqrt(((n-1.0)*(n-1.0)) + 4 * K)) / 2;
87 LHS = Si - payoff->strike();
88 RHS = temp + (1 - dividendDiscount * cumNormalDist(d1)) * Si / Q;
89 bi = dividendDiscount * cumNormalDist(d1) * (1 - 1/Q) +
90 (1 - dividendDiscount *
91 cumNormalDist.
derivative(d1) / std::sqrt(variance)) / Q;
92 while (std::fabs(LHS - RHS)/payoff->strike() > tolerance) {
93 Si = (payoff->strike() + RHS - bi * Si) / (1 - bi);
94 forwardSi = Si * dividendDiscount / riskFreeDiscount;
95 d1 = (std::log(forwardSi/payoff->strike())+0.5*variance)
97 LHS = Si - payoff->strike();
99 forwardSi, std::sqrt(variance))*riskFreeDiscount;
100 RHS = temp2 + (1 - dividendDiscount * cumNormalDist(d1)) * Si / Q;
101 bi = dividendDiscount * cumNormalDist(d1) * (1 - 1 / Q)
102 + (1 - dividendDiscount *
103 cumNormalDist.
derivative(d1) / std::sqrt(variance))
108 Q = (-(n-1.0) - std::sqrt(((n-1.0)*(n-1.0)) + 4 * K)) / 2;
109 LHS = payoff->strike() - Si;
110 RHS = temp - (1 - dividendDiscount * cumNormalDist(-d1)) * Si / Q;
111 bi = -dividendDiscount * cumNormalDist(-d1) * (1 - 1/Q)
112 - (1 + dividendDiscount * cumNormalDist.
derivative(-d1)
113 / std::sqrt(variance)) / Q;
114 while (std::fabs(LHS - RHS)/payoff->strike() > tolerance) {
115 Si = (payoff->strike() - RHS + bi * Si) / (1 + bi);
116 forwardSi = Si * dividendDiscount / riskFreeDiscount;
117 d1 = (std::log(forwardSi/payoff->strike())+0.5*variance)
118 /std::sqrt(variance);
119 LHS = payoff->strike() - Si;
121 forwardSi, std::sqrt(variance))*riskFreeDiscount;
122 RHS = temp2 - (1 - dividendDiscount * cumNormalDist(-d1)) * Si / Q;
123 bi = -dividendDiscount * cumNormalDist(-d1) * (1 - 1 / Q)
124 - (1 + dividendDiscount * cumNormalDist.
derivative(-d1)
125 / std::sqrt(variance)) / Q;
129 QL_FAIL(
"unknown option type");
138 "not an American Option");
140 ext::shared_ptr<AmericanExercise> ex =
141 ext::dynamic_pointer_cast<AmericanExercise>(arguments_.exercise);
142 QL_REQUIRE(ex,
"non-American exercise given");
143 QL_REQUIRE(!ex->payoffAtExpiry(),
144 "payoff at expiry not handled");
146 ext::shared_ptr<StrikedTypePayoff> payoff =
147 ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
148 QL_REQUIRE(payoff,
"non-striked payoff given");
150 Real variance =
process_->blackVolatility()->blackVariance(
151 ex->lastDate(), payoff->strike());
157 QL_REQUIRE(spot > 0.0,
"negative or null underlying given");
158 Real forwardPrice = spot * dividendDiscount / riskFreeDiscount;
162 if (dividendDiscount>=1.0 && payoff->optionType()==
Option::Call) {
164 results_.value = black.
value();
165 results_.delta = black.
delta(spot);
168 results_.gamma = black.
gamma(spot);
175 arguments_.exercise->lastDate());
176 results_.rho = black.
rho(t);
179 arguments_.exercise->lastDate());
183 arguments_.exercise->lastDate());
184 results_.vega = black.
vega(t);
185 results_.theta = black.
theta(spot, t);
193 Real tolerance = 1e-6;
195 dividendDiscount, variance, tolerance);
196 Real forwardSk = Sk * dividendDiscount / riskFreeDiscount;
197 Real d1 = (std::log(forwardSk/payoff->strike()) + 0.5*variance)
198 /std::sqrt(variance);
199 Real n = 2.0*std::log(dividendDiscount/riskFreeDiscount)/variance;
200 Real K = (!
close(riskFreeDiscount, 1.0, 1000))
201 ?
Real(-2.0*std::log(riskFreeDiscount)
202 / (variance*(1.0-riskFreeDiscount)))
205 switch (payoff->optionType()) {
207 Q = (-(n-1.0) + std::sqrt(((n-1.0)*(n-1.0))+4.0*K))/2.0;
208 a = (Sk/Q) * (1.0 - dividendDiscount * cumNormalDist(d1));
210 results_.value = black.
value() +
211 a * std::pow((spot/Sk), Q);
213 results_.value = spot - payoff->strike();
217 Q = (-(n-1.0) - std::sqrt(((n-1.0)*(n-1.0))+4.0*K))/2.0;
219 (1.0 - dividendDiscount * cumNormalDist(-d1));
221 results_.value = black.
value() +
222 a * std::pow((spot/Sk), Q);
224 results_.value = payoff->strike() - spot;
228 QL_FAIL(
"unknown option type");
BaroneAdesiWhaleyApproximationEngine(ext::shared_ptr< GeneralizedBlackScholesProcess >)
static Real criticalPrice(const ext::shared_ptr< StrikedTypePayoff > &payoff, DiscountFactor riskFreeDiscount, DiscountFactor dividendDiscount, Real variance, Real tolerance=1e-6)
void calculate() const override
ext::shared_ptr< GeneralizedBlackScholesProcess > process_
Black 1976 calculator class.
Real dividendRho(Time maturity) const
virtual Real delta(Real spot) const
Real vega(Time maturity) const
Real itmCashProbability() const
Real strikeSensitivity() const
virtual Real gamma(Real spot) const
virtual Real elasticity(Real spot) const
virtual Real thetaPerDay(Real spot, Time maturity) const
Real deltaForward() const
virtual Real theta(Real spot, Time maturity) const
Real rho(Time maturity) const
Cumulative normal distribution function.
Real derivative(Real x) const
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
Real Time
continuous quantity with 1-year units
Real DiscountFactor
discount factor between dates
bool close(const Quantity &m1, const Quantity &m2, Size n)
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)