31#include <ql/cashflows/cashflows.hpp>
32#include <ql/cashflows/simplecashflow.hpp>
33#include <ql/math/functional.hpp>
34#include <ql/quotes/derivedquote.hpp>
35#include <ql/quotes/simplequote.hpp>
40 const std::vector<Leg>& underlying,
const std::vector<bool>& isPayer,
const std::vector<std::string>& currencies,
41 const Date& referenceDate,
const std::string& forCcy,
const std::string& domCcy,
42 const Handle<YieldTermStructure>& forCurve,
const Handle<YieldTermStructure>& domCurve,
const Handle<Quote>& fxSpot,
43 const bool includeRefDateFlows) {
45 Date today = Settings::instance().evaluationDate();
49 QL_REQUIRE(referenceDate >= today,
"RepresentativeFxOptionMatcher: referenceDate ("
50 << referenceDate <<
") must be < today (" << today <<
")");
51 QL_REQUIRE(isPayer.size() == underlying.size(),
"RepresentativeFxOptionMatcher: isPayer ("
52 << isPayer.size() <<
") does not match underlying ("
53 << underlying.size() <<
")");
54 QL_REQUIRE(currencies.size() == underlying.size(),
"RepresentativeFxOptionMatcher: currencies ("
55 << currencies.size() <<
") does not match underlying ("
56 << underlying.size() <<
")");
60 auto fxScenarioValue = QuantLib::ext::make_shared<SimpleQuote>(fxSpot->value());
61 Handle<Quote> fxSpotScen(fxScenarioValue);
65 auto m = [](Real x) {
return 1.0 / x; };
66 Handle<Quote> fxSpotScenInv(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxSpotScen, m));
72 for (Size i = 0; i < underlying.size(); ++i) {
75 QL_REQUIRE(currencies[i] == forCcy || currencies[i] == domCcy,
76 "RepresentativeFxOptionMatcher: currency at index "
77 << i <<
" (" << currencies[i] <<
") does not match forCcy (" << forCcy <<
") or domCcy ("
80 for (
auto const& c : underlying[i]) {
84 if (c->date() < referenceDate || (c->date() == referenceDate && !includeRefDateFlows))
89 QL_REQUIRE(!QuantLib::ext::dynamic_pointer_cast<IndexedCoupon>(c),
90 "RepresentativeFxOptionMatcher: Indexed Coupons are not supported");
92 QuantLib::ext::shared_ptr<CashFlow> res;
94 if (
auto fxlinked = QuantLib::ext::dynamic_pointer_cast<FXLinked>(c)) {
98 std::set<std::string> ccys = {fxlinked->fxIndex()->sourceCurrency().code(),
99 fxlinked->fxIndex()->targetCurrency().code()};
100 QL_REQUIRE((ccys == std::set<std::string>{forCcy, domCcy}),
101 "RepresentativeFxOptionMatcher: FXLinked coupon ccys "
102 << fxlinked->fxIndex()->sourceCurrency().code() <<
", "
103 << fxlinked->fxIndex()->targetCurrency().code()
104 <<
" do noth match currencies to be matched (" << forCcy <<
", " << domCcy <<
")");
106 res = QuantLib::ext::dynamic_pointer_cast<CashFlow>(fxlinked->clone(fxlinked->fxIndex()->clone(
107 fxlinked->fxIndex()->sourceCurrency().code() == forCcy ? fxSpotScen : fxSpotScenInv,
108 fxlinked->fxIndex()->sourceCurve(), fxlinked->fxIndex()->targetCurve())));
109 QL_REQUIRE(res,
"RepresentativeFxOptionMatcher: internal error, cloned fx linked cashflow could not be "
116 res = QuantLib::ext::make_shared<SimpleCashFlow>(c->amount(), c->date());
121 res = QuantLib::ext::make_shared<ScaledCashFlow>(isPayer[i] ? -1.0 : 1.0, res);
123 if (currencies[i] == forCcy)
124 forCfs.push_back(res);
126 domCfs.push_back(res);
133 CashFlows::npv(forCfs, **forCurve,
false) * fxSpotScen->value() + CashFlows::npv(domCfs, **domCurve,
false);
137 constexpr Real relShift = 0.01;
139 Real baseFx = fxScenarioValue->value();
141 fxScenarioValue->setValue(baseFx * (1.0 + relShift));
143 CashFlows::npv(forCfs, **forCurve,
false) * fxSpotScen->value() + CashFlows::npv(domCfs, **domCurve,
false);
145 fxScenarioValue->setValue(baseFx * (1.0 - relShift));
147 CashFlows::npv(forCfs, **forCurve,
false) * fxSpotScen->value() + CashFlows::npv(domCfs, **domCurve,
false);
149 Real fxDelta = (npv_up - npv_down) / (2.0 * baseFx * relShift);
154 amount1_ = fxDelta / forCurve->discount(referenceDate);
155 amount2_ = (npv - fxDelta * baseFx) / domCurve->discount(referenceDate);
RepresentativeFxOptionMatcher(const std::vector< Leg > &underlying, const std::vector< bool > &isPayer, const std::vector< std::string > ¤cies, const Date &referenceDate, const std::string &forCcy, const std::string &domCcy, const Handle< YieldTermStructure > &forCurve, const Handle< YieldTermStructure > &domCurve, const Handle< Quote > &fxSpot, const bool includeRefDateFlows=false)
coupon with an indexed notional
representative fx option matcher
Coupon / Cashflow paying scaled amounts.