Coverage Report

Created: 2026-03-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/instruments/asianoption.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2003, 2004 Ferdinando Ametrano
5
 Copyright (C) 2007 StatPro Italia srl
6
 Copyright (C) 2025 Kareem Fareed
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <https://www.quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
#include <ql/instruments/asianoption.hpp>
23
#include <ql/time/date.hpp>
24
#include <ql/settings.hpp>
25
#include <algorithm>
26
#include <utility>
27
28
namespace QuantLib {
29
30
    DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(
31
        Average::Type averageType,
32
        Real runningAccumulator,
33
        Size pastFixings,
34
        std::vector<Date> fixingDates,
35
        const ext::shared_ptr<StrikedTypePayoff>& payoff,
36
        const ext::shared_ptr<Exercise>& exercise)
37
0
    : OneAssetOption(payoff, exercise), averageType_(averageType),
38
0
      runningAccumulator_(runningAccumulator), pastFixings_(pastFixings),
39
0
      fixingDates_(std::move(fixingDates)), allPastFixingsProvided_(false) {
40
0
        std::sort(fixingDates_.begin(), fixingDates_.end());
41
42
        // Add a hard override to the runningAccumulator if pastFixings is 0
43
        // (ie. the option is unseasoned)
44
0
        if (pastFixings_ == 0) {
45
0
            if (averageType == Average::Geometric) {
46
0
                runningAccumulator_ = 1.0;
47
0
            } else if (averageType == Average::Arithmetic) {
48
0
                runningAccumulator_ = 0.0;
49
0
            } else {
50
0
                QL_FAIL("Unrecognised average type, must be Average::Arithmetic or Average::Geometric");
51
0
            }
52
0
        }
53
0
    }
Unexecuted instantiation: QuantLib::DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(QuantLib::Average::Type, double, unsigned long, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
Unexecuted instantiation: QuantLib::DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(QuantLib::Average::Type, double, unsigned long, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
54
55
    DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(
56
        Average::Type averageType,
57
        std::vector<Date> fixingDates,
58
        const ext::shared_ptr<StrikedTypePayoff>& payoff,
59
        const ext::shared_ptr<Exercise>& exercise,
60
        std::vector<Real> allPastFixings)
61
0
    : OneAssetOption(payoff, exercise), averageType_(averageType), runningAccumulator_(0.0),
62
0
      pastFixings_(0), fixingDates_(std::move(fixingDates)),
63
0
      allPastFixingsProvided_(true), allPastFixings_(std::move(allPastFixings)) {}
Unexecuted instantiation: QuantLib::DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(QuantLib::Average::Type, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&, std::__1::vector<double, std::__1::allocator<double> >)
Unexecuted instantiation: QuantLib::DiscreteAveragingAsianOption::DiscreteAveragingAsianOption(QuantLib::Average::Type, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&, std::__1::vector<double, std::__1::allocator<double> >)
64
65
    void DiscreteAveragingAsianOption::setupArguments(
66
0
                                       PricingEngine::arguments* args) const {
67
68
0
        Real runningAccumulator = runningAccumulator_;
69
0
        Size pastFixings = pastFixings_;
70
0
        std::vector<Date> fixingDates = fixingDates_;
71
72
        // If the option was initialised with a list of fixings, before pricing we
73
        // compare the evaluation date to the fixing dates, and set up the pastFixings,
74
        // fixingDates, and runningAccumulator accordingly
75
0
        if (allPastFixingsProvided_) {
76
0
            std::vector<Date> futureFixingDates = std::vector<Date>();
77
0
            Date today = Settings::instance().evaluationDate();
78
79
0
            pastFixings = 0;
80
0
            for (auto fixingDate : fixingDates_) {
81
0
                if (fixingDate < today) {
82
0
                    pastFixings += 1;
83
0
                } else {
84
0
                    futureFixingDates.push_back(fixingDate);
85
0
                }
86
0
            }
87
0
            fixingDates = futureFixingDates;
88
89
0
            if (pastFixings > allPastFixings_.size())
90
0
                QL_FAIL("Not enough past fixings have been provided for the required historical fixing dates");
91
92
0
            if (averageType_ == Average::Geometric) {
93
0
                runningAccumulator = 1.0;
94
0
                for (Size i=0; i<pastFixings; i++)
95
0
                    runningAccumulator *= allPastFixings_[i];
96
97
0
            } else if (averageType_ == Average::Arithmetic) {
98
0
                runningAccumulator = 0.0;
99
0
                for (Size i=0; i<pastFixings; i++)
100
0
                    runningAccumulator += allPastFixings_[i];
101
102
0
            } else {
103
0
                QL_FAIL("Unrecognised average type, must be Average::Arithmetic or Average::Geometric");
104
0
            }
105
106
0
        }
107
108
0
        OneAssetOption::setupArguments(args);
109
110
0
        auto* moreArgs = dynamic_cast<DiscreteAveragingAsianOption::arguments*>(args);
111
0
        QL_REQUIRE(moreArgs != nullptr, "wrong argument type");
112
0
        moreArgs->averageType = averageType_;
113
0
        moreArgs->runningAccumulator = runningAccumulator;
114
0
        moreArgs->pastFixings = pastFixings;
115
0
        moreArgs->fixingDates = fixingDates;
116
0
    }
117
118
0
    void DiscreteAveragingAsianOption::arguments::validate() const {
119
120
0
        OneAssetOption::arguments::validate();
121
122
0
        QL_REQUIRE(Integer(averageType) != -1, "unspecified average type");
123
0
        QL_REQUIRE(pastFixings != Null<Size>(), "null past-fixing number");
124
0
        QL_REQUIRE(runningAccumulator != Null<Real>(), "null running product");
125
0
        switch (averageType) {
126
0
            case Average::Arithmetic:
127
0
                QL_REQUIRE(runningAccumulator >= 0.0,
128
0
                           "non negative running sum required: "
129
0
                           << runningAccumulator << " not allowed");
130
0
                break;
131
0
            case Average::Geometric:
132
0
                QL_REQUIRE(runningAccumulator > 0.0,
133
0
                           "positive running product required: "
134
0
                           << runningAccumulator << " not allowed");
135
0
                break;
136
0
            default:
137
0
                QL_FAIL("invalid average type");
138
0
        }
139
140
        // check fixingTimes_ here
141
0
    }
142
143
144
145
146
    ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(
147
        Average::Type averageType,
148
        const ext::shared_ptr<StrikedTypePayoff>& payoff,
149
        const ext::shared_ptr<Exercise>& exercise)
150
0
    : OneAssetOption(payoff, exercise),
151
0
      averageType_(averageType)
152
0
      {}
Unexecuted instantiation: QuantLib::ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(QuantLib::Average::Type, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
Unexecuted instantiation: QuantLib::ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(QuantLib::Average::Type, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
153
154
    ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(
155
        Average::Type averageType,
156
        Date startDate,
157
        const ext::shared_ptr<StrikedTypePayoff>& payoff,
158
        const ext::shared_ptr<Exercise>& exercise)
159
0
    : OneAssetOption(payoff, exercise),
160
0
      averageType_(averageType),
161
0
      startDate_(startDate) {}
Unexecuted instantiation: QuantLib::ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(QuantLib::Average::Type, QuantLib::Date, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
Unexecuted instantiation: QuantLib::ContinuousAveragingAsianOption::ContinuousAveragingAsianOption(QuantLib::Average::Type, QuantLib::Date, boost::shared_ptr<QuantLib::StrikedTypePayoff> const&, boost::shared_ptr<QuantLib::Exercise> const&)
162
163
    void ContinuousAveragingAsianOption::setupArguments(
164
0
                                       PricingEngine::arguments* args) const {
165
166
0
        OneAssetOption::setupArguments(args);
167
168
0
        auto* moreArgs = dynamic_cast<ContinuousAveragingAsianOption::arguments*>(args);
169
0
        QL_REQUIRE(moreArgs != nullptr, "wrong argument type");
170
0
        moreArgs->averageType = averageType_;
171
0
        moreArgs->startDate = startDate_;
172
0
    }
173
174
0
    void ContinuousAveragingAsianOption::arguments::validate() const {
175
176
0
        OneAssetOption::arguments::validate();
177
178
        QL_REQUIRE(Integer(averageType) != -1, "unspecified average type");
179
0
    }
180
181
}
182