1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2010 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 "chooseroption.hpp"
21#include "utilities.hpp"
22#include <ql/time/daycounters/actual360.hpp>
23#include <ql/instruments/simplechooseroption.hpp>
24#include <ql/instruments/complexchooseroption.hpp>
25#include <ql/pricingengines/exotic/analyticsimplechooserengine.hpp>
26#include <ql/pricingengines/exotic/analyticcomplexchooserengine.hpp>
27#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
28#include <ql/utilities/dataformatters.hpp>
29
30using namespace QuantLib;
31using namespace boost::unit_test_framework;
32
33#undef REPORT_FAILURE
34#define REPORT_FAILURE(greekName, choosingDate, \
35 exercise, s, q, r, today, v, \
36 expected, calculated, tolerance) \
37 BOOST_ERROR( \
38 exerciseTypeToString(exercise) \
39 << " Chooser option with " \
40 << " spot value: " << s << "\n" \
41 << " dividend yield: " << io::rate(q) << "\n" \
42 << " risk-free rate: " << io::rate(r) << "\n" \
43 << " reference date: " << today << "\n" \
44 << " maturity: " << exercise->lastDate() << "\n" \
45 << " volatility: " << io::volatility(v) << "\n\n" \
46 << " expected " << greekName << ": " << expected << "\n" \
47 << " calculated " << greekName << ": " << calculated << "\n"\
48 << " error: " << std::fabs(expected-calculated) \
49 << "\n" \
50 << " tolerance: " << tolerance);
51
52
53void ChooserOptionTest::testAnalyticSimpleChooserEngine(){
54
55 BOOST_TEST_MESSAGE("Testing analytic simple chooser option...");
56
57 /* The data below are from
58 "Complete Guide to Option Pricing Formulas", Espen Gaarder Haug
59 pages 39-40
60 */
61 DayCounter dc = Actual360();
62 Date today = Settings::instance().evaluationDate();
63
64 ext::shared_ptr<SimpleQuote> spot = ext::make_shared<SimpleQuote>(args: 50.0);
65 ext::shared_ptr<SimpleQuote> qRate = ext::make_shared<SimpleQuote>(args: 0.0);
66 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
67 ext::shared_ptr<SimpleQuote> rRate = ext::make_shared<SimpleQuote>(args: 0.08);
68 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
69 ext::shared_ptr<SimpleQuote> vol = ext::make_shared<SimpleQuote>(args: 0.25);
70 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
71
72 ext::shared_ptr<BlackScholesMertonProcess> stochProcess =
73 ext::make_shared<BlackScholesMertonProcess>(
74 args: Handle<Quote>(spot),
75 args: Handle<YieldTermStructure>(qTS),
76 args: Handle<YieldTermStructure>(rTS),
77 args: Handle<BlackVolTermStructure>(volTS));
78
79 ext::shared_ptr<PricingEngine> engine =
80 ext::make_shared<AnalyticSimpleChooserEngine>(args&: stochProcess);
81
82 Real strike = 50.0;
83
84 Date exerciseDate = today + 180;
85 ext::shared_ptr<Exercise> exercise =
86 ext::make_shared<EuropeanExercise>(args&: exerciseDate);
87
88 Date choosingDate = today + 90;
89 SimpleChooserOption option(choosingDate,strike,exercise);
90 option.setPricingEngine(engine);
91
92 Real calculated = option.NPV();
93 Real expected = 6.1071;
94 Real tolerance = 3e-5;
95 if (std::fabs(x: calculated-expected) > tolerance) {
96 REPORT_FAILURE("value", choosingDate,
97 exercise, spot->value(),
98 qRate->value(), rRate->value(), today,
99 vol->value(), expected, calculated, tolerance);
100 }
101
102}
103
104
105void ChooserOptionTest::testAnalyticComplexChooserEngine(){
106 BOOST_TEST_MESSAGE("Testing analytic complex chooser option...");
107
108 /* The example below is from
109 "Complete Guide to Option Pricing Formulas", Espen Gaarder Haug
110 */
111 DayCounter dc = Actual360();
112 Date today = Date::todaysDate();
113
114 ext::shared_ptr<SimpleQuote> spot = ext::make_shared<SimpleQuote>(args: 50.0);
115 ext::shared_ptr<SimpleQuote> qRate = ext::make_shared<SimpleQuote>(args: 0.05);
116 ext::shared_ptr<YieldTermStructure> qTS = flatRate(today, forward: qRate, dc);
117 ext::shared_ptr<SimpleQuote> rRate = ext::make_shared<SimpleQuote>(args: 0.10);
118 ext::shared_ptr<YieldTermStructure> rTS = flatRate(today, forward: rRate, dc);
119 ext::shared_ptr<SimpleQuote> vol = ext::make_shared<SimpleQuote>(args: 0.35);
120 ext::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, volatility: vol, dc);
121
122 ext::shared_ptr<BlackScholesMertonProcess> stochProcess =
123 ext::make_shared<BlackScholesMertonProcess>(
124 args: Handle<Quote>(spot),
125 args: Handle<YieldTermStructure>(qTS),
126 args: Handle<YieldTermStructure>(rTS),
127 args: Handle<BlackVolTermStructure>(volTS));
128
129 ext::shared_ptr<PricingEngine> engine =
130 ext::make_shared<AnalyticComplexChooserEngine>(args&: stochProcess);
131
132 Real callStrike = 55.0;
133 Real putStrike = 48.0;
134
135 Date choosingDate = today + 90;
136 Date callExerciseDate = choosingDate + 180;
137 Date putExerciseDate = choosingDate + 210;
138 ext::shared_ptr<Exercise> callExercise =
139 ext::make_shared<EuropeanExercise>(args&: callExerciseDate);
140 ext::shared_ptr<Exercise> putExercise =
141 ext::make_shared<EuropeanExercise>(args&: putExerciseDate);
142
143 ComplexChooserOption option(choosingDate,callStrike,putStrike,
144 callExercise,putExercise);
145 option.setPricingEngine(engine);
146
147 Real calculated = option.NPV();
148 Real expected = 6.0508;
149 Real error = std::fabs(x: calculated-expected);
150 Real tolerance = 1e-4;
151 if (error > tolerance) {
152 BOOST_ERROR("Failed to reproduce complex chooser option value"
153 << "\n expected: " << expected
154 << "\n calculated: " << calculated
155 << "\n error: " << error);
156 }
157}
158
159test_suite* ChooserOptionTest::suite() {
160 auto* suite = BOOST_TEST_SUITE("Chooser option tests");
161
162 suite->add(QUANTLIB_TEST_CASE(
163 &ChooserOptionTest::testAnalyticSimpleChooserEngine));
164 suite->add(QUANTLIB_TEST_CASE(
165 &ChooserOptionTest::testAnalyticComplexChooserEngine));
166
167 return suite;
168}
169

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