1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2015 Thema Consulting SA
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 <http://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/experimental/barrieroption/discretizeddoublebarrieroption.hpp>
21#include <vector>
22
23namespace QuantLib {
24
25 DiscretizedDoubleBarrierOption::DiscretizedDoubleBarrierOption(
26 const DoubleBarrierOption::arguments& args,
27 const StochasticProcess& process,
28 const TimeGrid& grid)
29 : arguments_(args), vanilla_(arguments_, process, grid) {
30 QL_REQUIRE(!args.exercise->dates().empty(), "specify at least one stopping date");
31
32 stoppingTimes_.resize(new_size: args.exercise->dates().size());
33 for (Size i=0; i<stoppingTimes_.size(); ++i) {
34 stoppingTimes_[i] =
35 process.time(args.exercise->date(index: i));
36 if (!grid.empty()) {
37 // adjust to the given grid
38 stoppingTimes_[i] = grid.closestTime(t: stoppingTimes_[i]);
39 }
40 }
41 }
42
43 void DiscretizedDoubleBarrierOption::reset(Size size) {
44 vanilla_.initialize(method: method(), t: time());
45 values_ = Array(size, 0.0);
46 adjustValues();
47 }
48
49 void DiscretizedDoubleBarrierOption::postAdjustValuesImpl() {
50 if (arguments_.barrierType!=DoubleBarrier::KnockOut) {
51 vanilla_.rollback(to: time());
52 }
53 Array grid = method()->grid(time());
54 checkBarrier(optvalues&: values_, grid);
55 }
56
57 void DiscretizedDoubleBarrierOption::checkBarrier(Array &optvalues, const Array &grid) const {
58
59 Time now = time();
60 bool endTime = isOnTime(t: stoppingTimes_.back());
61 bool stoppingTime = false;
62 switch (arguments_.exercise->type()) {
63 case Exercise::American:
64 if (now <= stoppingTimes_[1] &&
65 now >= stoppingTimes_[0])
66 stoppingTime = true;
67 break;
68 case Exercise::European:
69 if (isOnTime(t: stoppingTimes_[0]))
70 stoppingTime = true;
71 break;
72 case Exercise::Bermudan:
73 for (Real i : stoppingTimes_) {
74 if (isOnTime(t: i)) {
75 stoppingTime = true;
76 break;
77 }
78 }
79 break;
80 default:
81 QL_FAIL("invalid option type");
82 }
83 for (Size j=0; j<optvalues.size(); j++) {
84 switch (arguments_.barrierType) {
85 case DoubleBarrier::KnockIn:
86 if (grid[j] <= arguments_.barrier_lo) {
87 // knocked in dn
88 if (stoppingTime) {
89 optvalues[j] = std::max(a: vanilla()[j],
90 b: (*arguments_.payoff)(grid[j]));
91 }
92 else
93 optvalues[j] = vanilla()[j];
94 }
95 else if (grid[j] >= arguments_.barrier_hi) {
96 // knocked in up
97 if (stoppingTime) {
98 optvalues[j] = std::max(a: vanilla()[j],
99 b: (*arguments_.payoff)(grid[j]));
100 }
101 else
102 optvalues[j] = vanilla()[j];
103 }
104 else if (endTime)
105 optvalues[j] = arguments_.rebate;
106 break;
107 case DoubleBarrier::KnockOut:
108 if (grid[j] <= arguments_.barrier_lo)
109 optvalues[j] = arguments_.rebate; // knocked out lo
110 else if (grid[j] >= arguments_.barrier_hi)
111 optvalues[j] = arguments_.rebate; // knocked out hi
112 else if (stoppingTime)
113 optvalues[j] = std::max(a: optvalues[j],
114 b: (*arguments_.payoff)(grid[j]));
115 break;
116 case DoubleBarrier::KIKO:
117 // low barrier is KI, high is KO
118 if (grid[j] <= arguments_.barrier_lo) {
119 // knocked in dn
120 if (stoppingTime) {
121 optvalues[j] = std::max(a: vanilla()[j],
122 b: (*arguments_.payoff)(grid[j]));
123 }
124 else
125 optvalues[j] = vanilla()[j];
126 }
127 else if (grid[j] >= arguments_.barrier_hi)
128 optvalues[j] = arguments_.rebate; // knocked out hi
129 else if (endTime)
130 optvalues[j] = arguments_.rebate;
131 break;
132 case DoubleBarrier::KOKI:
133 // low barrier is KO, high is KI
134 if (grid[j] <= arguments_.barrier_lo)
135 optvalues[j] = arguments_.rebate; // knocked out lo
136 else if (grid[j] >= arguments_.barrier_hi) {
137 // knocked in up
138 if (stoppingTime) {
139 optvalues[j] = std::max(a: vanilla()[j],
140 b: (*arguments_.payoff)(grid[j]));
141 }
142 else
143 optvalues[j] = vanilla()[j];
144 }
145 else if (endTime)
146 optvalues[j] = arguments_.rebate;
147 break;
148 default:
149 QL_FAIL("invalid barrier type");
150 }
151 }
152 }
153
154
155
156 DiscretizedDermanKaniDoubleBarrierOption::DiscretizedDermanKaniDoubleBarrierOption(
157 const DoubleBarrierOption::arguments& args,
158 const StochasticProcess& process,
159 const TimeGrid& grid)
160 : unenhanced_(args, process, grid) {
161 }
162
163 void DiscretizedDermanKaniDoubleBarrierOption::reset(Size size) {
164 unenhanced_.initialize(method: method(), t: time());
165 values_ = Array(size, 0.0);
166 adjustValues();
167 }
168
169 void DiscretizedDermanKaniDoubleBarrierOption::postAdjustValuesImpl() {
170 unenhanced_.rollback(to: time());
171
172 Array grid = method()->grid(time());
173 unenhanced_.checkBarrier(optvalues&: values_, grid); // compute payoffs
174 adjustBarrier(optvalues&: values_, grid);
175 }
176
177 void DiscretizedDermanKaniDoubleBarrierOption::adjustBarrier(Array &optvalues, const Array &grid) {
178 Real barrier_lo = unenhanced_.arguments().barrier_lo;
179 Real barrier_hi = unenhanced_.arguments().barrier_hi;
180 Real rebate = unenhanced_.arguments().rebate;
181 switch (unenhanced_.arguments().barrierType) {
182 case DoubleBarrier::KnockIn:
183 for (Size j=0; j<optvalues.size()-1; ++j) {
184 if (grid[j]<=barrier_lo && grid[j+1] > barrier_lo) {
185 // grid[j+1] above barrier_lo, grid[j] under (in),
186 // interpolate optvalues[j+1]
187 Real ltob = (barrier_lo-grid[j]);
188 Real htob = (grid[j+1]-barrier_lo);
189 Real htol = (grid[j+1]-grid[j]);
190 Real u1 = unenhanced_.values()[j+1];
191 Real t1 = unenhanced_.vanilla()[j+1];
192 optvalues[j+1] = std::max(a: 0.0, b: (ltob*t1+htob*u1)/htol); // derman std
193 }
194 else if (grid[j] < barrier_hi && grid[j+1] >= barrier_hi) {
195 // grid[j+1] above barrier_hi (in), grid[j] under,
196 // interpolate optvalues[j]
197 Real ltob = (barrier_hi-grid[j]);
198 Real htob = (grid[j+1]-barrier_hi);
199 Real htol = (grid[j+1]-grid[j]);
200 Real u = unenhanced_.values()[j];
201 Real t = unenhanced_.vanilla()[j];
202 optvalues[j] = std::max(a: 0.0, b: (ltob*u+htob*t)/htol); // derman std
203 }
204 }
205 break;
206 case DoubleBarrier::KnockOut:
207 for (Size j=0; j<optvalues.size()-1; ++j) {
208 if (grid[j]<=barrier_lo && grid[j+1] > barrier_lo) {
209 // grid[j+1] above barrier_lo, grid[j] under (out),
210 // interpolate optvalues[j+1]
211 Real a = (barrier_lo-grid[j])*rebate;
212 Real b = (grid[j+1]-barrier_lo)*unenhanced_.values()[j+1];
213 Real c = (grid[j+1]-grid[j]);
214 optvalues[j+1] = std::max(a: 0.0, b: (a+b)/c);
215 }
216 else if (grid[j] < barrier_hi && grid[j+1] >= barrier_hi) {
217 // grid[j+1] above barrier_hi (out), grid[j] under,
218 // interpolate optvalues[j]
219 Real a = (barrier_hi-grid[j])*unenhanced_.values()[j];
220 Real b = (grid[j+1]-barrier_hi)*rebate;
221 Real c = (grid[j+1]-grid[j]);
222 optvalues[j] = std::max(a: 0.0, b: (a+b)/c);
223 }
224 }
225 break;
226 default:
227 QL_FAIL("unsupported barrier type");
228 break;
229 }
230 }
231
232}
233

source code of quantlib/ql/experimental/barrieroption/discretizeddoublebarrieroption.cpp