19#include <boost/make_shared.hpp>
20#include <boost/test/unit_test.hpp>
43#include <oret/toplevelfixture.hpp>
44#include <ql/cashflows/simplecashflow.hpp>
45#include <ql/currencies/all.hpp>
46#include <ql/indexes/indexmanager.hpp>
47#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
48#include <ql/termstructures/yield/flatforward.hpp>
49#include <ql/time/calendars/target.hpp>
50#include <ql/time/calendars/unitedstates.hpp>
51#include <ql/time/daycounters/actual360.hpp>
55using namespace boost::unit_test_framework;
59BOOST_FIXTURE_TEST_SUITE(OREPlusEquityFXTestSuite, ore::test::TopLevelFixture)
61BOOST_AUTO_TEST_SUITE(FXOptionTest)
78 TestMarket(Real spot, Real q, Real r, Real vol,
bool withFixings =
false) :
MarketImpl(false) {
79 asof_ = Date(3, Feb, 2016);
81 Settings::instance().evaluationDate() =
asof_;
88 std::map<std::string, QuantLib::Handle<QuantLib::Quote>> quotes;
89 quotes[
"EURJPY"] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spot));
90 fx_ = QuantLib::ext::make_shared<FXTriangulation>(quotes);
93 auto conventions = QuantLib::ext::make_shared<Conventions>();
94 conventions->add(QuantLib::ext::make_shared<FXConvention>(
"EUR-JPY-FX",
"0",
"EUR",
"JPY",
"10000",
"EUR,JPY"));
95 InstrumentConventions::instance().setConventions(conventions);
102 TimeSeries<Real> pastFixings;
103 pastFixings[Date(1, Feb, 2016)] = 100;
104 pastFixings[Date(2, Feb, 2016)] = 90;
105 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
106 TimeSeries<Real> pastFixingsInverted;
107 pastFixingsInverted[Date(1, Feb, 2016)] = 1 / pastFixings[Date(1, Feb, 2016)];
108 pastFixingsInverted[Date(2, Feb, 2016)] = 1 / pastFixings[Date(2, Feb, 2016)];
109 IndexManager::instance().setHistory(
"Reuters JPY/EUR", pastFixingsInverted);
113 void setFxSpot(
string ccyPair, Real spot) {
114 auto q = QuantLib::ext::dynamic_pointer_cast<SimpleQuote>(
fx_->getQuote(ccyPair).currentLink());
115 QL_REQUIRE(q,
"internal error: could not cast quote to SimpleQuote in TestMarket::setFxSpot()");
120 Handle<YieldTermStructure> flatRateYts(Real forward) {
121 QuantLib::ext::shared_ptr<YieldTermStructure> yts(
new FlatForward(0, NullCalendar(), forward, Actual360()));
122 return Handle<YieldTermStructure>(yts);
124 Handle<BlackVolTermStructure> flatRateFxv(Volatility forward) {
125 QuantLib::ext::shared_ptr<BlackVolTermStructure> fxv(
new BlackConstantVol(0, NullCalendar(), forward, Actual360()));
126 return Handle<BlackVolTermStructure>(fxv);
129 QuantLib::ext::shared_ptr<SimpleQuote> fxSpot_;
137 BOOST_TEST_MESSAGE(
"Testing FXDigitalOption Price...");
139 FxOptionData fxd[] = {{
"Put", 100.00, 80.0, 0.06, 0.06,
"20161030", 0.35, 2.6710}};
141 for (
auto& f : fxd) {
143 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
144 Date today = Settings::instance().evaluationDate();
145 Settings::instance().evaluationDate() = market->asofDate();
149 OptionData optionData(
"Long",
"Put",
"European",
true, vector<string>(1, f.t));
154 Real expectedNPV = f.result;
157 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
158 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
159 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
161 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
163 fxOption.
build(engineFactory);
167 BOOST_TEST_MESSAGE(
"FX Option, NPV Currency " << fxOption.
npvCurrency());
168 BOOST_TEST_MESSAGE(
"NPV = " << npv);
171 QL_REQUIRE(fxOption.
npvCurrency() ==
"JPY",
"unexpected NPV currency ");
173 BOOST_CHECK_CLOSE(npv, expectedNPV, 0.2);
174 Settings::instance().evaluationDate() = today;
178struct BarrierOptionData {
193 BOOST_TEST_MESSAGE(
"Testing FXBarrierOption Price...");
197 BarrierOptionData fxb[] = {
198 {
"DownAndOut", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 9.0246},
199 {
"DownAndOut", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 4.8759},
200 {
"DownAndOut", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
201 {
"DownAndOut", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
202 {
"DownAndOut", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
203 {
"UpAndOut", 105.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 2.6789},
204 {
"UpAndOut", 105.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 2.3580},
205 {
"UpAndOut", 105.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 2.3453},
207 {
"DownAndIn", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 7.7627},
208 {
"DownAndIn", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 4.0109},
209 {
"DownAndIn", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 2.0576},
210 {
"DownAndIn", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 13.8333},
211 {
"DownAndIn", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 7.8494},
212 {
"DownAndIn", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 3.9795},
213 {
"UpAndIn", 105.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 14.1112},
214 {
"UpAndIn", 105.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 8.4482},
215 {
"UpAndIn", 105.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 4.5910},
217 {
"DownAndOut", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 8.8334},
218 {
"DownAndOut", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 7.0285},
219 {
"DownAndOut", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 5.4137},
220 {
"DownAndOut", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
221 {
"DownAndOut", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
222 {
"DownAndOut", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
223 {
"UpAndOut", 105.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 2.6341},
224 {
"UpAndOut", 105.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 2.4389},
225 {
"UpAndOut", 105.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 2.4315},
227 {
"DownAndIn", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 9.0093},
228 {
"DownAndIn", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 5.1370},
229 {
"DownAndIn", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 2.8517},
230 {
"DownAndIn", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 14.8816},
231 {
"DownAndIn", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 9.2045},
232 {
"DownAndIn", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 5.3043},
233 {
"UpAndIn", 105.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 15.2098},
234 {
"UpAndIn", 105.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 9.7278},
235 {
"UpAndIn", 105.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 5.8350},
238 {
"DownAndOut", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 2.2798},
239 {
"DownAndOut", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 2.2947},
240 {
"DownAndOut", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 2.6252},
241 {
"DownAndOut", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
242 {
"DownAndOut", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
243 {
"DownAndOut", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 3.0000},
244 {
"UpAndOut", 105.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 3.7760},
245 {
"UpAndOut", 105.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 5.4932},
246 {
"UpAndOut", 105.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 7.5187},
248 {
"DownAndIn", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 2.9586},
249 {
"DownAndIn", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 6.5677},
250 {
"DownAndIn", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 11.9752},
251 {
"DownAndIn", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 2.2845},
252 {
"DownAndIn", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 5.9085},
253 {
"DownAndIn", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 11.6465},
254 {
"UpAndIn", 105.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 1.4653},
255 {
"UpAndIn", 105.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 3.3721},
256 {
"UpAndIn", 105.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 7.0846},
258 {
"DownAndOut", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 2.4170},
259 {
"DownAndOut", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 2.4258},
260 {
"DownAndOut", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 2.6246},
261 {
"DownAndOut", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
262 {
"DownAndOut", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
263 {
"DownAndOut", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 3.0000},
264 {
"UpAndOut", 105.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 4.2293},
265 {
"UpAndOut", 105.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 5.8032},
266 {
"UpAndOut", 105.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 7.5649},
268 {
"DownAndIn", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 3.8769},
269 {
"DownAndIn", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 7.7989},
270 {
"DownAndIn", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 13.3078},
271 {
"DownAndIn", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 3.3328},
272 {
"DownAndIn", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 7.2636},
273 {
"DownAndIn", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 12.9713},
274 {
"UpAndIn", 105.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 2.0658},
275 {
"UpAndIn", 105.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 4.4226},
276 {
"UpAndIn", 105.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 8.3686},
280 {
"DownAndOut", 95.0, 3.0,
"Call", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
281 {
"DownAndOut", 95.0, 3.0,
"Call", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
282 {
"DownAndOut", 100.0, 3.0,
"Call", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
283 {
"DownAndOut", 100.0, 3.0,
"Call", 100, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
284 {
"DownAndOut", 100.0, 3.0,
"Call", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
285 {
"UpAndOut", 105.0, 3.0,
"Call", 90, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
286 {
"UpAndOut", 105.0, 3.0,
"Call", 100, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
287 {
"UpAndOut", 105.0, 3.0,
"Call", 110, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
289 {
"DownAndOut", 95.0, 3.0,
"Put", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
290 {
"DownAndOut", 95.0, 3.0,
"Put", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
291 {
"DownAndOut", 100.0, 3.0,
"Put", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
292 {
"DownAndOut", 100.0, 3.0,
"Put", 100, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
293 {
"DownAndOut", 100.0, 3.0,
"Put", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 3.0},
294 {
"UpAndOut", 105.0, 3.0,
"Put", 90, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
295 {
"UpAndOut", 105.0, 3.0,
"Put", 100, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
296 {
"UpAndOut", 105.0, 3.0,
"Put", 110, 110.0, 0.04, 0.08, 0.50, 0.25, 3.0},
300 {
"DownAndIn", 95.0, 3.0,
"Call", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 7.06448},
301 {
"DownAndIn", 95.0, 3.0,
"Call", 100, 90.0, 0.04, 0.08, 0.50, 0.25, 3.29945},
302 {
"DownAndIn", 95.0, 3.0,
"Call", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 1.36007},
303 {
"DownAndIn", 100.0, 3.0,
"Call", 90, 90.0, 0.04, 0.08, 0.50, 0.25, 7.06448},
304 {
"DownAndIn", 100.0, 3.0,
"Call", 100, 90.0, 0.04, 0.08, 0.50, 0.25, 3.29945},
305 {
"DownAndIn", 100.0, 3.0,
"Call", 110, 90.0, 0.04, 0.08, 0.50, 0.25, 1.36007},
306 {
"UpAndIn", 105.0, 3.0,
"Call", 90, 110.0, 0.04, 0.08, 0.50, 0.25, 22.21500},
307 {
"UpAndIn", 105.0, 3.0,
"Call", 100, 110.0, 0.04, 0.08, 0.50, 0.25, 14.52180},
308 {
"UpAndIn", 105.0, 3.0,
"Call", 110, 110.0, 0.04, 0.08, 0.50, 0.25, 8.63437}};
310 vector<string> positions = {
"Long",
"Short"};
311 for (
auto& f : fxb) {
312 for (
auto& position : positions) {
314 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
315 Date today = Settings::instance().evaluationDate();
316 Settings::instance().evaluationDate() = market->asofDate();
319 OptionData optionData(position, f.optionType,
"European",
true, vector<string>(1,
"20160801"));
320 vector<Real> barriers = {f.barrier};
321 vector<TradeBarrier> tradeBarriers;
323 BarrierData barrierData(f.barrierType, barriers, f.rebate, tradeBarriers);
325 FxBarrierOption fxBarrierOption(env, optionData, barrierData, Date(),
"",
"EUR", 1,
330 Real Notional = 1000000;
331 BarrierData barrierDataScaled(f.barrierType, barriers, f.rebate * Notional, tradeBarriers);
332 FxBarrierOption fxBarrierOptionNotional(env, optionData, barrierDataScaled, Date(),
"",
"EUR", Notional,
333 "JPY", Notional * f.k);
335 Real expectedNPV = f.result;
338 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
339 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
340 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
341 engineData->model(
"FxOption") =
"GarmanKohlhagen";
342 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
344 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
346 fxBarrierOption.
build(engineFactory);
347 fxBarrierOptionNotional.
build(engineFactory);
349 Real npv = (position ==
"Long" ? 1 : -1) * fxBarrierOption.
instrument()->NPV();
351 BOOST_TEST_MESSAGE(
"NPV Currency " << fxBarrierOption.
npvCurrency());
352 BOOST_TEST_MESSAGE(
"FX Barrier Option NPV = " << npv);
355 QL_REQUIRE(fxBarrierOption.
npvCurrency() ==
"JPY",
"unexpected NPV currency ");
357 BOOST_CHECK_CLOSE(npv, expectedNPV, 0.2);
358 BOOST_CHECK_CLOSE(fxBarrierOption.
instrument()->NPV() * 1000000,
359 fxBarrierOptionNotional.
instrument()->NPV(), 0.2);
360 Settings::instance().evaluationDate() = today;
366 BOOST_TEST_MESSAGE(
"Testing FXBarrierOption Symmetry...");
372 BarrierOptionData fxb[] = {
373 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 9.0246},
374 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 7.7627},
375 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 4.0109},
376 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 2.0576},
377 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 13.8333},
378 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 7.8494},
379 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 3.9795},
380 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 9.0093},
381 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 5.1370},
382 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 2.8517},
383 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 14.8816},
384 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 9.2045},
385 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 5.3043}};
387 for (
auto& f : fxb) {
389 QuantLib::ext::shared_ptr<Market> marketCall = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
390 QuantLib::ext::shared_ptr<Market> marketPut = QuantLib::ext::make_shared<TestMarket>(f.k, f.r, f.q, f.v);
391 Date today = Settings::instance().evaluationDate();
392 Settings::instance().evaluationDate() = marketCall->asofDate();
395 OptionData optionCallData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
396 OptionData optionPutData(
"Long",
"Put",
"European",
true, vector<string>(1,
"20160801"));
397 vector<Real> barriersCall = {f.barrier};
398 vector<Real> barriersPut = {f.s * f.k / f.barrier};
399 vector<TradeBarrier> tradeBarriers_call, tradeBarriers_put;
400 tradeBarriers_call.push_back(
TradeBarrier(f.barrier,
""));
401 tradeBarriers_put.push_back(
TradeBarrier(f.s * f.k / f.barrier,
""));
402 BarrierData barrierCallData(
"DownAndIn", barriersCall, 0.0, tradeBarriers_call);
403 BarrierData barrierPutData(
"UpAndIn", barriersPut, 0.0, tradeBarriers_put);
406 FxBarrierOption fxCallOption(env, optionCallData, barrierCallData, Date(),
"",
"EUR", 1,
408 FxBarrierOption fxPutOption(env, optionPutData, barrierPutData, Date(),
"",
"EUR", 1,
412 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
413 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
414 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
415 engineData->model(
"FxOption") =
"GarmanKohlhagen";
416 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
418 QuantLib::ext::shared_ptr<EngineFactory> engineFactoryCall = QuantLib::ext::make_shared<EngineFactory>(engineData, marketCall);
419 QuantLib::ext::shared_ptr<EngineFactory> engineFactoryPut = QuantLib::ext::make_shared<EngineFactory>(engineData, marketPut);
421 fxCallOption.
build(engineFactoryCall);
422 fxPutOption.
build(engineFactoryPut);
424 Real npvCall = fxCallOption.
instrument()->NPV();
425 Real npvPut = fxPutOption.
instrument()->NPV();
427 BOOST_TEST_MESSAGE(
"NPV Currency " << fxCallOption.
npvCurrency());
428 BOOST_TEST_MESSAGE(
"FX Barrier Option, NPV Call " << npvCall);
429 BOOST_TEST_MESSAGE(
"FX Barrier Option, NPV Put " << npvPut);
431 BOOST_CHECK_CLOSE(npvCall, npvPut, 0.01);
433 Settings::instance().evaluationDate() = today;
438 BOOST_TEST_MESSAGE(
"Testing FXBarrierOption Parity...");
442 BarrierOptionData fxb[] = {
444 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
445 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
446 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
447 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
448 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
449 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
450 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
451 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
452 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
453 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
454 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
455 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
456 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
459 for (
auto& f : fxb) {
461 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
462 Date today = Settings::instance().evaluationDate();
463 Settings::instance().evaluationDate() = market->asofDate();
466 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
468 vector<Real> barriers = {f.barrier};
469 vector<TradeBarrier> tradeBarriers;
471 BarrierData downInData(
"DownAndIn", barriers, 0.0, tradeBarriers);
472 BarrierData upInData(
"UpAndIn", barriers, 0.0, tradeBarriers);
473 BarrierData downOutData(
"DownAndOut", barriers, 0.0, tradeBarriers);
474 BarrierData upOutData(
"UpAndOut", barriers, 0.0, tradeBarriers);
478 FxOption fxOption(env, optionData,
"EUR", 1,
481 FxBarrierOption downInOption(env, optionData, downInData, Date(),
"",
"EUR", 1,
483 FxBarrierOption upInOption(env, optionData, upInData, Date(),
"",
"EUR", 1,
485 FxBarrierOption downOutOption(env, optionData, downOutData, Date(),
"",
"EUR", 1,
487 FxBarrierOption upOutOption(env, optionData, upOutData, Date(),
"",
"EUR", 1,
491 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
492 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
493 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
494 engineData->model(
"FxOption") =
"GarmanKohlhagen";
495 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
497 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
499 fxOption.
build(engineFactory);
500 downInOption.
build(engineFactory);
501 upInOption.
build(engineFactory);
502 downOutOption.
build(engineFactory);
503 upOutOption.
build(engineFactory);
508 BOOST_CHECK_CLOSE(npv, downInOption.
instrument()->NPV() + downOutOption.
instrument()->NPV(), 0.01);
511 Settings::instance().evaluationDate() = today;
516 BOOST_TEST_MESSAGE(
"Testing FXBarrierOption when barrier already touched...");
520 BarrierOptionData fxb[] = {
521 {
"DownAndIn", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
522 {
"DownAndIn", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
523 {
"DownAndIn", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
524 {
"DownAndIn", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
525 {
"DownAndIn", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
526 {
"DownAndIn", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
527 {
"UpAndIn", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
528 {
"UpAndIn", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
529 {
"UpAndIn", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
531 {
"DownAndIn", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
532 {
"DownAndIn", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
533 {
"DownAndIn", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
534 {
"DownAndIn", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
535 {
"DownAndIn", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
536 {
"DownAndIn", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
537 {
"UpAndIn", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
538 {
"UpAndIn", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
539 {
"UpAndIn", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
541 {
"DownAndOut", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
542 {
"DownAndOut", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
543 {
"DownAndOut", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
544 {
"DownAndOut", 100.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
545 {
"DownAndOut", 100.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
546 {
"DownAndOut", 100.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
547 {
"UpAndOut", 95.0, 3.0,
"Call", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
548 {
"UpAndOut", 95.0, 3.0,
"Call", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
549 {
"UpAndOut", 95.0, 3.0,
"Call", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
551 {
"DownAndOut", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
552 {
"DownAndOut", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
553 {
"DownAndOut", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
554 {
"DownAndOut", 100.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
555 {
"DownAndOut", 100.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
556 {
"DownAndOut", 100.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
557 {
"UpAndOut", 95.0, 3.0,
"Put", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
558 {
"UpAndOut", 95.0, 3.0,
"Put", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
559 {
"UpAndOut", 95.0, 3.0,
"Put", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0}};
561 for (
auto& f : fxb) {
563 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
564 Date today = Settings::instance().evaluationDate();
565 Settings::instance().evaluationDate() = market->asofDate();
568 OptionData optionData(
"Long", f.optionType,
"European",
true, vector<string>(1,
"20160801"));
570 vector<Real> barriers = {f.barrier};
571 vector<TradeBarrier> tradeBarriers;
573 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
577 FxBarrierOption fxBarrierOption(env, optionData, barrierData, Date(1, Month::February, 2016),
578 "TARGET",
"EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
579 FxOption fxOption(env, optionData,
"EUR", 1,
582 FxBarrierOption fxBarrierOptionInverted(env, optionData, barrierData, Date(1, Month::February, 2016),
584 "JPY", f.k,
"FX-Reuters-JPY-EUR");
587 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
588 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
589 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
590 engineData->model(
"FxOption") =
"GarmanKohlhagen";
591 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
593 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
595 fxOption.
build(engineFactory);
596 fxBarrierOption.
build(engineFactory);
597 fxBarrierOptionInverted.
build(engineFactory);
600 if (f.barrierType ==
"DownAndIn" || f.barrierType ==
"UpAndIn") {
602 BOOST_CHECK_CLOSE(fxBarrierOptionInverted.
instrument()->NPV(), fxOption.
instrument()->NPV(), 0.01);
604 BOOST_CHECK_CLOSE(fxBarrierOption.
instrument()->NPV(), 0.0, 0.01);
605 BOOST_CHECK_CLOSE(fxBarrierOptionInverted.
instrument()->NPV(), 0.0, 0.01);
608 Settings::instance().evaluationDate() = today;
609 IndexManager::instance().clearHistories();
613struct DigitalBarrierOptionData {
628 BOOST_TEST_MESSAGE(
"Testing FXDigitalBarrierOption Price...");
632 DigitalBarrierOptionData fxb[] = {
634 {
"DownAndIn", 100.00, 15.00,
"Call", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.9289},
635 {
"DownAndIn", 100.00, 15.00,
"Call", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 6.2150},
636 {
"UpAndIn", 100.00, 15.00,
"Call", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 5.8926},
637 {
"UpAndIn", 100.00, 15.00,
"Call", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 7.4519},
638 {
"DownAndIn", 100.00, 15.00,
"Put", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.4314},
639 {
"DownAndIn", 100.00, 15.00,
"Put", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 3.1454},
640 {
"UpAndIn", 100.00, 15.00,
"Put", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 5.3297},
641 {
"UpAndIn", 100.00, 15.00,
"Put", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.7704},
642 {
"DownAndOut", 100.00, 15.00,
"Call", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.8758},
643 {
"DownAndOut", 100.00, 15.00,
"Call", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.9081},
644 {
"UpAndOut", 100.00, 15.00,
"Call", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0000},
645 {
"UpAndOut", 100.00, 15.00,
"Call", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0407},
646 {
"DownAndOut", 100.00, 15.00,
"Put", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0323},
647 {
"DownAndOut", 100.00, 15.00,
"Put", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0000},
648 {
"UpAndOut", 100.00, 15.00,
"Put", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.0461},
649 {
"UpAndOut", 100.00, 15.00,
"Put", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.0054}};
651 for (
auto& f : fxb) {
653 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
654 Date today = market->asofDate();
655 Settings::instance().evaluationDate() = market->asofDate();
658 OptionData optionData(
"Long", f.optionType,
"European",
true, vector<string>(1,
"20160801"));
660 vector<Real> barriers = {f.barrier};
661 vector<TradeBarrier> tradeBarriers;
663 BarrierData barrierData(f.barrierType, barriers, 0, tradeBarriers);
669 Real expectedNPV = f.result / f.cash;
672 map<string, string> engineParamMap;
673 engineParamMap[
"Scheme"] =
"Douglas";
674 engineParamMap[
"TimeGridPerYear"] =
"800";
675 engineParamMap[
"XGrid"] =
"400";
676 engineParamMap[
"DampingSteps"] =
"100";
678 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
679 engineData->model(
"FxDigitalBarrierOption") =
"GarmanKohlhagen";
680 engineData->engine(
"FxDigitalBarrierOption") =
"FdBlackScholesBarrierEngine";
681 engineData->engineParameters(
"FxDigitalBarrierOption") = engineParamMap;
682 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
683 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
684 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
685 barrierOption.
build(engineFactory);
687 Real npv = barrierOption.
instrument()->NPV() / f.cash;
689 BOOST_TEST_MESSAGE(
"NPV Currency " << barrierOption.
npvCurrency());
693 BOOST_CHECK_SMALL(npv - expectedNPV, 1e-3);
694 Settings::instance().evaluationDate() = today;
699 BOOST_TEST_MESSAGE(
"Testing FXDigitalBarrierOption Price...");
703 DigitalBarrierOptionData fxb[] = {
705 {
"", 100.00, 15.00,
"Call", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
706 {
"", 100.00, 15.00,
"Call", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
707 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
708 {
"", 100.00, 15.00,
"Call", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
709 {
"", 100.00, 15.00,
"Put", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
710 {
"", 100.00, 15.00,
"Put", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
711 {
"", 100.00, 15.00,
"Put", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
712 {
"", 100.00, 15.00,
"Put", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
713 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, -0.14, 0.10, 0.5, 0.20, 0.0},
714 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, 0.03, 0.10, 0.5, 0.20, 0.0},
715 {
"", 100.00, 15.00,
"Put", 102.00, 98.00, 0.00, 0.10, 0.5, 0.20, 0.0},
716 {
"", 100.00, 15.00,
"Put", 102.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0},
717 {
"", 100.00, 15.00,
"Call", 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0},
718 {
"", 100.00, 15.00,
"Call", 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0},
719 {
"", 100.00, 15.00,
"Put", 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0},
720 {
"", 100.00, 15.00,
"Put", 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0}};
722 vector<string> payoutCcys = {
"EUR",
"JPY"};
723 for (
auto& f : fxb) {
725 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
726 Date today = market->asofDate();
727 Settings::instance().evaluationDate() = market->asofDate();
728 for (
auto& payoutCcy : payoutCcys) {
731 OptionData optionData(
"Long", f.optionType,
"European",
true, vector<string>(1,
"20160801"));
733 vector<Real> barriers = {f.barrier};
734 vector<TradeBarrier> tradeBarriers;
737 BarrierData downInData(
"DownAndIn", barriers, 0.0, tradeBarriers);
738 BarrierData upInData(
"UpAndIn", barriers, 0.0, tradeBarriers);
739 BarrierData downOutData(
"DownAndOut", barriers, 0.0, tradeBarriers);
740 BarrierData upOutData(
"UpAndOut", barriers, 0.0, tradeBarriers);
741 BarrierData barrierData(f.barrierType, barriers, 0, tradeBarriers);
744 FxDigitalOption fxOption(env, optionData, f.k, payoutCcy, f.cash,
"EUR",
748 "JPY",
"",
"",
"", payoutCcy);
750 "JPY",
"",
"",
"", payoutCcy);
752 "JPY",
"",
"",
"", payoutCcy);
754 "JPY",
"",
"",
"", payoutCcy);
757 map<string, string> engineParamMap;
758 engineParamMap[
"Scheme"] =
"Douglas";
759 engineParamMap[
"TimeGridPerYear"] =
"400";
760 engineParamMap[
"XGrid"] =
"400";
761 engineParamMap[
"DampingSteps"] =
"100";
763 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
764 engineData->model(
"FxDigitalBarrierOption") =
"GarmanKohlhagen";
765 engineData->engine(
"FxDigitalBarrierOption") =
"FdBlackScholesBarrierEngine";
766 engineData->engineParameters(
"FxDigitalBarrierOption") = engineParamMap;
767 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
768 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
769 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
771 fxOption.
build(engineFactory);
772 downInOption.
build(engineFactory);
773 upInOption.
build(engineFactory);
774 downOutOption.
build(engineFactory);
775 upOutOption.
build(engineFactory);
779 BOOST_TEST_MESSAGE(
"NPV Currency " << fxOption.
npvCurrency());
783 BOOST_CHECK_CLOSE(npv, downInOption.
instrument()->NPV() + downOutOption.
instrument()->NPV(), 0.1);
786 Settings::instance().evaluationDate() = today;
791 BOOST_TEST_MESSAGE(
"Testing FXDigitalBarrierOption Price...");
793 DigitalBarrierOptionData fxb[] = {
795 {
"", 100.00, 15.00,
"Call", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
796 {
"", 100.00, 15.00,
"Call", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
797 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
798 {
"", 100.00, 15.00,
"Call", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
799 {
"", 100.00, 15.00,
"Put", 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
800 {
"", 100.00, 15.00,
"Put", 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0},
801 {
"", 100.00, 15.00,
"Put", 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
802 {
"", 100.00, 15.00,
"Put", 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0},
803 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, -0.14, 0.10, 0.5, 0.20, 0.0},
804 {
"", 100.00, 15.00,
"Call", 102.00, 95.00, 0.03, 0.10, 0.5, 0.20, 0.0},
805 {
"", 100.00, 15.00,
"Put", 102.00, 98.00, 0.00, 0.10, 0.5, 0.20, 0.0},
806 {
"", 100.00, 15.00,
"Put", 102.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0},
807 {
"", 100.00, 15.00,
"Call", 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0},
808 {
"", 100.00, 15.00,
"Call", 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0},
809 {
"", 100.00, 15.00,
"Put", 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0},
810 {
"", 100.00, 15.00,
"Put", 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0}};
812 vector<string> payoutCcys = {
"EUR",
"JPY"};
813 vector<string> fxIndices = {
"FX-Reuters-EUR-JPY",
"FX-Reuters-JPY-EUR"};
814 for (
auto& f : fxb) {
816 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
817 Date today = market->asofDate();
818 Settings::instance().evaluationDate() = market->asofDate();
819 for (
auto& payoutCcy : payoutCcys) {
820 for (
auto& fxIndex : fxIndices) {
822 OptionData optionData(
"Long", f.optionType,
"European",
true, vector<string>(1,
"20160801"));
824 vector<Real> barriers = {f.barrier};
825 vector<TradeBarrier> tradeBarriers;
828 BarrierData downInData(
"DownAndIn", barriers, 0.0, tradeBarriers);
829 BarrierData upInData(
"UpAndIn", barriers, 0.0, tradeBarriers);
830 BarrierData downOutData(
"DownAndOut", barriers, 0.0, tradeBarriers);
831 BarrierData upOutData(
"UpAndOut", barriers, 0.0, tradeBarriers);
834 FxDigitalOption fxOption(env, optionData, f.k, payoutCcy, f.cash,
"EUR",
837 "JPY",
"20160201",
"TARGET", fxIndex, payoutCcy);
839 "JPY",
"20160201",
"TARGET", fxIndex, payoutCcy);
841 "JPY",
"20160201",
"TARGET", fxIndex, payoutCcy);
843 "JPY",
"20160201",
"TARGET", fxIndex, payoutCcy);
846 map<string, string> engineParamMap;
847 engineParamMap[
"Scheme"] =
"Douglas";
848 engineParamMap[
"TimeGridPerYear"] =
"400";
849 engineParamMap[
"XGrid"] =
"400";
850 engineParamMap[
"DampingSteps"] =
"100";
852 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
853 engineData->model(
"FxDigitalBarrierOption") =
"GarmanKohlhagen";
854 engineData->engine(
"FxDigitalBarrierOption") =
"FdBlackScholesBarrierEngine";
855 engineData->engineParameters(
"FxDigitalBarrierOption") = engineParamMap;
856 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
857 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
858 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
860 fxOption.
build(engineFactory);
861 downInOption.
build(engineFactory);
862 upInOption.
build(engineFactory);
863 downOutOption.
build(engineFactory);
864 upOutOption.
build(engineFactory);
868 BOOST_TEST_MESSAGE(
"NPV Currency " << fxOption.
npvCurrency());
871 BOOST_CHECK_CLOSE(npv, downInOption.
instrument()->NPV(), 0.01);
872 BOOST_CHECK_CLOSE(npv, upInOption.
instrument()->NPV(), 0.01);
873 BOOST_CHECK_CLOSE(0.0, downOutOption.
instrument()->NPV(), 0.01);
874 BOOST_CHECK_CLOSE(0.0, upOutOption.
instrument()->NPV(), 0.01);
877 Settings::instance().evaluationDate() = today;
878 IndexManager::instance().clearHistories();
882struct FxTouchOptionData {
888 bool payoffCurrencyDomestic;
898 BOOST_TEST_MESSAGE(
"Testing FXTouchOption Price...");
902 FxTouchOptionData fxd[] = {
904 {
"DownAndIn", 100.0, 15.0,
true,
"Put",
true, 105.0, 0.0, 0.1, 0.5, 0.2, 9.3604},
905 {
"UpAndIn", 100.0, 15.0,
true,
"Call",
true, 95.0, 0.0, 0.1, 0.5, 0.2, 11.2223},
906 {
"DownAndOut", 100.0, 15.0,
true,
"Put",
true, 105.0, 0.0, 0.1, 0.5, 0.2, 4.9081},
907 {
"UpAndOut", 100.0, 15.0,
true,
"Call",
true, 95.0, 0.0, 0.1, 0.5, 0.2, 3.0461},
910 {
"DownAndIn", 100.0, 15.0,
false,
"Put",
true, 105.0, 0.0, 0.1, 0.5, 0.2, 9.3604},
911 {
"UpAndIn", 100.0, 15.0,
false,
"Call",
true, 95.0, 0.0, 0.1, 0.5, 0.2, 11.2223},
914 {
"DownAndIn", 100.0, 15.0,
true,
"Put",
true, 95.0, 0.0, 0.1, 0.5, 0.2, 14.2684},
915 {
"UpAndIn", 100.0, 15.0,
true,
"Call",
true, 105.0, 0.0, 0.1, 0.5, 0.2, 14.2684},
916 {
"DownAndOut", 100.0, 15.0,
true,
"Put",
true, 95.0, 0.0, 0.1, 0.5, 0.2, 0.0},
917 {
"UpAndOut", 100.0, 15.0,
true,
"Call",
true, 105.0, 0.0, 0.1, 0.5, 0.2, 0.0},
920 {
"UpAndIn", 1000.0, 15.0,
true,
"Call",
true, 100.0, 0.0, 0.1, 0.5, 0.2, 0.0},
921 {
"UpAndOut", 1000.0, 15.0,
true,
"Call",
true, 100.0, 0.0, 0.1, 0.5, 0.2, 14.2684},
925 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
926 engineData->model(
"FxTouchOption") =
"GarmanKohlhagen";
927 engineData->engine(
"FxTouchOption") =
"AnalyticDigitalAmericanEngine";
928 engineData->model(
"Swap") =
"DiscountedCashflows";
929 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
931 for (
auto& f : fxd) {
933 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
935 Date today = Settings::instance().evaluationDate();
936 Settings::instance().evaluationDate() = market->asofDate();
939 vector<Real> barriers = {f.barrier};
940 vector<TradeBarrier> tradeBarriers;
942 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
943 OptionData optionData(
"Long", f.optionType,
"American", f.payoffAtExpiry, vector<string>(1,
"20160801"));
945 FxTouchOption fxTouchOption(env, optionData, barrierData,
"EUR",
"JPY",
946 f.payoffCurrencyDomestic ?
"JPY" :
"EUR", f.cash);
948 Real expectedNPV = f.result;
951 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
953 fxTouchOption.
build(engineFactory);
958 BOOST_TEST_MESSAGE(
"FX Touch Option, NPV Currency " << ccy);
959 BOOST_TEST_MESSAGE(
"NPV = " << npv);
960 BOOST_TEST_MESSAGE(
"Expected NPV = " << expectedNPV);
962 BOOST_CHECK_SMALL(npv - expectedNPV, 0.01);
963 Settings::instance().evaluationDate() = today;
968 BOOST_TEST_MESSAGE(
"Testing FXTouchOption Parity...");
972 FxTouchOptionData fxb[] = {
974 {
"", 0.0, 1e6,
true,
"",
true, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
975 {
"", 95.0, 1e6,
true,
"",
true, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
976 {
"", 100.0, 1e6,
true,
"",
true, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
977 {
"", 105.0, 1e6,
true,
"",
true, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
978 {
"", 999.0, 1e6,
true,
"",
true, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0}};
980 for (
auto& f : fxb) {
982 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
983 Date today = Settings::instance().evaluationDate();
984 Settings::instance().evaluationDate() = market->asofDate();
987 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
989 vector<Real> barriers = {f.barrier};
990 vector<TradeBarrier> tradeBarriers;
993 BarrierData downInData(
"DownAndIn", barriers, 0.0, tradeBarriers);
994 BarrierData upInData(
"UpAndIn", barriers, 0.0, tradeBarriers);
995 BarrierData downOutData(
"DownAndOut", barriers, 0.0, tradeBarriers);
996 BarrierData upOutData(
"UpAndOut", barriers, 0.0, tradeBarriers);
1000 vector<double> amounts = {f.cash};
1001 vector<string> dates = {
"2016-08-01"};
1003 LegData legData(QuantLib::ext::make_shared<CashflowData>(amounts, dates),
true,
1004 f.payoffCurrencyDomestic ?
"JPY" :
"EUR");
1008 FxTouchOption downInOption(env, optionData, downInData,
"EUR",
"JPY", f.payoffCurrencyDomestic ?
"JPY" :
"EUR",
1010 FxTouchOption upInOption(env, optionData, upInData,
"EUR",
"JPY", f.payoffCurrencyDomestic ?
"JPY" :
"EUR",
1012 FxTouchOption downOutOption(env, optionData, downOutData,
"EUR",
"JPY",
1013 f.payoffCurrencyDomestic ?
"JPY" :
"EUR", f.cash);
1014 FxTouchOption upOutOption(env, optionData, upOutData,
"EUR",
"JPY", f.payoffCurrencyDomestic ?
"JPY" :
"EUR",
1018 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1019 engineData->model(
"FxTouchOption") =
"GarmanKohlhagen";
1020 engineData->engine(
"FxTouchOption") =
"AnalyticDigitalAmericanEngine";
1021 engineData->model(
"Swap") =
"DiscountedCashflows";
1022 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1024 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1026 swap.build(engineFactory);
1027 downInOption.build(engineFactory);
1028 upInOption.
build(engineFactory);
1029 downOutOption.
build(engineFactory);
1030 upOutOption.
build(engineFactory);
1032 Real npv = swap.instrument()->NPV();
1035 BOOST_CHECK_CLOSE(npv, downInOption.instrument()->NPV() + downOutOption.
instrument()->NPV(), 0.01);
1036 BOOST_CHECK_CLOSE(npv, upInOption.
instrument()->NPV() + upOutOption.
instrument()->NPV(), 0.01);
1038 Settings::instance().evaluationDate() = today;
1043 BOOST_TEST_MESSAGE(
"Testing FXTouchOption when barrier already touched...");
1045 struct FxTouchOptionTouchedData {
1061 FxTouchOptionTouchedData fxt[] = {
1063 {
"DownAndIn", 80.0, 1e6, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1064 {
"DownAndIn", 80.0, 1e6, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1065 {
"DownAndIn", 80.0, 1e6, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1066 {
"DownAndIn", 80.0, 1e6, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1067 {
"DownAndIn", 80.0, 1e6, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1068 {
"DownAndIn", 80.0, 1e6, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1070 {
"UpAndIn", 120.0, 1e6, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1071 {
"UpAndIn", 120.0, 1e6, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1072 {
"UpAndIn", 120.0, 1e6, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1073 {
"UpAndIn", 120.0, 1e6, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1074 {
"UpAndIn", 120.0, 1e6, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1075 {
"UpAndIn", 120.0, 1e6, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1077 {
"DownAndOut", 80.0, 1e6, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1078 {
"DownAndOut", 80.0, 1e6, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1079 {
"DownAndOut", 80.0, 1e6, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1080 {
"DownAndOut", 80.0, 1e6, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1081 {
"DownAndOut", 80.0, 1e6, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1082 {
"DownAndOut", 80.0, 1e6, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1084 {
"UpAndOut", 120.0, 1e6, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1085 {
"UpAndOut", 120.0, 1e6, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1086 {
"UpAndOut", 120.0, 1e6, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1087 {
"UpAndOut", 120.0, 1e6, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1088 {
"UpAndOut", 120.0, 1e6, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1089 {
"UpAndOut", 120.0, 1e6, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0}};
1091 vector<string> payoutCcys = {
"EUR",
"JPY"};
1092 vector<string> fxIndices = {
"FX-Reuters-EUR-JPY",
"FX-Reuters-JPY-EUR"};
1093 for (
auto& f : fxt) {
1095 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
1096 Date today = Settings::instance().evaluationDate();
1097 Settings::instance().evaluationDate() = market->asofDate();
1098 TimeSeries<Real> pastFixings;
1099 pastFixings[market->asofDate() - 1 * Days] = f.s_1;
1100 pastFixings[market->asofDate() - 2 * Days] = f.s_2;
1101 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
1102 TimeSeries<Real> pastFixingsInverted;
1103 pastFixingsInverted[market->asofDate() - 1 * Days] = 1 / pastFixings[market->asofDate() - 1 * Days];
1104 pastFixingsInverted[market->asofDate() - 2 * Days] = 1 / pastFixings[market->asofDate() - 2 * Days];
1105 IndexManager::instance().setHistory(
"Reuters JPY/EUR", pastFixingsInverted);
1106 for (
auto& payoutCcy : payoutCcys) {
1107 for (
auto& fxIndex : fxIndices) {
1109 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1111 vector<Real> barriers = {f.barrier};
1112 vector<TradeBarrier> tradeBarriers;
1114 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
1118 vector<double> amounts = {f.cash};
1119 vector<string> dates = {
"2016-08-01"};
1121 LegData legData(QuantLib::ext::make_shared<CashflowData>(amounts, dates),
true, payoutCcy);
1125 FxTouchOption touchOption(env, optionData, barrierData,
"EUR",
"JPY", payoutCcy, f.cash,
"20160201",
1129 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1130 engineData->model(
"FxTouchOption") =
"GarmanKohlhagen";
1131 engineData->engine(
"FxTouchOption") =
"AnalyticDigitalAmericanEngine";
1132 engineData->model(
"Swap") =
"DiscountedCashflows";
1133 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1135 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1137 touchOption.build(engineFactory);
1138 swap.build(engineFactory);
1141 if (f.barrierType ==
"DownAndIn" || f.barrierType ==
"UpAndIn")
1142 BOOST_CHECK_CLOSE(touchOption.instrument()->NPV(), swap.instrument()->NPV(), 0.01);
1144 BOOST_CHECK_CLOSE(touchOption.instrument()->NPV(), 0.0, 0.01);
1147 Settings::instance().evaluationDate() = today;
1148 IndexManager::instance().clearHistories();
1152struct DoubleBarrierOptionData {
1167struct DoubleTouchOptionData {
1183DoubleBarrierOptionData fxdb[] = {
1185 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3515},
1186 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.25, 6.1644},
1187 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.35, 7.0373},
1188 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.15, 6.9853},
1189 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.25, 7.9336},
1190 {
"KnockOut", 50.0, 150.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.35, 6.5088},
1192 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3505},
1193 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.25, 5.8500},
1194 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.35, 5.7726},
1195 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.15, 6.8082},
1196 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.25, 6.3383},
1197 {
"KnockOut", 60.0, 140.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.35, 4.3841},
1199 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3139},
1200 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.25, 4.8293},
1201 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.35, 3.7765},
1202 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.15, 5.9697},
1203 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.25, 4.0004},
1204 {
"KnockOut", 70.0, 130.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.35, 2.2563},
1206 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.15, 3.7516},
1207 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.25, 2.6387},
1208 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.35, 1.4903},
1209 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.15, 3.5805},
1210 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.25, 1.5098},
1211 {
"KnockOut", 80.0, 120.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.5635},
1213 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.2055},
1214 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.25, 0.3098},
1215 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.25, 0.35, 0.0477},
1216 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.15, 0.5537},
1217 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.25, 0.0441},
1219 {
"KnockOut", 90.0, 110.0, 0.0,
"Call", 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.00109}};
1223DoubleTouchOptionData fxdt[] = {
1225 {
"KnockOut", 80.0, 120.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.1, 9.8716},
1226 {
"KnockOut", 80.0, 120.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.2, 8.9307},
1227 {
"KnockOut", 80.0, 120.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.3, 6.3272},
1228 {
"KnockOut", 80.0, 120.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.5, 1.9094},
1230 {
"KnockOut", 85.0, 115.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.1, 9.7961},
1231 {
"KnockOut", 85.0, 115.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.2, 7.2300},
1232 {
"KnockOut", 85.0, 115.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.3, 3.7100},
1233 {
"KnockOut", 85.0, 115.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.5, 0.4271},
1235 {
"KnockOut", 90.0, 110.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.1, 8.9054},
1236 {
"KnockOut", 90.0, 110.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.2, 3.6752},
1237 {
"KnockOut", 90.0, 110.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.3, 0.7960},
1238 {
"KnockOut", 90.0, 110.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.5, 0.0059},
1240 {
"KnockOut", 95.0, 105.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.1, 3.6323},
1241 {
"KnockOut", 95.0, 105.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.2, 0.0911},
1242 {
"KnockOut", 95.0, 105.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.3, 0.0002},
1243 {
"KnockOut", 95.0, 105.0, 10.0, 100.0, 0.02, 0.05, 0.25, 0.5, 0.0000}};
1247 BOOST_TEST_MESSAGE(
"Testing FXDoubleBarrierOption Price...");
1248 for (
auto& f : fxdb) {
1250 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1251 Date today = Settings::instance().evaluationDate();
1252 Settings::instance().evaluationDate() = market->asofDate();
1255 Date exDate = today + Integer(f.t * 360 + 0.5);
1257 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1258 vector<TradeBarrier> tradeBarriers;
1259 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1260 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1261 BarrierData barrierData(f.barrierType, barriers, f.rebate, tradeBarriers);
1269 Real Notional = 1000000;
1270 BarrierData barrierDataScaled(f.barrierType, barriers, f.rebate * Notional, tradeBarriers);
1273 "JPY", Notional * f.k);
1275 Real expectedNPV = f.result;
1278 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1279 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
1280 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
1281 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1282 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1284 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1286 fxDoubleBarrierOption.
build(engineFactory);
1288 fxDoubleBarrierOptionNotional.
build(engineFactory);
1290 Real npv = fxDoubleBarrierOption.
instrument()->NPV();
1292 BOOST_TEST_MESSAGE(
"NPV Currency " << fxDoubleBarrierOption.
npvCurrency());
1293 BOOST_TEST_MESSAGE(
"FX Barrier Option NPV = " << npv);
1295 BOOST_CHECK_CLOSE(npv, expectedNPV, 0.2);
1296 BOOST_CHECK_CLOSE(fxDoubleBarrierOption.
instrument()->NPV() * 1000000,
1297 fxDoubleBarrierOptionNotional.
instrument()->NPV(), 0.2);
1298 Settings::instance().evaluationDate() = today;
1303 BOOST_TEST_MESSAGE(
"Testing FXDoubleBarrierOption Parity ...");
1304 for (
auto& f : fxdb) {
1306 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1307 Date today = Settings::instance().evaluationDate();
1308 Settings::instance().evaluationDate() = market->asofDate();
1310 Date exDate = today + Integer(f.t * 360 + 0.5);
1312 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1313 vector<TradeBarrier> tradeBarriers;
1314 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1315 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1316 BarrierData barrierDataIn(
"KnockIn", barriers, f.rebate, tradeBarriers);
1317 BarrierData barrierDataOut(
"KnockOut", barriers, f.rebate, tradeBarriers);
1326 FxOption fxOption(env, optionData,
"EUR", 1,
1331 Real Notional = 1000000;
1332 BarrierData barrierDataScaled(f.barrierType, barriers, f.rebate * Notional, tradeBarriers);
1335 "JPY", Notional * f.k);
1338 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1339 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
1340 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
1341 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1342 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1344 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1346 fxDoubleBarrierInOption.
build(engineFactory);
1347 fxDoubleBarrierOutOption.
build(engineFactory);
1348 fxOption.
build(engineFactory);
1350 Real npv = fxDoubleBarrierInOption.
instrument()->NPV();
1352 BOOST_TEST_MESSAGE(
"NPV Currency " << fxDoubleBarrierInOption.
npvCurrency());
1353 BOOST_TEST_MESSAGE(
"FX Barrier Option NPV = " << npv);
1354 BOOST_TEST_MESSAGE(
"FX Option NPV = " << fxOption.
instrument()->NPV());
1357 QL_REQUIRE(fxOption.
npvCurrency() ==
"JPY",
"unexpected NPV currency ");
1359 BOOST_CHECK_CLOSE(fxDoubleBarrierInOption.
instrument()->NPV() + fxDoubleBarrierOutOption.
instrument()->NPV(),
1361 Settings::instance().evaluationDate() = today;
1366 BOOST_TEST_MESSAGE(
"Testing FXDoubleBarrierOption when barrier already touched...");
1368 struct DoubleBarrierOptionTouchedData {
1387 DoubleBarrierOptionTouchedData fxdb[] = {
1390 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1391 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1392 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1393 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1394 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1395 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1397 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1398 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1399 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1400 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1401 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1402 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1404 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1405 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1406 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1407 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1408 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1409 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1411 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 80.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1412 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 80.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1413 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1414 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1415 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 70.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1416 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1418 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1419 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1420 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1421 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1422 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1423 {
"KnockIn", 80.0, 120.0, 3.0,
"Call", 100.0, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1425 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1426 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1427 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1428 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1429 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1430 {
"KnockIn", 80.0, 120.0, 3.0,
"Put", 100.0, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1432 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1433 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1434 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1435 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1436 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1437 {
"KnockOut", 80.0, 120.0, 3.0,
"Call", 100.0, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1439 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1440 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 120.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1441 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1442 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 100.0, 130.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1443 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 100.0, 130.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1444 {
"KnockOut", 80.0, 120.0, 3.0,
"Put", 100.0, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0}};
1446 for (
auto& f : fxdb) {
1448 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
1449 Date today = Settings::instance().evaluationDate();
1450 Settings::instance().evaluationDate() = market->asofDate();
1451 TimeSeries<Real> pastFixings;
1452 pastFixings[market->asofDate() - 1 * Days] = f.s_1;
1453 pastFixings[market->asofDate() - 2 * Days] = f.s_2;
1454 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
1455 TimeSeries<Real> pastFixingsInverted;
1456 pastFixingsInverted[market->asofDate() - 1 * Days] = 1 / pastFixings[market->asofDate() - 1 * Days];
1457 pastFixingsInverted[market->asofDate() - 2 * Days] = 1 / pastFixings[market->asofDate() - 2 * Days];
1458 IndexManager::instance().setHistory(
"Reuters JPY/EUR", pastFixingsInverted);
1461 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1463 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1464 vector<TradeBarrier> tradeBarriers;
1465 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1466 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1467 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
1471 FxDoubleBarrierOption doubleBarrierOption(env, optionData, barrierData, Date(1, Month::February, 2016),
"TARGET",
1472 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
1473 FxDoubleBarrierOption doubleBarrierOptionInverted(env, optionData, barrierData, Date(1, Month::February, 2016),
"TARGET",
1474 "EUR", 1,
"JPY", f.k,
"FX-Reuters-JPY-EUR");
1475 FxOption fxOption(env, optionData,
"EUR", 1,
1479 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1480 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
1481 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
1482 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1483 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1485 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1487 doubleBarrierOption.
build(engineFactory);
1488 doubleBarrierOptionInverted.
build(engineFactory);
1489 fxOption.
build(engineFactory);
1492 if (f.barrierType ==
"KnockIn") {
1493 BOOST_CHECK_CLOSE(doubleBarrierOption.
instrument()->NPV(), fxOption.
instrument()->NPV(), 0.01);
1494 BOOST_CHECK_CLOSE(doubleBarrierOptionInverted.
instrument()->NPV(), fxOption.
instrument()->NPV(), 0.01);
1496 BOOST_CHECK_CLOSE(doubleBarrierOption.
instrument()->NPV(), 0.0, 0.01);
1497 BOOST_CHECK_CLOSE(doubleBarrierOptionInverted.
instrument()->NPV(), 0.0, 0.01);
1500 Settings::instance().evaluationDate() = today;
1501 IndexManager::instance().clearHistories();
1506 BOOST_TEST_MESSAGE(
"Testing FXDoubleTouchOption Price...");
1509 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1510 engineData->model(
"FxDoubleTouchOption") =
"GarmanKohlhagen";
1511 engineData->engine(
"FxDoubleTouchOption") =
"AnalyticDoubleBarrierBinaryEngine";
1512 engineData->model(
"Swap") =
"DiscountedCashflows";
1513 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1515 for (
auto& f : fxdt) {
1517 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1519 Date today = Settings::instance().evaluationDate();
1520 Settings::instance().evaluationDate() = market->asofDate();
1522 Date exDate = today + Integer(f.t * 360 + 0.5);
1523 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1524 vector<TradeBarrier> tradeBarriers;
1525 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1526 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1527 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
1530 FxDoubleTouchOption fxDoubleTouchOption(env, optionData, barrierData,
"EUR",
"JPY",
"JPY", f.cash);
1532 Real expectedNPV = f.result;
1535 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1537 fxDoubleTouchOption.
build(engineFactory);
1539 Real npv = fxDoubleTouchOption.
instrument()->NPV();
1542 BOOST_TEST_MESSAGE(
"FX Double Touch Option, NPV Currency " << ccy);
1543 BOOST_TEST_MESSAGE(
"NPV = " << npv);
1544 BOOST_TEST_MESSAGE(
"Expected NPV = " << expectedNPV);
1546 BOOST_CHECK_SMALL(npv - expectedNPV, 0.01);
1547 Settings::instance().evaluationDate() = today;
1552 BOOST_TEST_MESSAGE(
"Testing FXDoubleTouchOption Parity...");
1556 for (
auto& f : fxdt) {
1558 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1559 Date today = Settings::instance().evaluationDate();
1560 Settings::instance().evaluationDate() = market->asofDate();
1563 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1565 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1566 vector<TradeBarrier> tradeBarriers;
1567 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1568 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1569 BarrierData knonkOutData(
"KnockOut", barriers, 0.0, tradeBarriers);
1570 BarrierData knonkInData(
"KnockIn", barriers, 0.0, tradeBarriers);
1574 vector<double> amounts = {f.cash};
1575 vector<string> dates = {
"2016-08-01"};
1577 LegData legData(QuantLib::ext::make_shared<CashflowData>(amounts, dates),
true,
"JPY");
1581 FxDoubleTouchOption knockOutOption(env, optionData, knonkOutData,
"EUR",
"JPY",
"JPY", f.cash);
1582 FxDoubleTouchOption knockInOption(env, optionData, knonkInData,
"EUR",
"JPY",
"JPY", f.cash);
1585 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1586 engineData->model(
"FxDoubleTouchOption") =
"GarmanKohlhagen";
1587 engineData->engine(
"FxDoubleTouchOption") =
"AnalyticDoubleBarrierBinaryEngine";
1588 engineData->model(
"Swap") =
"DiscountedCashflows";
1589 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1591 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1593 swap.build(engineFactory);
1594 knockOutOption.build(engineFactory);
1595 knockInOption.
build(engineFactory);
1597 Real npv = swap.instrument()->NPV();
1600 BOOST_CHECK_CLOSE(npv, knockOutOption.instrument()->NPV() + knockInOption.
instrument()->NPV(), 0.01);
1602 Settings::instance().evaluationDate() = today;
1607 BOOST_TEST_MESSAGE(
"Testing FXDoubleTouchOption when barrier already touched...");
1609 struct DoubleTouchOptionTouchedData {
1626 DoubleTouchOptionTouchedData fxdt[] = {
1628 {
"KnockIn", 80.0, 120.0, 1e6, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1629 {
"KnockIn", 80.0, 120.0, 1e6, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1630 {
"KnockOut", 80.0, 120.0, 1e6, 80.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1631 {
"KnockOut", 80.0, 120.0, 1e6, 70.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1633 {
"KnockIn", 80.0, 120.0, 1e6, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1634 {
"KnockIn", 80.0, 120.0, 1e6, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1635 {
"KnockOut", 80.0, 120.0, 1e6, 120.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1636 {
"KnockOut", 80.0, 120.0, 1e6, 130.0, 100.0, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1638 {
"KnockIn", 80.0, 120.0, 1e6, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1639 {
"KnockIn", 80.0, 120.0, 1e6, 100.0, 70.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1640 {
"KnockIn", 80.0, 120.0, 1e6, 70.0, 70.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1641 {
"KnockOut", 80.0, 120.0, 1e6, 100.0, 100.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1642 {
"KnockOut", 80.0, 120.0, 1e6, 100.0, 70.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1643 {
"KnockOut", 80.0, 120.0, 1e6, 70.0, 70.0, 70.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1645 {
"KnockIn", 80.0, 120.0, 1e6, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1646 {
"KnockIn", 80.0, 120.0, 1e6, 100.0, 120.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1647 {
"KnockIn", 80.0, 120.0, 1e6, 120.0, 120.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1648 {
"KnockOut", 80.0, 120.0, 1e6, 100.0, 100.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1649 {
"KnockOut", 80.0, 120.0, 1e6, 100.0, 120.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1650 {
"KnockOut", 80.0, 120.0, 1e6, 120.0, 120.0, 120.0, 0.04, 0.08, 0.50, 0.25, 0.0}};
1652 vector<string> payoutCcys = {
"EUR",
"JPY"};
1653 vector<string> fxIndices = {
"FX-Reuters-EUR-JPY",
"FX-Reuters-JPY-EUR"};
1654 for (
auto& f : fxdt) {
1656 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
1657 Date today = Settings::instance().evaluationDate();
1658 Settings::instance().evaluationDate() = market->asofDate();
1659 TimeSeries<Real> pastFixings;
1660 pastFixings[market->asofDate() - 1 * Days] = f.s_1;
1661 pastFixings[market->asofDate() - 2 * Days] = f.s_2;
1662 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
1663 TimeSeries<Real> pastFixingsInverted;
1664 pastFixingsInverted[market->asofDate() - 1 * Days] = 1 / pastFixings[market->asofDate() - 1 * Days];
1665 pastFixingsInverted[market->asofDate() - 2 * Days] = 1 / pastFixings[market->asofDate() - 2 * Days];
1666 IndexManager::instance().setHistory(
"Reuters JPY/EUR", pastFixingsInverted);
1668 for (
auto& payoutCcy : payoutCcys) {
1669 for (
auto& fxIndex : fxIndices) {
1671 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1673 vector<Real> barriers = {f.barrierLow, f.barrierHigh};
1674 vector<TradeBarrier> tradeBarriers;
1675 tradeBarriers.push_back(
TradeBarrier(f.barrierLow,
""));
1676 tradeBarriers.push_back(
TradeBarrier(f.barrierHigh,
""));
1677 BarrierData barrierData(f.barrierType, barriers, 0.0, tradeBarriers);
1681 vector<double> amounts = {f.cash};
1682 vector<string> dates = {
"2016-08-01"};
1684 LegData legData(QuantLib::ext::make_shared<CashflowData>(amounts, dates),
true, payoutCcy);
1687 FxDoubleTouchOption doubleTouchOption(env, optionData, barrierData,
"EUR",
"JPY", payoutCcy, f.cash,
1688 "20160201",
"TARGET", fxIndex);
1691 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1692 engineData->model(
"FxDoubleTouchOption") =
"GarmanKohlhagen";
1693 engineData->engine(
"FxDoubleTouchOption") =
"AnalyticDoubleBarrierBinaryEngine";
1694 engineData->model(
"Swap") =
"DiscountedCashflows";
1695 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1697 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1699 doubleTouchOption.build(engineFactory);
1700 swap.build(engineFactory);
1703 if (f.barrierType ==
"KnockIn")
1704 BOOST_CHECK_CLOSE(doubleTouchOption.instrument()->NPV(), swap.instrument()->NPV(), 0.01);
1706 BOOST_CHECK_CLOSE(doubleTouchOption.instrument()->NPV(), 0.0, 0.01);
1709 Settings::instance().evaluationDate() = today;
1710 IndexManager::instance().clearHistories();
1715 BOOST_TEST_MESSAGE(
"Testing FXEuropeanBarrierOption Symmetry...");
1719 BarrierOptionData fxb[] = {
1721 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1722 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1723 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1724 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1725 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1726 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1727 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1728 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1729 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1730 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1731 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1732 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1735 for (
auto& f : fxb) {
1737 QuantLib::ext::shared_ptr<Market> marketCall = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1738 QuantLib::ext::shared_ptr<Market> marketPut = QuantLib::ext::make_shared<TestMarket>(f.k, f.r, f.q, f.v);
1739 Date today = Settings::instance().evaluationDate();
1740 Settings::instance().evaluationDate() = marketCall->asofDate();
1743 OptionData optionCallData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1744 OptionData optionPutData(
"Long",
"Put",
"European",
true, vector<string>(1,
"20160801"));
1745 vector<Real> barriersCall = {f.barrier};
1746 vector<TradeBarrier> tradeBarriers_call;
1747 tradeBarriers_call.push_back(
TradeBarrier(f.barrier,
""));
1748 vector<Real> barriersPut = {f.s * f.k / f.barrier};
1749 vector<TradeBarrier> tradeBarriers_put;
1750 tradeBarriers_put.push_back(
TradeBarrier(f.s * f.k / f.barrier,
""));
1751 BarrierData barrierCallData(
"DownAndIn", barriersCall, f.rebate, tradeBarriers_call);
1752 BarrierData barrierPutData(
"UpAndIn", barriersPut, f.rebate, tradeBarriers_put);
1761 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1762 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
1763 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
1764 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1765 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1767 QuantLib::ext::shared_ptr<EngineFactory> engineFactoryCall = QuantLib::ext::make_shared<EngineFactory>(engineData, marketCall);
1768 QuantLib::ext::shared_ptr<EngineFactory> engineFactoryPut = QuantLib::ext::make_shared<EngineFactory>(engineData, marketPut);
1770 fxCallOption.
build(engineFactoryCall);
1771 fxPutOption.
build(engineFactoryPut);
1773 Real npvCall = fxCallOption.
instrument()->NPV();
1774 Real npvPut = fxPutOption.
instrument()->NPV();
1776 BOOST_TEST_MESSAGE(
"NPV Currency " << fxCallOption.
npvCurrency());
1777 BOOST_TEST_MESSAGE(
"FX Barrier Option, NPV Call " << npvCall);
1778 BOOST_TEST_MESSAGE(
"FX Barrier Option, NPV Put " << npvPut);
1780 BOOST_TEST(npvCall >= 0);
1781 BOOST_TEST(npvPut >= 0);
1782 BOOST_CHECK_CLOSE(npvCall, npvPut, 0.01);
1784 Settings::instance().evaluationDate() = today;
1789 BOOST_TEST_MESSAGE(
"Testing FXEuropeanBarrierOption Parity...");
1793 BarrierOptionData fxb[] = {
1795 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1796 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1797 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1798 {
"", 100.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1799 {
"", 100.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1800 {
"", 100.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.25, 0.0},
1801 {
"", 95.0, 0.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1802 {
"", 95.0, 0.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1803 {
"", 95.0, 0.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1804 {
"", 100.0, 3.0,
"", 90, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1805 {
"", 100.0, 3.0,
"", 100, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1806 {
"", 100.0, 3.0,
"", 110, 100.0, 0.04, 0.08, 0.50, 0.30, 0.0},
1810 for (
auto& f : fxb) {
1813 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v);
1814 Date today = Settings::instance().evaluationDate();
1815 Settings::instance().evaluationDate() = market->asofDate();
1818 OptionData optionData(
"Long", optionType,
"European",
true, vector<string>(1,
"20160801"));
1820 vector<Real> barriers = {f.barrier};
1821 vector<TradeBarrier> tradeBarriers;
1824 BarrierData downInData(
"DownAndIn", barriers, f.rebate, tradeBarriers);
1825 BarrierData upInData(
"UpAndIn", barriers, f.rebate, tradeBarriers);
1826 BarrierData downOutData(
"DownAndOut", barriers, f.rebate, tradeBarriers);
1827 BarrierData upOutData(
"UpAndOut", barriers, f.rebate, tradeBarriers);
1831 FxOption fxOption(env, optionData,
"EUR", 1,
1843 vector<double> amounts = {f.rebate};
1844 vector<string> dates = {
"2016-08-01"};
1845 LegData legData(QuantLib::ext::make_shared<CashflowData>(amounts, dates),
false,
"JPY");
1849 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1850 engineData->model(
"FxDigitalOption") =
"GarmanKohlhagen";
1851 engineData->engine(
"FxDigitalOption") =
"AnalyticEuropeanEngine";
1852 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1853 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1854 engineData->model(
"Swap") =
"DiscountedCashflows";
1855 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
1857 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1859 fxOption.
build(engineFactory);
1860 downInOption.
build(engineFactory);
1861 upInOption.
build(engineFactory);
1862 downOutOption.
build(engineFactory);
1863 upOutOption.
build(engineFactory);
1864 swap.build(engineFactory);
1866 Real npv = fxOption.
instrument()->NPV() + swap.instrument()->NPV();
1869 BOOST_TEST(downInOption.
instrument()->NPV() >= 0);
1870 BOOST_TEST(downOutOption.
instrument()->NPV() >= 0);
1871 BOOST_TEST(upInOption.
instrument()->NPV() >= 0);
1872 BOOST_TEST(upOutOption.
instrument()->NPV() >= 0);
1873 BOOST_CHECK_CLOSE(npv, downInOption.
instrument()->NPV() + downOutOption.
instrument()->NPV(), 0.01);
1874 BOOST_CHECK_CLOSE(npv, upInOption.
instrument()->NPV() + upOutOption.
instrument()->NPV(), 0.01);
1876 Settings::instance().evaluationDate() = today;
1882 BOOST_TEST_MESSAGE(
"Testing FXDoubleBarrierOption when barrier already touched...");
1884 struct KIKOBarrierOptionData {
1886 string knockOutType;
1887 Real barrierKnockIn;
1888 Real barrierKnockOut;
1899 KIKOBarrierOptionData fxdb[] = {
1902 {
"DownAndIn",
"UpAndOut", 80.0, 120.0, 0.0,
"Call", 100.0, 100.0, 0.04, 0.08, 0.50, 0.2},
1903 {
"UpAndIn",
"UpAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 80.0, 0.04, 0.08, 0.50, 0.2},
1904 {
"UpAndIn",
"DownAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 80.0, 0.04, 0.08, 0.50, 0.2},
1905 {
"DownAndIn",
"DownAndOut", 100.0, 80.0, 0.0,
"Call", 100.0, 120.0, 0.04, 0.08, 0.50, 0.2}};
1908 for (
auto& f : fxdb) {
1910 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
1911 Date today = Settings::instance().evaluationDate();
1912 Settings::instance().evaluationDate() = today;
1913 Settings::instance().evaluationDate() = market->asofDate();
1916 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1917 vector<TradeBarrier> tradeBarriers_KI;
1918 tradeBarriers_KI.push_back(
TradeBarrier(f.barrierKnockIn,
""));
1919 vector<TradeBarrier> tradeBarriers_KO;
1920 tradeBarriers_KO.push_back(
TradeBarrier(f.barrierKnockOut,
""));
1921 BarrierData knockInBarrierData(f.knockInType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
1922 BarrierData knockOutBarrierData(f.knockOutType, {f.barrierKnockOut}, 0.0, tradeBarriers_KO);
1924 vector<BarrierData> barriers = {knockInBarrierData, knockOutBarrierData};
1927 FxKIKOBarrierOption kikoBarrierOption(env, optionData, barriers,
"EUR", 1,
"JPY", f.k,
"20160201",
"TARGET",
1928 "FX-Reuters-EUR-JPY");
1929 FxBarrierOption koBarrierOption(env, optionData, knockOutBarrierData, Date(1, Month::February, 2016),
"TARGET",
"EUR", 1,
1930 "JPY", f.k,
"FX-Reuters-EUR-JPY");
1932 FxOption fxOption(env, optionData,
"EUR", 1,
1936 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
1937 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
1938 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
1939 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
1940 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
1941 engineData->model(
"FxOption") =
"GarmanKohlhagen";
1942 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
1944 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
1947 TimeSeries<Real> pastFixings;
1948 pastFixings[market->asofDate() - 1 * Days] = f.barrierKnockIn;
1949 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
1951 kikoBarrierOption.
reset();
1952 kikoBarrierOption.
build(engineFactory);
1953 koBarrierOption.
build(engineFactory);
1954 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), koBarrierOption.
instrument()->NPV(), 0.01);
1956 IndexManager::instance().clearHistories();
1957 TimeSeries<Real> pastFixings2;
1958 pastFixings2[market->asofDate() - 1 * Days] = f.barrierKnockIn;
1959 pastFixings2[market->asofDate() - 2 * Days] = f.barrierKnockOut;
1960 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings2);
1961 kikoBarrierOption.
reset();
1962 kikoBarrierOption.
build(engineFactory);
1964 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), 0.0, 0.01);
1966 IndexManager::instance().clearHistories();
1969 KIKOBarrierOptionData fxdb3[] = {
1972 {
"DownAndIn",
"UpAndOut", 80.0, 120.0, 0.0,
"Call", 100.0, 79.0, 0.04, 0.08, 0.50, 0.2},
1973 {
"UpAndIn",
"UpAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 101.0, 0.04, 0.08, 0.50, 0.2},
1974 {
"UpAndIn",
"DownAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 101.0, 0.04, 0.08, 0.50, 0.2},
1975 {
"DownAndIn",
"DownAndOut", 100.0, 80.0, 0.0,
"Call", 100.0, 99.0, 0.04, 0.08, 0.50, 0.2}};
1978 for (
auto& f : fxdb3) {
1980 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
1981 Date today = Settings::instance().evaluationDate();
1982 Settings::instance().evaluationDate() = today;
1983 Settings::instance().evaluationDate() = market->asofDate();
1986 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
1987 vector<TradeBarrier> tradeBarriers_KI;
1988 tradeBarriers_KI.push_back(
TradeBarrier(f.barrierKnockIn,
""));
1989 vector<TradeBarrier> tradeBarriers_KO;
1990 tradeBarriers_KO.push_back(
TradeBarrier(f.barrierKnockOut,
""));
1991 BarrierData knockInBarrierData(f.knockInType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
1992 BarrierData knockOutBarrierData(f.knockOutType, {f.barrierKnockOut}, 0.0, tradeBarriers_KO);
1994 vector<BarrierData> barriers = {knockInBarrierData, knockOutBarrierData};
1997 FxKIKOBarrierOption kikoBarrierOption(env, optionData, barriers,
"EUR", 1,
"JPY", f.k,
"20160201",
"TARGET",
1998 "FX-Reuters-EUR-JPY");
1999 FxBarrierOption koBarrierOption(env, optionData, knockOutBarrierData, Date(1, Month::February, 2016),
"TARGET",
2000 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2002 FxOption fxOption(env, optionData,
"EUR", 1,
2006 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
2007 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
2008 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
2009 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
2010 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
2011 engineData->model(
"FxOption") =
"GarmanKohlhagen";
2012 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
2014 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
2016 kikoBarrierOption.
build(engineFactory);
2017 koBarrierOption.
build(engineFactory);
2018 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), koBarrierOption.
instrument()->NPV(), 0.01);
2021 KIKOBarrierOptionData fxdb4[] = {
2024 {
"DownAndIn",
"UpAndOut", 80.0, 120.0, 0.0,
"Call", 120.0, 121.0, 0.04, 0.08, 0.50, 0.2},
2025 {
"UpAndIn",
"UpAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 121.0, 0.04, 0.08, 0.50, 0.2},
2026 {
"UpAndIn",
"DownAndOut", 100.0, 120.0, 0.0,
"Call", 100.0, 119.0, 0.04, 0.08, 0.50, 0.2},
2027 {
"DownAndIn",
"DownAndOut", 100.0, 80.0, 0.0,
"Call", 100.0, 79.0, 0.04, 0.08, 0.50, 0.2}};
2030 for (
auto& f : fxdb4) {
2032 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
2033 Date today = Settings::instance().evaluationDate();
2034 Settings::instance().evaluationDate() = today;
2035 Settings::instance().evaluationDate() = market->asofDate();
2038 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
2039 vector<TradeBarrier> tradeBarriers_KI;
2040 tradeBarriers_KI.push_back(
TradeBarrier(f.barrierKnockIn,
""));
2041 vector<TradeBarrier> tradeBarriers_KO;
2042 tradeBarriers_KO.push_back(
TradeBarrier(f.barrierKnockOut,
""));
2043 BarrierData knockInBarrierData(f.knockInType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
2044 BarrierData knockOutBarrierData(f.knockOutType, {f.barrierKnockOut}, 0.0, tradeBarriers_KO);
2046 vector<BarrierData> barriers = {knockInBarrierData, knockOutBarrierData};
2049 FxKIKOBarrierOption kikoBarrierOption(env, optionData, barriers,
"EUR", 1,
"JPY", f.k,
"20160201",
"TARGET",
2050 "FX-Reuters-EUR-JPY");
2051 FxBarrierOption koBarrierOption(env, optionData, knockOutBarrierData, Date(1, Month::February, 2016),
"TARGET",
2052 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2054 FxOption fxOption(env, optionData,
"EUR", 1,
2058 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
2059 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
2060 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
2061 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
2062 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
2063 engineData->model(
"FxOption") =
"GarmanKohlhagen";
2064 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
2066 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
2069 kikoBarrierOption.
build(engineFactory);
2071 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), 0.0, 0.01);
2076 KIKOBarrierOptionData fxdb2[] = {
2079 {
"DownAndIn",
"UpAndOut", 80.0, 1000000.0, 0.0,
"Call", 100.0, 100.0, 0.04, 0.08, 0.50, 0.2},
2080 {
"UpAndIn",
"UpAndOut", 150.0, 1000000.0, 0.0,
"Call", 100.0, 80.0, 0.04, 0.08, 0.50, 0.2},
2081 {
"UpAndIn",
"DownAndOut", 150.0, 0.000001, 0.0,
"Call", 100.0, 80.0, 0.04, 0.08, 0.50, 0.2},
2082 {
"DownAndIn",
"DownAndOut", 100.0, 0.000001, 0.0,
"Call", 100.0, 120.0, 0.04, 0.08, 0.50, 0.2}};
2084 for (
auto& f : fxdb2) {
2085 BOOST_TEST_MESSAGE(
"testing " << f.knockInType <<
" " << f.knockOutType);
2087 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
2088 Date today = Settings::instance().evaluationDate();
2089 Settings::instance().evaluationDate() = today;
2090 Settings::instance().evaluationDate() = market->asofDate();
2093 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
2094 vector<TradeBarrier> tradeBarriers_KI;
2095 tradeBarriers_KI.push_back(
TradeBarrier(f.barrierKnockIn,
""));
2096 vector<TradeBarrier> tradeBarriers_KO;
2097 tradeBarriers_KO.push_back(
TradeBarrier(f.barrierKnockOut,
""));
2098 BarrierData knockInBarrierData(f.knockInType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
2099 BarrierData knockOutBarrierData(f.knockOutType, {f.barrierKnockOut}, 0.0, tradeBarriers_KO);
2100 BarrierData knockOutBarrierData2(f.knockOutType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
2102 vector<BarrierData> barriers = {knockInBarrierData, knockOutBarrierData};
2105 FxKIKOBarrierOption kikoBarrierOption(env, optionData, barriers,
"EUR", 1,
"JPY", f.k,
"20160201",
"TARGET",
2106 "FX-Reuters-EUR-JPY");
2107 FxBarrierOption kiBarrierOption(env, optionData, knockInBarrierData, Date(1, Month::February, 2016),
"TARGET",
2108 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2109 FxBarrierOption koBarrierOption(env, optionData, knockOutBarrierData, Date(1, Month::February, 2016),
"TARGET",
2110 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2111 FxBarrierOption koBarrierOption2(env, optionData, knockOutBarrierData2, Date(1, Month::February, 2016),
2112 "TARGET",
"EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2114 vector<Real> barrier = {std::min(f.barrierKnockIn, f.barrierKnockOut),
2115 std::max(f.barrierKnockIn, f.barrierKnockOut)};
2116 vector<TradeBarrier> tradeBarriers = {
TradeBarrier(std::min(f.barrierKnockIn, f.barrierKnockOut),
""),
2117 TradeBarrier(std::max(f.barrierKnockIn, f.barrierKnockOut),
"")};
2118 BarrierData barrierData(
"KnockOut", barrier, 0, tradeBarriers);
2123 FxOption fxOption(env, optionData,
"EUR", 1,
2127 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
2128 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
2129 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
2130 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
2131 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
2132 engineData->model(
"FxOption") =
"GarmanKohlhagen";
2133 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
2135 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
2137 TimeSeries<Real> pastFixings;
2138 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
2140 kikoBarrierOption.
build(engineFactory);
2141 kiBarrierOption.
build(engineFactory);
2142 koBarrierOption.
build(engineFactory);
2143 koBarrierOption2.
build(engineFactory);
2144 dkoBarrierOption.
build(engineFactory);
2145 fxOption.
build(engineFactory);
2147 BOOST_TEST_MESSAGE(
"KIKO NPV: " << kikoBarrierOption.
instrument()->NPV());
2148 BOOST_TEST_MESSAGE(
"KI NPV: " << kiBarrierOption.
instrument()->NPV());
2149 BOOST_TEST_MESSAGE(
"KO(knockoutLevel) NPV: " << koBarrierOption.
instrument()->NPV());
2150 BOOST_TEST_MESSAGE(
"KO(knockinLevel) NPV: " << koBarrierOption2.
instrument()->NPV());
2151 BOOST_TEST_MESSAGE(
"DoubleKnockOut NPV: " << dkoBarrierOption.
instrument()->NPV());
2152 BOOST_TEST_MESSAGE(
"FXOption NPV: " << fxOption.
instrument()->NPV());
2154 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), kiBarrierOption.
instrument()->NPV(), 0.01);
2157 pastFixings[market->asofDate() - 1 * Days] = f.barrierKnockIn;
2158 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
2160 kikoBarrierOption.
reset();
2161 kiBarrierOption.
reset();
2162 dkoBarrierOption.
reset();
2163 kikoBarrierOption.
build(engineFactory);
2164 kiBarrierOption.
build(engineFactory);
2165 fxOption.
build(engineFactory);
2167 kikoBarrierOption.
build(engineFactory);
2168 kiBarrierOption.
build(engineFactory);
2169 koBarrierOption.
build(engineFactory);
2170 dkoBarrierOption.
build(engineFactory);
2171 fxOption.
build(engineFactory);
2173 BOOST_TEST_MESSAGE(
"KIKO NPV: " << kikoBarrierOption.
instrument()->NPV());
2174 BOOST_TEST_MESSAGE(
"KI NPV: " << kiBarrierOption.
instrument()->NPV());
2175 BOOST_TEST_MESSAGE(
"KO(knockoutLevel) NPV: " << koBarrierOption.
instrument()->NPV());
2176 BOOST_TEST_MESSAGE(
"KO(knockinLevel) NPV: " << koBarrierOption2.
instrument()->NPV());
2177 BOOST_TEST_MESSAGE(
"DoubleKnockOut NPV: " << dkoBarrierOption.
instrument()->NPV());
2178 BOOST_TEST_MESSAGE(
"FXOption NPV: " << fxOption.
instrument()->NPV());
2181 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), kiBarrierOption.
instrument()->NPV(), 0.01);
2183 IndexManager::instance().clearHistories();
2188 KIKOBarrierOptionData fxdb5[] = {
2191 {
"UpAndIn",
"UpAndOut", 80.0, 150.0, 0.0,
"Call", 100.0, 70.0, 0.04, 0.08, 0.50, 0.2},
2192 {
"DownAndIn",
"DownAndOut", 150.0, 80, 0.0,
"Call", 100.0, 160.0, 0.04, 0.08, 0.50, 0.2}};
2194 for (
auto& f : fxdb5) {
2195 BOOST_TEST_MESSAGE(
"testing " << f.knockInType <<
" " << f.knockOutType);
2197 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(f.s, f.q, f.r, f.v,
true);
2198 Date today = Settings::instance().evaluationDate();
2199 Settings::instance().evaluationDate() = today;
2200 Settings::instance().evaluationDate() = market->asofDate();
2203 OptionData optionData(
"Long",
"Call",
"European",
true, vector<string>(1,
"20160801"));
2204 vector<TradeBarrier> tradeBarriers_KI = {
TradeBarrier(f.barrierKnockIn,
"")};
2205 vector<TradeBarrier> tradeBarriers_KO = {
TradeBarrier(f.barrierKnockOut,
"")};
2206 BarrierData knockInBarrierData(f.knockInType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
2207 BarrierData knockOutBarrierData(f.knockOutType, {f.barrierKnockOut}, 0.0, tradeBarriers_KO);
2208 BarrierData knockOutBarrierData2(f.knockOutType, {f.barrierKnockIn}, 0.0, tradeBarriers_KI);
2210 vector<BarrierData> barriers = {knockInBarrierData, knockOutBarrierData};
2213 FxKIKOBarrierOption kikoBarrierOption(env, optionData, barriers,
"EUR", 1,
"JPY", f.k,
"20160201",
"TARGET",
2214 "FX-Reuters-EUR-JPY");
2215 FxBarrierOption kiBarrierOption(env, optionData, knockInBarrierData, Date(1, Month::February, 2016),
"TARGET",
2216 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2217 FxBarrierOption koBarrierOption(env, optionData, knockOutBarrierData, Date(1, Month::February, 2016),
"TARGET",
2218 "EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2219 FxBarrierOption koBarrierOption2(env, optionData, knockOutBarrierData2, Date(1, Month::February, 2016),
2220 "TARGET",
"EUR", 1,
"JPY", f.k,
"FX-Reuters-EUR-JPY");
2222 vector<Real> barrier = {std::min(f.barrierKnockIn, f.barrierKnockOut),
2223 std::max(f.barrierKnockIn, f.barrierKnockOut)};
2224 vector<TradeBarrier> tradeBarriers = {
TradeBarrier(std::min(f.barrierKnockIn, f.barrierKnockOut),
""),
2225 TradeBarrier(std::max(f.barrierKnockIn, f.barrierKnockOut),
"")};
2226 BarrierData barrierData(
"KnockOut", barrier, 0, tradeBarriers);
2232 FxOption fxOption(env, optionData,
"EUR", 1,
2236 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
2237 engineData->model(
"FxDoubleBarrierOption") =
"GarmanKohlhagen";
2238 engineData->engine(
"FxDoubleBarrierOption") =
"AnalyticDoubleBarrierEngine";
2239 engineData->model(
"FxBarrierOption") =
"GarmanKohlhagen";
2240 engineData->engine(
"FxBarrierOption") =
"AnalyticBarrierEngine";
2241 engineData->model(
"FxOption") =
"GarmanKohlhagen";
2242 engineData->engine(
"FxOption") =
"AnalyticEuropeanEngine";
2244 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
2246 TimeSeries<Real> pastFixings;
2247 IndexManager::instance().setHistory(
"Reuters EUR/JPY", pastFixings);
2249 kikoBarrierOption.
build(engineFactory);
2250 kiBarrierOption.
build(engineFactory);
2251 koBarrierOption.
build(engineFactory);
2252 koBarrierOption2.
build(engineFactory);
2253 dkoBarrierOption.
build(engineFactory);
2254 fxOption.
build(engineFactory);
2256 BOOST_TEST_MESSAGE(
"KIKO NPV: " << kikoBarrierOption.
instrument()->NPV());
2257 BOOST_TEST_MESSAGE(
"KI NPV: " << kiBarrierOption.
instrument()->NPV());
2258 BOOST_TEST_MESSAGE(
"KO(knockoutLevel) NPV: " << koBarrierOption.
instrument()->NPV());
2259 BOOST_TEST_MESSAGE(
"KO(knockinLevel) NPV: " << koBarrierOption2.
instrument()->NPV());
2260 BOOST_TEST_MESSAGE(
"DoubleKnockOut NPV: " << dkoBarrierOption.
instrument()->NPV());
2261 BOOST_TEST_MESSAGE(
"FXOption NPV: " << fxOption.
instrument()->NPV());
2264 dynamic_pointer_cast<TestMarket>(market)->setFxSpot(
"EURJPY", f.barrierKnockIn);
2265 BOOST_CHECK_CLOSE(kikoBarrierOption.
instrument()->NPV(), koBarrierOption.
instrument()->NPV(), 0.01);
2268 dynamic_pointer_cast<TestMarket>(market)->setFxSpot(
"EURJPY", f.barrierKnockOut);
2269 BOOST_CHECK_SMALL(kikoBarrierOption.
instrument()->NPV(), 0.0001);
2271 IndexManager::instance().clearHistories();
2276BOOST_AUTO_TEST_SUITE_END()
2278BOOST_AUTO_TEST_SUITE_END()
Engine builder for FX Forwards.
Engine builder for FX Options.
Engine builder for Swaps.
Serializable obejct holding barrier data.
Serializable object holding generic trade data, reporting dimensions.
Serializable FX Barrier Option.
Serializable FX Digital Barrier Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Serializable FX Digital Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Serializable FX Double Barrier Option.
Serializable FX Double One-Touch/No-Touch Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Serializable FX European Barrier Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Serializable FX KIKO Barrier Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
void build(const QuantLib::ext::shared_ptr< ore::data::EngineFactory > &ef) override
Serializable FX One-Touch/No-Touch Option.
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Build QuantLib/QuantExt instrument, link pricing engine.
Serializable object holding leg data.
static const string defaultConfiguration
Default configuration label.
map< pair< string, string >, Handle< BlackVolTermStructure > > fxVols_
QuantLib::ext::shared_ptr< FXTriangulation > fx_
map< tuple< string, YieldCurveType, string >, Handle< YieldTermStructure > > yieldCurves_
Serializable object holding option data.
Serializable Swap, Single and Cross Currency.
const QuantLib::ext::shared_ptr< InstrumentWrapper > & instrument() const
const string & npvCurrency() const
void reset()
Reset trade, clear all base class data. This does not reset accumulated timings for this trade.
A class to hold pricing engine parameters.
FX Barrier Option data model and serialization.
FX Digital Option data model and serialization.
FX Double Barrier Option data model and serialization.
FX Double One-Touch/No-Touch Option data model and serialization.
FX European Barrier Option data model and serialization.
BOOST_AUTO_TEST_CASE(testFXDigitalOptionPrice)
FX Forward data model and serialization.
FX Option data model and serialization.
FX One-Touch/No-Touch Option data model and serialization.
An implementation of the Market class that stores the required objects in maps.
std::string to_string(const LocationInfo &l)
Swap trade data model and serialization.
vector< Option::Type > optionTypes