Skip to content

Commit 39c93cb

Browse files
mgronckijenkins
authored andcommitted
QPR-12206 AMC engine support indexedCoupons
1 parent 1016395 commit 39c93cb

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

OREData/ored/portfolio/swap.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ using std::make_pair;
4242
namespace ore {
4343
namespace data {
4444

45+
46+
47+
4548
void Swap::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
4649
DLOG("Swap::build() called for trade " << id());
4750

@@ -55,6 +58,7 @@ void Swap::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
5558
Size numLegs = legData_.size();
5659
legPayers_ = vector<bool>(numLegs);
5760
std::vector<QuantLib::Currency> currencies(numLegs);
61+
std::vector<QuantLib::Currency> underlyingCurrencies(numLegs);
5862
legs_.resize(numLegs);
5963

6064
isXCCY_ = false;
@@ -67,11 +71,31 @@ void Swap::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
6771
currencies[i] = parseCurrencyWithMinors(legData_[i].currency());
6872
else
6973
currencies[i] = parseCurrency(legData_[i].currency());
74+
7075
if (currencies[i] != currency)
7176
isXCCY_ = true;
7277
isResetting_ = isResetting_ || (!legData_[i].isNotResetXCCY());
7378
}
7479

80+
81+
// Check if there is indexing is used for NDF, needed for AMC
82+
for (Size i = 0; i < numLegs; ++i) {
83+
underlyingCurrencies[i] = currencies[i];
84+
if (tradeType_ == "CrossCurrencySwap" && !isXCCY_) {
85+
vector<Indexing> indexings = legData_[i].indexing();
86+
if (!indexings.empty() && indexings.front().hasData()) {
87+
Indexing indexing = indexings.front();
88+
if (boost::starts_with(indexing.index(), "FX-")) {
89+
auto index = parseFxIndex(indexing.index());
90+
Currency srcCurrency = index->sourceCurrency();
91+
Currency tgtCurrency = index->targetCurrency();
92+
underlyingCurrencies[i] = currency == srcCurrency ? tgtCurrency : srcCurrency;
93+
isXCCY_ = true;
94+
}
95+
}
96+
}
97+
}
98+
7599
static std::set<std::string> eligibleForXbs = {"Fixed", "Floating"};
76100
bool useXbsCurves = true;
77101
for(Size i=0;i<numLegs;++i) {
@@ -151,7 +175,7 @@ void Swap::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
151175
boost::shared_ptr<CrossCurrencySwapEngineBuilderBase> swapBuilder =
152176
boost::dynamic_pointer_cast<CrossCurrencySwapEngineBuilderBase>(builder);
153177
QL_REQUIRE(swapBuilder, "No Builder found for CrossCurrencySwap " << id());
154-
swap->setPricingEngine(swapBuilder->engine(currencies, npvCcy));
178+
swap->setPricingEngine(swapBuilder->engine(underlyingCurrencies, npvCcy));
155179
// take the first legs currency as the npv currency (arbitrary choice)
156180
instrument_.reset(new VanillaInstrument(swap));
157181
} else {

QuantExt/qle/pricingengines/mcmultilegbaseengine.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,42 @@ McMultiLegBaseEngine::CashflowInfo McMultiLegBaseEngine::createCashflowInfo(boos
105105
return info;
106106
}
107107

108+
if (auto indexCpn = boost::dynamic_pointer_cast<IndexedCoupon>(flow)) {
109+
if (boost::dynamic_pointer_cast<FxIndex>(indexCpn->index()) &&
110+
boost::dynamic_pointer_cast<FixedRateCoupon>(indexCpn->underlying())) {
111+
auto fxIndex = boost::dynamic_pointer_cast<FxIndex>(indexCpn->index());
112+
Date fxLinkedFixingDate = indexCpn->fixingDate();
113+
Size fxLinkedSourceCcyIdx = model_->ccyIndex(fxIndex->sourceCurrency());
114+
Size fxLinkedTargetCcyIdx = model_->ccyIndex(fxIndex->targetCurrency());
115+
if (fxLinkedFixingDate > today_) {
116+
Real fxSimTime = time(fxLinkedFixingDate);
117+
info.simulationTimes.push_back(fxSimTime);
118+
info.modelIndices.push_back({});
119+
if (fxLinkedSourceCcyIdx > 0) {
120+
info.modelIndices.front().push_back(
121+
model_->pIdx(CrossAssetModel::AssetType::FX, fxLinkedSourceCcyIdx - 1));
122+
}
123+
if (fxLinkedTargetCcyIdx > 0) {
124+
info.modelIndices.front().push_back(
125+
model_->pIdx(CrossAssetModel::AssetType::FX, fxLinkedTargetCcyIdx - 1));
126+
}
127+
}
128+
info.amountCalculator = [this, fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixingDate,
129+
indexCpn](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
130+
if (fxLinkedFixingDate <= today_)
131+
return RandomVariable(n, indexCpn->amount());
132+
RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
133+
Size fxIdx = 0;
134+
if (fxLinkedSourceCcyIdx > 0)
135+
fxSource = exp(*states.at(0).at(fxIdx++));
136+
if (fxLinkedTargetCcyIdx > 0)
137+
fxTarget = exp(*states.at(0).at(fxIdx));
138+
return RandomVariable(n, indexCpn->underlying()->amount()) * fxSource / fxTarget;
139+
};
140+
return info;
141+
}
142+
}
143+
108144
// handle fx linked fixed cashflow
109145

110146
if (auto fxl = boost::dynamic_pointer_cast<FXLinkedCashFlow>(flow)) {

0 commit comments

Comments
 (0)