/src/quantlib/ql/methods/finitedifferences/stepconditions/fdmsimplestoragecondition.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2011 Klaus Spanderen |
5 | | Copyright (C) 2014 Ralph Schreyer |
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 | | <https://www.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 <algorithm> |
22 | | #include <ql/math/interpolations/bilinearinterpolation.hpp> |
23 | | #include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp> |
24 | | #include <ql/methods/finitedifferences/stepconditions/fdmsimplestoragecondition.hpp> |
25 | | #include <utility> |
26 | | |
27 | | namespace QuantLib { |
28 | | |
29 | | FdmSimpleStorageCondition::FdmSimpleStorageCondition( |
30 | | std::vector<Time> exerciseTimes, |
31 | | ext::shared_ptr<FdmMesher> mesher, |
32 | | ext::shared_ptr<FdmInnerValueCalculator> calculator, |
33 | | Real changeRate) |
34 | 0 | : exerciseTimes_(std::move(exerciseTimes)), mesher_(std::move(mesher)), |
35 | 0 | calculator_(std::move(calculator)), changeRate_(changeRate) { |
36 | |
|
37 | 0 | x_.reserve(mesher_->layout()->dim()[0]); |
38 | 0 | y_.reserve(mesher_->layout()->dim()[1]); |
39 | |
|
40 | 0 | for (const auto& iter : *mesher_->layout()) { |
41 | 0 | if (iter.coordinates()[1] == 0U) { |
42 | 0 | x_.push_back(mesher_->location(iter, 0)); |
43 | 0 | } |
44 | 0 | if (iter.coordinates()[0] == 0U) { |
45 | 0 | y_.push_back(mesher_->location(iter, 1)); |
46 | 0 | } |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | 0 | void FdmSimpleStorageCondition::applyTo(Array& a, Time t) const { |
51 | 0 | const auto iter |
52 | 0 | = std::find(exerciseTimes_.begin(), exerciseTimes_.end(), t); |
53 | |
|
54 | 0 | if (iter != exerciseTimes_.end()) { |
55 | 0 | Array retVal(a.size()); |
56 | |
|
57 | 0 | Matrix m(y_.size(), x_.size()); |
58 | 0 | std::copy(a.begin(), a.end(), m.begin()); |
59 | 0 | BilinearInterpolation interpl(x_.begin(), x_.end(), |
60 | 0 | y_.begin(), y_.end(), m); |
61 | |
|
62 | 0 | QL_REQUIRE(mesher_->layout()->size() == a.size(), |
63 | 0 | "inconsistent array dimensions"); |
64 | | |
65 | 0 | for (const auto& iter : *mesher_->layout()) { |
66 | 0 | const std::vector<Size>& coor = iter.coordinates(); |
67 | 0 | const Real x = x_[coor[0]]; |
68 | 0 | const Real y = y_[coor[1]]; |
69 | |
|
70 | 0 | const Real price = calculator_->innerValue(iter, t); |
71 | |
|
72 | 0 | const Real maxWithDraw = std::min(y-y_.front(), changeRate_); |
73 | 0 | const Real sellPrice = interpl(x, y-maxWithDraw); |
74 | |
|
75 | 0 | const Real maxInject = std::min(y_.back()-y, changeRate_); |
76 | 0 | const Real buyPrice = interpl(x, y+maxInject); |
77 | | |
78 | | // bang-bang-wait strategy |
79 | 0 | Real currentValue = std::max({ |
80 | 0 | a[iter.index()], |
81 | 0 | Real(buyPrice - price*maxInject), |
82 | 0 | Real(sellPrice + price*maxWithDraw) |
83 | 0 | }); |
84 | | |
85 | | // check if intermediate grid points give a better value |
86 | 0 | auto yIter = std::upper_bound(y_.begin(), y_.end(), y - maxWithDraw); |
87 | |
|
88 | 0 | while (yIter != y_.end() && *yIter < y + maxInject) { |
89 | 0 | if (*yIter != y) { |
90 | 0 | const Real change = *yIter - y; |
91 | 0 | const Real storagePrice(interpl(x, *yIter)); |
92 | |
|
93 | 0 | currentValue = std::max(currentValue, |
94 | 0 | storagePrice - change*price); |
95 | 0 | } |
96 | 0 | ++yIter; |
97 | 0 | } |
98 | |
|
99 | 0 | retVal[iter.index()] = currentValue; |
100 | 0 | } |
101 | 0 | a = retVal; |
102 | 0 | } |
103 | 0 | } |
104 | | } |