QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
turnbullwakemanasianengine.cpp
1/*
2 Copyright (C) 2021 Skandinaviska Enskilda Banken AB (publ)
3
4 This file is part of QuantLib, a free-software/open-source library
5 for financial quantitative analysts and developers - http://quantlib.org/
6
7 QuantLib is free software: you can redistribute it and/or modify it
8 under the terms of the QuantLib license. You should have received a
9 copy of the license along with this program; if not, please email
10 <quantlib-dev@lists.sf.net>. The license is also available online at
11 <http://quantlib.org/license.shtml>.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the license for more details.
16*/
17
18#include <ql/exercise.hpp>
20#include <ql/pricingengines/blackcalculator.hpp>
21
22using namespace QuantLib;
23
25
26 // Enforce a few required things
27 QL_REQUIRE(arguments_.exercise->type() == Exercise::European, "not a European Option");
29 "must be Arithmetic Average::Type");
30
31 // Calculate the accrued portion
32 Size pastFixings = arguments_.pastFixings;
33 Size futureFixings = arguments_.fixingDates.size();
34 Real accruedAverage = 0;
35 if (pastFixings != 0) {
36 accruedAverage = arguments_.runningAccumulator / (pastFixings + futureFixings);
37 }
38 results_.additionalResults["accrued"] = accruedAverage;
39
40 Real discount = process_->riskFreeRate()->discount(arguments_.exercise->lastDate());
41 results_.additionalResults["discount"] = discount;
42
43 ext::shared_ptr<PlainVanillaPayoff> payoff =
44 ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
45 QL_REQUIRE(payoff, "non-plain payoff given");
46
47 // We will read the volatility off the surface at the effective strike
48 Real effectiveStrike = payoff->strike() - accruedAverage;
49 results_.additionalResults["strike"] = payoff->strike();
50 results_.additionalResults["effective_strike"] = effectiveStrike;
51
52 // If the effective strike is negative, exercise resp. permanent OTM is guaranteed and the
53 // valuation is made easy
54 Size m = futureFixings + pastFixings;
55 if (effectiveStrike <= 0.0) {
56 // For a reference, see "Option Pricing Formulas", Haug, 2nd ed, p. 193
57 if (payoff->optionType() == Option::Type::Call) {
58 Real spot = process_->stateVariable()->value();
59 Real S_A_hat = accruedAverage;
60 for (const auto& fd : arguments_.fixingDates) {
61 S_A_hat += (spot * process_->dividendYield()->discount(fd) /
62 process_->riskFreeRate()->discount(fd)) /
63 m;
64 }
65 results_.value = discount * (S_A_hat - payoff->strike());
66 results_.delta = discount * (S_A_hat - accruedAverage) / spot;
67 } else if (payoff->optionType() == Option::Type::Put) {
68 results_.value = 0;
69 results_.delta = 0;
70 }
71 results_.gamma = 0;
72 return;
73 }
74
75 // We should only get this far when the effectiveStrike > 0 but will check anyway
76 QL_REQUIRE(effectiveStrike > 0.0, "expected effectiveStrike to be positive");
77
78 // Expected value of the non-accrued portion of the average prices
79 // In general, m will equal n below if there is no accrued. If accrued, m > n.
80 Real EA = 0.0;
81 std::vector<Real> forwards;
82 std::vector<Time> times;
83 std::vector<Real> spotVars;
84 std::vector<Real> spotVolsVec; // additional results only
85 Real spot = process_->stateVariable()->value();
86
87 for (const auto& fd : arguments_.fixingDates) {
88 DiscountFactor dividendDiscount = process_->dividendYield()->discount(fd);
89 DiscountFactor riskFreeDiscountForFwdEstimation = process_->riskFreeRate()->discount(fd);
90
91 forwards.push_back(spot * dividendDiscount / riskFreeDiscountForFwdEstimation);
92 times.push_back(process_->blackVolatility()->timeFromReference(fd));
93
94 spotVars.push_back(
95 process_->blackVolatility()->blackVariance(times.back(), effectiveStrike));
96 spotVolsVec.push_back(std::sqrt(spotVars.back() / times.back()));
97
98 EA += forwards.back();
99 }
100 EA /= m;
101
102 // Expected value of A^2.
103 Real EA2 = 0.0;
104 Size n = forwards.size();
105
106 for (Size i = 0; i < n; ++i) {
107 EA2 += forwards[i] * forwards[i] * exp(spotVars[i]);
108 for (Size j = 0; j < i; ++j) {
109 EA2 += 2 * forwards[i] * forwards[j] * exp(spotVars[j]);
110 }
111 }
112
113 EA2 /= m * m;
114
115 // Calculate value
116 Real tn = times.back();
117 Real sigma = sqrt(log(EA2 / (EA * EA)) / tn);
118
119 // Populate results
120 BlackCalculator black(payoff->optionType(), effectiveStrike, EA, sigma * sqrt(tn), discount);
121
122 results_.value = black.value();
123 results_.delta = black.delta(spot);
124 results_.gamma = black.gamma(spot);
125
126 results_.additionalResults["forward"] = EA;
127 results_.additionalResults["exp_A_2"] = EA2;
128 results_.additionalResults["tte"] = tn;
129 results_.additionalResults["sigma"] = sigma;
130 results_.additionalResults["times"] = times;
131 results_.additionalResults["spotVols"] = spotVolsVec;
132 results_.additionalResults["forwards"] = forwards;
133}
Black 1976 calculator class.
virtual Real delta(Real spot) const
virtual Real gamma(Real spot) const
std::map< std::string, ext::any > additionalResults
Definition: instrument.hpp:123
ext::shared_ptr< GeneralizedBlackScholesProcess > process_
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
Turnbull Wakeman moment-matching Asian option Engine.