Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/pricingengines/exotic/analyticwriterextensibleoptionengine.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2011 Master IMAFA - Polytech'Nice Sophia - Université de Nice Sophia Antipolis
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <https://www.quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
#include <ql/pricingengines/exotic/analyticwriterextensibleoptionengine.hpp>
21
#include <ql/math/distributions/bivariatenormaldistribution.hpp>
22
#include <ql/pricingengines/blackformula.hpp>
23
#include <utility>
24
25
using namespace std;
26
27
namespace QuantLib {
28
29
    AnalyticWriterExtensibleOptionEngine::AnalyticWriterExtensibleOptionEngine(
30
        ext::shared_ptr<GeneralizedBlackScholesProcess> process)
31
0
    : process_(std::move(process)) {
32
0
        registerWith(process_);
33
0
    }
34
35
0
    void AnalyticWriterExtensibleOptionEngine::calculate() const {
36
        // We take all the arguments:
37
38
0
        ext::shared_ptr<PlainVanillaPayoff> payoff1 =
39
0
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
40
0
        QL_REQUIRE(payoff1, "not a plain vanilla payoff");
41
42
0
        ext::shared_ptr<PlainVanillaPayoff> payoff2 =
43
0
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff2);
44
0
        QL_REQUIRE(payoff2, "not a plain vanilla payoff");
45
46
0
        ext::shared_ptr<Exercise> exercise1 = arguments_.exercise;
47
48
0
        ext::shared_ptr<Exercise> exercise2 = arguments_.exercise2;
49
50
51
        // We create and apply the calculate process:
52
53
0
        Option::Type type = payoff1->optionType();
54
55
        // STEP 1:
56
57
        // S = spot
58
0
        Real spot = process_->stateVariable()->value();
59
60
        // For the B&S formulae:
61
0
        DayCounter dividendDC = process_->dividendYield()->dayCounter();
62
0
        Rate dividend = process_->dividendYield()->zeroRate(
63
0
                  exercise1->lastDate(), dividendDC, Continuous, NoFrequency);
64
65
0
        DayCounter riskFreeDC = process_->riskFreeRate()->dayCounter();
66
0
        Rate riskFree = process_->riskFreeRate()->zeroRate(
67
0
                  exercise1->lastDate(), riskFreeDC, Continuous, NoFrequency);
68
69
        // The time to maturity:
70
0
        Time t1 = riskFreeDC.yearFraction(
71
0
                                    process_->riskFreeRate()->referenceDate(),
72
0
                                    arguments_.exercise->lastDate());
73
0
        Time t2 = riskFreeDC.yearFraction(
74
0
                                    process_->riskFreeRate()->referenceDate(),
75
0
                                    arguments_.exercise2->lastDate());
76
77
        // b = r-q:
78
0
        Real b = riskFree - dividend;
79
80
0
        Real forwardPrice = spot * std::exp(b*t1);
81
82
0
        Volatility volatility = process_->blackVolatility()->blackVol(
83
0
                                    exercise1->lastDate(), payoff1->strike());
84
85
0
        Real stdDev = volatility*std::sqrt(t1);
86
87
0
        Real discount = std::exp(-riskFree*t1);
88
89
        // Call the B&S method:
90
0
        Real black = blackFormula(type, payoff1->strike(),
91
0
                                  forwardPrice, stdDev, discount);
92
93
        // STEP 2:
94
95
        // Standard bivariate normal distribution:
96
0
        Real ro = std::sqrt(t1/t2);
97
0
        Real z1 = (std::log(spot/payoff2->strike()) +
98
0
                   (b+std::pow(volatility, 2)/2)*t2)/(volatility*std::sqrt(t2));
99
0
        Real z2 = (std::log(spot/payoff1->strike()) +
100
0
                   (b+std::pow(volatility, 2)/2)*t1)/(volatility*std::sqrt(t1));
101
102
        // Call the bivariate method:
103
0
        BivariateCumulativeNormalDistributionWe04DP biv(-ro);
104
105
106
        // STEP 3:
107
108
0
        Real bivariate1, bivariate2, result;
109
110
        // Final computing:
111
0
        if (type == Option::Call) {
112
            // Call case:
113
0
            bivariate1 = biv(z1, -z2);
114
0
            bivariate2 = biv(z1-volatility*std::sqrt(t2),
115
0
                             -z2+volatility*std::sqrt(t1));
116
0
            result = black + spot*std::exp((b-riskFree)*t2)*bivariate1
117
0
                - payoff2->strike()*std::exp((-riskFree)*t2)*bivariate2;
118
0
        } else {
119
            // Put case:
120
0
            bivariate1 = biv(-z1, z2);
121
0
            bivariate2 = biv(-z1+volatility*std::sqrt(t2),
122
0
                             z2-volatility*std::sqrt(t1));
123
0
            result = black - spot*std::exp((b-riskFree)*t2)*bivariate1
124
0
                + payoff2->strike()*std::exp((-riskFree)*t2)*bivariate2;
125
0
        }
126
127
        // Save the result:
128
0
        results_.value = result;
129
0
    }
130
131
}