[go: up one dir, main page]

1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2014 Master IMAFA - Polytech'Nice Sophia - Université de Nice Sophia Antipolis
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include "partialtimebarrieroption.hpp"
21#include "utilities.hpp"
22#include <ql/experimental/exoticoptions/partialtimebarrieroption.hpp>
23#include <ql/experimental/exoticoptions/analyticpartialtimebarrieroptionengine.hpp>
24#include <ql/quotes/simplequote.hpp>
25#include <ql/utilities/dataformatters.hpp>
26#include <ql/time/calendars/target.hpp>
27#include <ql/time/daycounters/actual360.hpp>
28
29using namespace QuantLib;
30using namespace boost::unit_test_framework;
31
32namespace partial_time_barrier_option_test {
33
34 struct TestCase {
35 Real underlying;
36 Real strike;
37 Integer days;
38 Real result;
39 };
40
41}
42
43void PartialTimeBarrierOptionTest::testAnalyticEngine() {
44 BOOST_TEST_MESSAGE(
45 "Testing analytic engine for partial-time barrier option...");
46
47 using namespace partial_time_barrier_option_test;
48
49 Date today = Settings::instance().evaluationDate();
50
51 Option::Type type = Option::Call;
52 DayCounter dc = Actual360();
53 Date maturity = today + 360;
54 ext::shared_ptr<Exercise> exercise =
55 ext::make_shared<EuropeanExercise>(args&: maturity);
56 Real barrier = 100.0;
57 Real rebate = 0.0;
58
59 ext::shared_ptr<SimpleQuote> spot = ext::make_shared<SimpleQuote>();
60 ext::shared_ptr<SimpleQuote> qRate = ext::make_shared<SimpleQuote>(args: 0.0);
61 ext::shared_ptr<SimpleQuote> rRate = ext::make_shared<SimpleQuote>(args: 0.1);
62 ext::shared_ptr<SimpleQuote> vol = ext::make_shared<SimpleQuote>(args: 0.25);
63
64 Handle<Quote> underlying(spot);
65 Handle<YieldTermStructure> dividendTS(flatRate(today, forward: qRate, dc));
66 Handle<YieldTermStructure> riskFreeTS(flatRate(today, forward: rRate, dc));
67 Handle<BlackVolTermStructure> blackVolTS(flatVol(today, volatility: vol, dc));
68
69 const ext::shared_ptr<BlackScholesMertonProcess> process =
70 ext::make_shared<BlackScholesMertonProcess>(args&: underlying,
71 args&: dividendTS,
72 args&: riskFreeTS,
73 args&: blackVolTS);
74 ext::shared_ptr<PricingEngine> engine =
75 ext::make_shared<AnalyticPartialTimeBarrierOptionEngine>(args: process);
76
77 TestCase cases[] = {
78 { .underlying: 95.0, .strike: 90.0, .days: 1, .result: 0.0393 },
79 { .underlying: 95.0, .strike: 110.0, .days: 1, .result: 0.0000 },
80 { .underlying: 105.0, .strike: 90.0, .days: 1, .result: 9.8751 },
81 { .underlying: 105.0, .strike: 110.0, .days: 1, .result: 6.2303 },
82
83 { .underlying: 95.0, .strike: 90.0, .days: 90, .result: 6.2747 },
84 { .underlying: 95.0, .strike: 110.0, .days: 90, .result: 3.7352 },
85 { .underlying: 105.0, .strike: 90.0, .days: 90, .result: 15.6324 },
86 { .underlying: 105.0, .strike: 110.0, .days: 90, .result: 9.6812 },
87
88 { .underlying: 95.0, .strike: 90.0, .days: 180, .result: 10.3345 },
89 { .underlying: 95.0, .strike: 110.0, .days: 180, .result: 5.8712 },
90 { .underlying: 105.0, .strike: 90.0, .days: 180, .result: 19.2896 },
91 { .underlying: 105.0, .strike: 110.0, .days: 180, .result: 11.6055 },
92
93 { .underlying: 95.0, .strike: 90.0, .days: 270, .result: 13.4342 },
94 { .underlying: 95.0, .strike: 110.0, .days: 270, .result: 7.1270 },
95 { .underlying: 105.0, .strike: 90.0, .days: 270, .result: 22.0753 },
96 { .underlying: 105.0, .strike: 110.0, .days: 270, .result: 12.7342 },
97
98 { .underlying: 95.0, .strike: 90.0, .days: 359, .result: 16.8576 },
99 { .underlying: 95.0, .strike: 110.0, .days: 359, .result: 7.5763 },
100 { .underlying: 105.0, .strike: 90.0, .days: 359, .result: 25.1488 },
101 { .underlying: 105.0, .strike: 110.0, .days: 359, .result: 13.1376 }
102 };
103
104 for (auto& i : cases) {
105 Date coverEventDate = today + i.days;
106 ext::shared_ptr<StrikedTypePayoff> payoff =
107 ext::make_shared<PlainVanillaPayoff>(args&: type, args&: i.strike);
108 PartialTimeBarrierOption option(PartialBarrier::DownOut,
109 PartialBarrier::EndB1,
110 barrier, rebate,
111 coverEventDate,
112 payoff, exercise);
113 option.setPricingEngine(engine);
114
115 spot->setValue(i.underlying);
116 Real calculated = option.NPV();
117 Real expected = i.result;
118 Real error = std::fabs(x: calculated-expected);
119 Real tolerance = 1e-4;
120 if (error > tolerance)
121 BOOST_ERROR("Failed to reproduce partial-time barrier option value"
122 << "\n expected: " << expected
123 << "\n calculated: " << calculated
124 << "\n error: " << error);
125 }
126}
127
128
129test_suite* PartialTimeBarrierOptionTest::suite() {
130 auto* suite = BOOST_TEST_SUITE("Partial-time barrier option tests");
131
132 suite->add(QUANTLIB_TEST_CASE(
133 &PartialTimeBarrierOptionTest::testAnalyticEngine));
134
135 return suite;
136}
137

source code of quantlib/test-suite/partialtimebarrieroption.cpp