Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
barrieroptionwrapper.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7 ORE is free software: you can redistribute it and/or modify it
8 under the terms of the Modified BSD License. You should have received a
9 copy of the license along with this program.
10 The license is also available online at <http://opensourcerisk.org>
11 This program is distributed on the basis that it will form a useful
12 contribution to risk analytics and model standardisation, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
15 */
16
17/*! \file ored/portfolio/barrieroptionwrapper.hpp
18 \brief Wrapper for option instruments, tracks whether option has been exercised or not
19 \ingroup tradedata
20*/
21
30#include <ql/instruments/barriertype.hpp>
31#include <ql/instruments/vanillaoption.hpp>
32#include <ql/instruments/barrieroption.hpp>
33#include <ql/settings.hpp>
34
35using namespace QuantLib;
36
37namespace ore {
38namespace data {
39
41 Real addNPV = additionalInstrumentsNPV();
42
43 Date today = Settings::instance().evaluationDate();
44
45 // check the trigger on the first run, we only need to re check it if the
46 // instrument becomes un calculated. The trigger should only need to be rechecked
47 // for a change in valuation date or spot, and this ensures
48 if (!exercised_ || !instrument_->isCalculated()) {
49 exercise();
50 }
51
52 if (exercised_) {
53 Real npv;
54 if (barrierType_ == Barrier::DownOut || barrierType_ == Barrier::UpOut)
55 npv = (today == exerciseDate_) ? multiplier2() * rebate_ * undMultiplier_ : 0.0;
56 else
58
59 return npv + addNPV;
60 } else {
61 // if not exercised we just return the original option's NPV
63
64 // Handling the edge case where barrier = strike, is KO, and underlying is only ITM when inside KO barrier.
65 // NPV should then be zero, but the pricing engine might not necessarily be pricing it as zero at the boundary.
66 auto vanillaOption = QuantLib::ext::dynamic_pointer_cast<VanillaOption>(activeUnderlyingInstrument_);
67 if (vanillaOption) {
68 auto payoff = QuantLib::ext::dynamic_pointer_cast<StrikedTypePayoff>(vanillaOption->payoff());
69 if (payoff && ((barrierType_ == Barrier::DownOut && payoff->optionType() == Option::Put) ||
70 (barrierType_ == Barrier::UpOut && payoff->optionType() == Option::Call))) {
71 const bool isTouchingOnly = true;
72 if (checkBarrier(payoff->strike(), isTouchingOnly))
73 npv = 0;
74 }
75 }
76 return npv + addNPV;
77 }
78}
79
80const std::map<std::string, boost::any>& BarrierOptionWrapper::additionalResults() const {
81 static std::map<std::string, boost::any> emptyMap;
82 NPV();
83 if (exercised_) {
84 if (!(barrierType_ == Barrier::DownOut || barrierType_ == Barrier::UpOut))
85 return activeUnderlyingInstrument_->additionalResults();
86 else
87 return emptyMap;
88 } else {
89 auto vanillaOption = QuantLib::ext::dynamic_pointer_cast<VanillaOption>(activeUnderlyingInstrument_);
90 if (vanillaOption) {
91 auto payoff = QuantLib::ext::dynamic_pointer_cast<StrikedTypePayoff>(vanillaOption->payoff());
92 if (payoff && ((barrierType_ == Barrier::DownOut && payoff->optionType() == Option::Put) ||
93 (barrierType_ == Barrier::UpOut && payoff->optionType() == Option::Call))) {
94 const bool isTouchingOnly = true;
95 if (checkBarrier(payoff->strike(), isTouchingOnly))
96 return emptyMap;
97 }
98 }
99
100 return instrument_->additionalResults();
101 }
102}
103
104bool SingleBarrierOptionWrapper::checkBarrier(Real spot, bool isTouchingOnly) const {
105 if (isTouchingOnly)
106 return close_enough(spot, barrier_);
107 else {
108 switch (barrierType_) {
109 case Barrier::DownIn:
110 case Barrier::DownOut:
111 return spot <= barrier_;
112 case Barrier::UpIn:
113 case Barrier::UpOut:
114 return spot >= barrier_;
115 default:
116 QL_FAIL("unknown barrier type " << barrierType_);
117 }
118 }
119}
120
122 bool trigger = false;
123 Date today = Settings::instance().evaluationDate();
124
125 // check historical fixings - only check if the instrument is not calculated
126 // really only needs to be checked if evaluation date changed
127 if (!instrument_->isCalculated()) {
128 if (startDate_ != Date() && startDate_ < today) {
129 QL_REQUIRE(index_, "no index provided");
130 QL_REQUIRE(calendar_ != Calendar(), "no calendar provided");
131
132 QuantLib::ext::shared_ptr<QuantExt::EqFxIndexBase> eqfxIndex =
133 QuantLib::ext::dynamic_pointer_cast<QuantExt::EqFxIndexBase>(index_);
134
135 if (eqfxIndex) {
136 Date d = calendar_.adjust(startDate_);
137 while (d < today && !trigger) {
138 Real fixing = eqfxIndex->pastFixing(d);
139 if (fixing == Null<Real>()) {
142 "Missing fixing for index " + index_->name() + " on " + ore::data::to_string(d) +
143 ", Skipping this date, assuming no trigger",
144 std::map<std::string, std::string>({{"exceptionType", "Invalid or missing fixings"}}))
145 .log();
146 } else {
147 // This is so we can use pastIndex and not fail on a missing fixing to be
148 // consistent with previous implemention, however maybe we should use fixing
149 // and be strict on needed fixings being present
150 auto fxInd = QuantLib::ext::dynamic_pointer_cast<QuantExt::FxIndex>(eqfxIndex);
151 const bool isTouchingOnly = false;
152 trigger = checkBarrier(fixing, isTouchingOnly);
153 if (trigger)
154 exerciseDate_ = d;
155 }
156 d = calendar_.advance(d, 1, Days);
157 }
158 }
159 }
160 }
161
162 // check todays spot, if triggered today set the exerciseDate, may have to pay a rebate
163 if (!trigger) {
164 const bool isTouchingOnly = false;
165 trigger = checkBarrier(spot_->value(), isTouchingOnly);
166 if (trigger)
167 exerciseDate_ = today;
168 }
169
170 exercised_ = trigger;
171 return trigger;
172}
173
174bool DoubleBarrierOptionWrapper::checkBarrier(Real spot, bool isTouchingOnly) const {
175 if (isTouchingOnly)
176 return close_enough(spot, barrierLow_) || close_enough(spot, barrierHigh_);
177 else
178 return spot <= barrierLow_ || spot >= barrierHigh_;
179}
180
182 bool trigger = false;
183 Date today = Settings::instance().evaluationDate();
184
185 // check historical fixings - only check if the instrument is not calculated
186 // really only needs to be checked if evaluation date changed
187 if (!instrument_->isCalculated()) {
188 if (startDate_ != Date() && startDate_ < today) {
189 QL_REQUIRE(index_, "no index provided");
190 QL_REQUIRE(calendar_ != Calendar(), "no calendar provided");
191
192
193 QuantLib::ext::shared_ptr<QuantExt::EqFxIndexBase> eqfxIndex =
194 QuantLib::ext::dynamic_pointer_cast<QuantExt::EqFxIndexBase>(index_);
195
196 if (eqfxIndex) {
197 Date d = calendar_.adjust(startDate_);
198 while (d < today && !trigger) {
199 Real fixing = eqfxIndex->pastFixing(d);
200 if (fixing == Null<Real>()) {
203 "Missing fixing for index " + index_->name() + " on " + ore::data::to_string(d) +
204 ", Skipping this date, assuming no trigger",
205 std::map<std::string, std::string>({{"exceptionType", "Invalid or missing fixings"}}))
206 .log();
207 } else {
208 const bool isTouchingOnly = false;
209 trigger = checkBarrier(fixing, isTouchingOnly);
210 }
211 d = calendar_.advance(d, 1, Days);
212 }
213 }
214 }
215 }
216
217 // check todays spot, if triggered today set the exerciseDate, may have to pay a rebate
218 if (!trigger) {
219 const bool isTouchingOnly = false;
220 trigger = checkBarrier(spot_->value(), isTouchingOnly);
221 exerciseDate_ = today;
222 }
223
224 exercised_ = trigger;
225 return trigger;
226}
227
228} // namespace data
229} // namespace oreplus
Wrapper for option instruments, tracks whether option has been exercised or not.
QuantLib::Real NPV() const override
Return the NPV of this instrument.
const std::map< std::string, boost::any > & additionalResults() const override
Return the additional results of this instrument.
virtual bool checkBarrier(Real, bool) const =0
QuantLib::ext::shared_ptr< QuantLib::Index > index_
bool checkBarrier(Real spot, bool isTouchingOnly) const override
QuantLib::Real additionalInstrumentsNPV() const
Real getTimedNPV(const QuantLib::ext::shared_ptr< QuantLib::Instrument > &instr) const
QuantLib::ext::shared_ptr< QuantLib::Instrument > instrument_
void log() const
generate Boost log record to pass to corresponding sinks
Definition: log.cpp:491
QuantLib::Date exerciseDate_
virtual bool exercise() const =0
QuantLib::ext::shared_ptr< QuantLib::Instrument > activeUnderlyingInstrument_
Real multiplier2() const override
bool checkBarrier(Real spot, bool isTouchingOnly) const override
Base class for wrapper of QL instrument, used to store "state" of trade under each scenario.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
bool checkBarrier(Real spot, Barrier::Type type, Real barrier)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Wrapper for option instruments, tracks whether option has been exercised or not.
string conversion utilities