Coverage Report

Created: 2025-08-28 06:30

/src/quantlib/ql/pricingengines/lookback/analyticcontinuousfixedlookback.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2006 Warren Chou
5
 Copyright (C) 2007 StatPro Italia srl
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <http://quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
#include <ql/exercise.hpp>
22
#include <ql/pricingengines/lookback/analyticcontinuousfixedlookback.hpp>
23
#include <utility>
24
25
namespace QuantLib {
26
27
    AnalyticContinuousFixedLookbackEngine::AnalyticContinuousFixedLookbackEngine(
28
        ext::shared_ptr<GeneralizedBlackScholesProcess> process)
29
0
    : process_(std::move(process)) {
30
0
        registerWith(process_);
31
0
    }
32
33
0
    void AnalyticContinuousFixedLookbackEngine::calculate() const {
34
35
0
        ext::shared_ptr<PlainVanillaPayoff> payoff =
36
0
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
37
0
        QL_REQUIRE(payoff, "Non-plain payoff given");
38
39
0
        QL_REQUIRE(process_->x0() > 0.0, "negative or null underlying");
40
41
0
        Real strike = payoff->strike();
42
43
0
        switch (payoff->optionType()) {
44
0
          case Option::Call:
45
0
            QL_REQUIRE(payoff->strike()>=0.0,
46
0
                       "Strike must be positive or null");
47
0
            if (strike <= minmax())
48
0
                results_.value = A(1) + C(1);
49
0
            else
50
0
                results_.value = B(1);
51
0
            break;
52
0
          case Option::Put:
53
0
            QL_REQUIRE(payoff->strike()>0.0,
54
0
                       "Strike must be positive");
55
0
            if (strike >= minmax())
56
0
                results_.value = A(-1) + C(-1);
57
0
            else
58
0
                results_.value = B(-1);
59
0
            break;
60
0
          default:
61
0
            QL_FAIL("Unknown type");
62
0
        }
63
0
    }
64
65
66
0
    Real AnalyticContinuousFixedLookbackEngine::underlying() const {
67
0
        return process_->x0();
68
0
    }
69
70
0
    Real AnalyticContinuousFixedLookbackEngine::strike() const {
71
0
        ext::shared_ptr<PlainVanillaPayoff> payoff =
72
0
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
73
0
        QL_REQUIRE(payoff, "Non-plain payoff given");
74
0
        return payoff->strike();
75
0
    }
76
77
0
    Time AnalyticContinuousFixedLookbackEngine::residualTime() const {
78
0
        return process_->time(arguments_.exercise->lastDate());
79
0
    }
80
81
0
    Volatility AnalyticContinuousFixedLookbackEngine::volatility() const {
82
0
        return process_->blackVolatility()->blackVol(residualTime(), strike());
83
0
    }
84
85
0
    Real AnalyticContinuousFixedLookbackEngine::stdDeviation() const {
86
0
        return volatility() * std::sqrt(residualTime());
87
0
    }
88
89
0
    Rate AnalyticContinuousFixedLookbackEngine::riskFreeRate() const {
90
0
        return process_->riskFreeRate()->zeroRate(residualTime(), Continuous,
91
0
                                                  NoFrequency);
92
0
    }
93
94
    DiscountFactor AnalyticContinuousFixedLookbackEngine::riskFreeDiscount()
95
0
                              const {
96
0
        return process_->riskFreeRate()->discount(residualTime());
97
0
    }
98
99
0
    Rate AnalyticContinuousFixedLookbackEngine::dividendYield() const {
100
0
        return process_->dividendYield()->zeroRate(residualTime(),
101
0
                                                   Continuous, NoFrequency);
102
0
    }
103
104
    DiscountFactor AnalyticContinuousFixedLookbackEngine::dividendDiscount()
105
0
                              const {
106
0
        return process_->dividendYield()->discount(residualTime());
107
0
    }
108
109
0
    Real AnalyticContinuousFixedLookbackEngine::minmax() const {
110
0
        return arguments_.minmax;
111
0
    }
112
113
0
    Real AnalyticContinuousFixedLookbackEngine::A(Real eta) const {
114
0
        Volatility vol = volatility();
115
0
        Real lambda = 2.0*(riskFreeRate() - dividendYield())/(vol*vol);
116
0
        Real ss = underlying()/minmax();
117
0
        Real d1 =
118
0
            std::log(ss)/stdDeviation() + 0.5*(lambda+1.0)*stdDeviation();
119
0
        Real N1 = f_(eta*d1);
120
0
        Real N2 = f_(eta*(d1-stdDeviation()));
121
0
        Real N3 = f_(eta*(d1-lambda*stdDeviation()));
122
0
        Real N4 = f_(eta*d1);
123
0
        Real powss = std::pow(ss, -lambda);
124
0
        return eta*(underlying() * dividendDiscount() * N1 -
125
0
                    minmax() * riskFreeDiscount() * N2 -
126
0
                    underlying() * riskFreeDiscount() *
127
0
                    (powss * N3 - dividendDiscount()* N4/riskFreeDiscount())/
128
0
            lambda);
129
0
    }
130
131
0
    Real AnalyticContinuousFixedLookbackEngine::B(Real eta) const {
132
0
        Volatility vol = volatility();
133
0
        Real lambda = 2.0*(riskFreeRate() - dividendYield())/(vol*vol);
134
0
        Real ss = underlying()/strike();
135
0
        Real d1 =
136
0
            std::log(ss)/stdDeviation() + 0.5*(lambda+1.0)*stdDeviation();
137
0
        Real N1 = f_(eta*d1);
138
0
        Real N2 = f_(eta*(d1-stdDeviation()));
139
0
        Real N3 = f_(eta*(d1-lambda*stdDeviation()));
140
0
        Real N4 = f_(eta*d1);
141
0
        Real powss = std::pow(ss, -lambda);
142
0
        return eta*(underlying() * dividendDiscount() * N1 -
143
0
                    strike() * riskFreeDiscount() * N2 -
144
0
                    underlying() * riskFreeDiscount() *
145
0
                    (powss * N3 - dividendDiscount()* N4/riskFreeDiscount())/
146
0
            lambda);
147
0
    }
148
149
0
    Real AnalyticContinuousFixedLookbackEngine::C(Real eta) const {
150
0
        return eta*(riskFreeDiscount()*(minmax() - strike()));
151
0
    }
152
153
}
154