/src/quantlib/ql/instruments/vanillaswingoption.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2010, 2011 Klaus Spanderen |
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 | | /*! \file vanillaswingoption.cpp |
21 | | \brief vanilla swing option class |
22 | | */ |
23 | | |
24 | | |
25 | | #include <ql/event.hpp> |
26 | | #include <ql/instruments/vanillaswingoption.hpp> |
27 | | |
28 | | namespace QuantLib { |
29 | | |
30 | | namespace { |
31 | | const Size secPerDay = 24U * 3600U; |
32 | | |
33 | | std::pair<std::vector<Date>, std::vector<Size> > |
34 | 0 | createDateTimes(const Date& from, const Date& to, Size stepSize) { |
35 | |
|
36 | 0 | std::vector<Size> secs; |
37 | 0 | std::vector<Date> dates; |
38 | |
|
39 | 0 | Date iterDate = from; |
40 | 0 | Size iterStepSize = 0U; |
41 | |
|
42 | 0 | while (iterDate <= to) { |
43 | 0 | dates.push_back(iterDate); |
44 | 0 | secs.push_back(iterStepSize); |
45 | |
|
46 | 0 | iterStepSize+=stepSize; |
47 | 0 | if (iterStepSize >= secPerDay) { |
48 | 0 | iterDate+=1L; |
49 | 0 | iterStepSize%=secPerDay; |
50 | 0 | } |
51 | 0 | } |
52 | |
|
53 | 0 | return std::pair<std::vector<Date>,std::vector<Size> >(dates, secs); |
54 | 0 | } |
55 | | } |
56 | | |
57 | | SwingExercise::SwingExercise(const std::vector<Date>& dates, const std::vector<Size>& seconds) |
58 | 0 | : BermudanExercise(dates), |
59 | 0 | seconds_(seconds.empty() ? std::vector<Size>(dates.size(), 0U) : seconds) { |
60 | 0 | QL_REQUIRE(dates_.size() == seconds_.size(), |
61 | 0 | "dates and seconds must have the same size"); |
62 | 0 | for (Size i=0; i < dates_.size(); ++i) { |
63 | 0 | QL_REQUIRE(seconds_[i] < secPerDay, |
64 | 0 | "a date can not have more than 24*3600 seconds"); |
65 | 0 | if (i > 0) { |
66 | 0 | QL_REQUIRE(dates_[i-1] < dates_[i] |
67 | 0 | || (dates_[i-1] == dates_[i] |
68 | 0 | && seconds_[i-1] < seconds_[i]), |
69 | 0 | "date times must be sorted"); |
70 | 0 | } |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | |
75 | | SwingExercise::SwingExercise(const Date& from, |
76 | | const Date& to, Size stepSizeSecs) |
77 | 0 | : BermudanExercise(createDateTimes(from, to, stepSizeSecs).first), |
78 | 0 | seconds_(createDateTimes(from, to, stepSizeSecs).second) { |
79 | 0 | } |
80 | | |
81 | 0 | const std::vector<Size>& SwingExercise::seconds() const { return seconds_; } |
82 | | |
83 | | std::vector<Time> SwingExercise::exerciseTimes(const DayCounter& dc, |
84 | 0 | const Date& refDate) const { |
85 | 0 | std::vector<Time> exerciseTimes; |
86 | 0 | exerciseTimes.reserve(dates().size()); |
87 | 0 | for (Size i=0; i<dates().size(); ++i) { |
88 | 0 | Time t = dc.yearFraction(refDate, dates()[i]); |
89 | |
|
90 | 0 | const Time dt = dc.yearFraction(refDate, dates()[i] + Period(1U, Days)) - t; |
91 | |
|
92 | 0 | t += dt*seconds()[i]/(24*3600.); |
93 | |
|
94 | 0 | QL_REQUIRE(t >= 0, "exercise dates must not contain past date"); |
95 | 0 | exerciseTimes.push_back(t); |
96 | 0 | } |
97 | | |
98 | 0 | return exerciseTimes; |
99 | 0 | } |
100 | | |
101 | 0 | Real VanillaForwardPayoff::operator()(Real price) const { |
102 | 0 | switch (type_) { |
103 | 0 | case Option::Call: |
104 | 0 | return price-strike_; |
105 | 0 | case Option::Put: |
106 | 0 | return strike_-price; |
107 | 0 | default: |
108 | 0 | QL_FAIL("unknown/illegal option type"); |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | 0 | void VanillaForwardPayoff::accept(AcyclicVisitor& v) { |
113 | 0 | auto* v1 = dynamic_cast<Visitor<VanillaForwardPayoff>*>(&v); |
114 | 0 | if (v1 != nullptr) |
115 | 0 | v1->visit(*this); |
116 | 0 | else |
117 | 0 | StrikedTypePayoff::accept(v); |
118 | 0 | } |
119 | | |
120 | | |
121 | 0 | void VanillaSwingOption::arguments::validate() const { |
122 | 0 | QL_REQUIRE(payoff, "no payoff given"); |
123 | 0 | QL_REQUIRE(exercise, "no exercise given"); |
124 | | |
125 | 0 | QL_REQUIRE(minExerciseRights <= maxExerciseRights, |
126 | 0 | "minExerciseRights <= maxExerciseRights"); |
127 | 0 | QL_REQUIRE(exercise->dates().size() >= maxExerciseRights, |
128 | 0 | "number of exercise rights exceeds " |
129 | 0 | "number of exercise dates"); |
130 | 0 | } |
131 | | |
132 | | void VanillaSwingOption::setupArguments( |
133 | 0 | PricingEngine::arguments* args) const { |
134 | 0 | auto* arguments = dynamic_cast<VanillaSwingOption::arguments*>(args); |
135 | 0 | QL_REQUIRE(arguments != nullptr, "wrong argument type"); |
136 | | |
137 | 0 | arguments->payoff |
138 | 0 | = ext::dynamic_pointer_cast<StrikedTypePayoff>(payoff_); |
139 | 0 | arguments->exercise |
140 | 0 | = ext::dynamic_pointer_cast<SwingExercise>(exercise_); |
141 | 0 | arguments->minExerciseRights = minExerciseRights_; |
142 | 0 | arguments->maxExerciseRights = maxExerciseRights_; |
143 | 0 | } |
144 | | |
145 | 0 | bool VanillaSwingOption::isExpired() const { |
146 | 0 | return detail::simple_event(exercise_->lastDate()).hasOccurred(); |
147 | 0 | } |
148 | | } |