1	/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2	
3	/*!
4	 Copyright (C) 2006, 2007 StatPro Italia srl
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	/*  This example showcases the CompositeInstrument class. Such class
21	    is used to build a static replication of a down-and-out barrier
22	    option, as outlined in Section 10.2 of Mark Joshi's "The Concepts
23	    and Practice of Mathematical Finance" to which we refer the
24	    reader.
25	*/
26	
27	#include <ql/qldefines.hpp>
28	#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
29	#  include <ql/auto_link.hpp>
30	#endif
31	#include <ql/instruments/compositeinstrument.hpp>
32	#include <ql/instruments/barrieroption.hpp>
33	#include <ql/instruments/europeanoption.hpp>
34	#include <ql/pricingengines/barrier/analyticbarrierengine.hpp>
35	#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
36	#include <ql/exercise.hpp>
37	#include <ql/termstructures/yield/flatforward.hpp>
38	#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
39	#include <ql/quotes/simplequote.hpp>
40	#include <ql/time/calendars/nullcalendar.hpp>
41	
42	#include <iostream>
43	#include <iomanip>
44	
45	using namespace QuantLib;
46	
47	int main(int, char* []) {
48	
49	    try {
50	
51	        std::cout << std::endl;
52	
53	        Date today(29, May, 2006);
54	        Settings::instance().evaluationDate() = today;
55	
56	        // the option to replicate
57	        Barrier::Type barrierType = Barrier::DownOut;
58	        Real barrier = 70.0;
59	        Real rebate = 0.0;
60	        Option::Type type = Option::Put;
61	        Real underlyingValue = 100.0;
62	        auto underlying = ext::make_shared<SimpleQuote>(underlyingValue);
63	        Real strike = 100.0;
64	        auto riskFreeRate = ext::make_shared<SimpleQuote>(0.04);
65	        auto volatility = ext::make_shared<SimpleQuote>(0.20);
66	        Date maturity = today + 1*Years;
67	
68	        std::cout << std::endl ;
69	
70	        // write column headings
71	        Size widths[] = { 45, 15, 15 };
72	        Size totalWidth = widths[0]+widths[1]+widths[2];
73	        std::string rule(totalWidth, '-'), dblrule(totalWidth, '=');
74	
75	        std::cout << dblrule << std::endl;
76	        std::cout << "Initial market conditions" << std::endl;
77	        std::cout << dblrule << std::endl;
78	        std::cout << std::setw(widths[0]) << std::left << "Option"
79	                  << std::setw(widths[1]) << std::left << "NPV"
80	                  << std::setw(widths[2]) << std::left << "Error"
81	                  << std::endl;
82	        std::cout << rule << std::endl;
83	
84	        // bootstrap the yield/vol curves
85	        DayCounter dayCounter = Actual365Fixed();
86	        Handle<Quote> h1(riskFreeRate);
87	        Handle<Quote> h2(volatility);
88	        Handle<YieldTermStructure> flatRate(
89	            ext::make_shared<FlatForward>(0, NullCalendar(), h1, dayCounter));
90	        Handle<BlackVolTermStructure> flatVol(
91	            ext::make_shared<BlackConstantVol>(0, NullCalendar(), h2, dayCounter));
92	
93	        // instantiate the option
94	        auto exercise = ext::make_shared<EuropeanExercise>(maturity);
95	        auto payoff = ext::make_shared<PlainVanillaPayoff>(type, strike);
96	
97	        auto bsProcess = ext::make_shared<BlackScholesProcess>(
98	            Handle<Quote>(underlying), flatRate, flatVol);
99	
100	        auto barrierEngine = ext::make_shared<AnalyticBarrierEngine>(bsProcess);
101	        auto europeanEngine = ext::make_shared<AnalyticEuropeanEngine>(bsProcess);
102	
103	        BarrierOption referenceOption(barrierType, barrier, rebate,
104	                                      payoff, exercise);
105	        referenceOption.setPricingEngine(barrierEngine);
106	
107	        Real referenceValue = referenceOption.NPV();
108	
109	        std::cout << std::setw(widths[0]) << std::left
110	                  << "Original barrier option"
111	                  << std::fixed
112	                  << std::setw(widths[1]) << std::left << referenceValue
113	                  << std::setw(widths[2]) << std::left << "N/A"
114	                  << std::endl;
115	
116	        // Replicating portfolios
117	        CompositeInstrument portfolio1, portfolio2, portfolio3;
118	
119	        // Final payoff first (the same for all portfolios):
120	        // as shown in Joshi, a put struck at K...
121	        auto put1 = ext::make_shared<EuropeanOption>(payoff, exercise);
122	        put1->setPricingEngine(europeanEngine);
123	        portfolio1.add(put1);
124	        portfolio2.add(put1);
125	        portfolio3.add(put1);
126	        // ...minus a digital put struck at B of notional K-B...
127	        auto digitalPayoff = ext::make_shared<CashOrNothingPayoff>(Option::Put, barrier, 1.0);
128	        auto digitalPut = ext::make_shared<EuropeanOption>(digitalPayoff, exercise);
129	        digitalPut->setPricingEngine(europeanEngine);
130	        portfolio1.subtract(digitalPut, strike-barrier);
131	        portfolio2.subtract(digitalPut, strike-barrier);
132	        portfolio3.subtract(digitalPut, strike-barrier);
133	        // ...minus a put option struck at B.
134	        auto lowerPayoff = ext::make_shared<PlainVanillaPayoff>(Option::Put, barrier);
135	        auto put2 = ext::make_shared<EuropeanOption>(lowerPayoff, exercise);
136	        put2->setPricingEngine(europeanEngine);
137	        portfolio1.subtract(put2);
138	        portfolio2.subtract(put2);
139	        portfolio3.subtract(put2);
140	
141	        // Now we use puts struck at B to kill the value of the
142	        // portfolio on a number of points (B,t).  For the first
143	        // portfolio, we'll use 12 dates at one-month's distance.
144	        Integer i;
145	        for (i=12; i>=1; i--) {
146	            // First, we instantiate the option...
147	            Date innerMaturity = today + i*Months;
148	            auto innerExercise = ext::make_shared<EuropeanExercise>(innerMaturity);
149	            auto innerPayoff = ext::make_shared<PlainVanillaPayoff>(Option::Put, barrier);
150	            auto putn = ext::make_shared<EuropeanOption>(innerPayoff, innerExercise);
151	            putn->setPricingEngine(europeanEngine);
152	            // ...second, we evaluate the current portfolio and the
153	            // latest put at (B,t)...
154	            Date killDate = today + (i-1)*Months;
155	            Settings::instance().evaluationDate() = killDate;
156	            underlying->setValue(barrier);
157	            Real portfolioValue = portfolio1.NPV();
158	            Real putValue = putn->NPV();
159	            // ...finally, we estimate the notional that kills the
160	            // portfolio value at that point...
161	            Real notional = portfolioValue/putValue;
162	            // ...and we subtract from the portfolio a put with such
163	            // notional.
164	            portfolio1.subtract(putn, notional);
165	        }
166	        // The portfolio being complete, we return to today's market...
167	        Settings::instance().evaluationDate() = today;
168	        underlying->setValue(underlyingValue);
169	        // ...and output the value.
170	        Real portfolioValue = portfolio1.NPV();
171	        Real error = portfolioValue - referenceValue;
172	        std::cout << std::setw(widths[0]) << std::left
173	                  << "Replicating portfolio (12 dates)"
174	                  << std::fixed
175	                  << std::setw(widths[1]) << std::left << portfolioValue
176	                  << std::setw(widths[2]) << std::left << error
177	                  << std::endl;
178	
179	        // For the second portfolio, we'll use 26 dates at two-weeks'
180	        // distance.
181	        for (i=52; i>=2; i-=2) {
182	            // Same as above.
183	            Date innerMaturity = today + i*Weeks;
184	            auto innerExercise = ext::make_shared<EuropeanExercise>(innerMaturity);
185	            auto innerPayoff = ext::make_shared<PlainVanillaPayoff>(Option::Put, barrier);
186	            auto putn = ext::make_shared<EuropeanOption>(innerPayoff, innerExercise);
187	            putn->setPricingEngine(europeanEngine);
188	            Date killDate = today + (i-2)*Weeks;
189	            Settings::instance().evaluationDate() = killDate;
190	            underlying->setValue(barrier);
191	            Real portfolioValue = portfolio2.NPV();
192	            Real putValue = putn->NPV();
193	            Real notional = portfolioValue/putValue;
194	            portfolio2.subtract(putn, notional);
195	        }
196	        Settings::instance().evaluationDate() = today;
197	        underlying->setValue(underlyingValue);
198	        portfolioValue = portfolio2.NPV();
199	        error = portfolioValue - referenceValue;
200	        std::cout << std::setw(widths[0]) << std::left
201	                  << "Replicating portfolio (26 dates)"
202	                  << std::fixed
203	                  << std::setw(widths[1]) << std::left << portfolioValue
204	                  << std::setw(widths[2]) << std::left << error
205	                  << std::endl;
206	
207	        // For the third portfolio, we'll use 52 dates at one-week's
208	        // distance.
209	        for (i=52; i>=1; i--) {
210	            // Same as above.
211	            Date innerMaturity = today + i*Weeks;
212	            auto innerExercise = ext::make_shared<EuropeanExercise>(innerMaturity);
213	            auto innerPayoff = ext::make_shared<PlainVanillaPayoff>(Option::Put, barrier);
214	            auto putn = ext::make_shared<EuropeanOption>(innerPayoff, innerExercise);
215	            putn->setPricingEngine(europeanEngine);
216	            Date killDate = today + (i-1)*Weeks;
217	            Settings::instance().evaluationDate() = killDate;
218	            underlying->setValue(barrier);
219	            Real portfolioValue = portfolio3.NPV();
220	            Real putValue = putn->NPV();
221	            Real notional = portfolioValue/putValue;
222	            portfolio3.subtract(putn, notional);
223	        }
224	        Settings::instance().evaluationDate() = today;
225	        underlying->setValue(underlyingValue);
226	        portfolioValue = portfolio3.NPV();
227	        error = portfolioValue - referenceValue;
228	        std::cout << std::setw(widths[0]) << std::left
229	                  << "Replicating portfolio (52 dates)"
230	                  << std::fixed
231	                  << std::setw(widths[1]) << std::left << portfolioValue
232	                  << std::setw(widths[2]) << std::left << error
233	                  << std::endl;
234	
235	        // Now we modify the market condition to see whether the
236	        // replication holds. First, we change the underlying value so
237	        // that the option is out of the money.
238	        std::cout << dblrule << std::endl;
239	        std::cout << "Modified market conditions: out of the money"
240	                  << std::endl;
241	        std::cout << dblrule << std::endl;
242	        std::cout << std::setw(widths[0]) << std::left << "Option"
243	                  << std::setw(widths[1]) << std::left << "NPV"
244	                  << std::setw(widths[2]) << std::left << "Error"
245	                  << std::endl;
246	        std::cout << rule << std::endl;
247	
248	        underlying->setValue(110.0);
249	
250	        referenceValue = referenceOption.NPV();
251	        std::cout << std::setw(widths[0]) << std::left
252	                  << "Original barrier option"
253	                  << std::fixed
254	                  << std::setw(widths[1]) << std::left << referenceValue
255	                  << std::setw(widths[2]) << std::left << "N/A"
256	                  << std::endl;
257	        portfolioValue = portfolio1.NPV();
258	        error = portfolioValue - referenceValue;
259	        std::cout << std::setw(widths[0]) << std::left
260	                  << "Replicating portfolio (12 dates)"
261	                  << std::fixed
262	                  << std::setw(widths[1]) << std::left << portfolioValue
263	                  << std::setw(widths[2]) << std::left << error
264	                  << std::endl;
265	        portfolioValue = portfolio2.NPV();
266	        error = portfolioValue - referenceValue;
267	        std::cout << std::setw(widths[0]) << std::left
268	                  << "Replicating portfolio (26 dates)"
269	                  << std::fixed
270	                  << std::setw(widths[1]) << std::left << portfolioValue
271	                  << std::setw(widths[2]) << std::left << error
272	                  << std::endl;
273	        portfolioValue = portfolio3.NPV();
274	        error = portfolioValue - referenceValue;
275	        std::cout << std::setw(widths[0]) << std::left
276	                  << "Replicating portfolio (52 dates)"
277	                  << std::fixed
278	                  << std::setw(widths[1]) << std::left << portfolioValue
279	                  << std::setw(widths[2]) << std::left << error
280	                  << std::endl;
281	
282	        // Next, we change the underlying value so that the option is
283	        // in the money.
284	        std::cout << dblrule << std::endl;
285	        std::cout << "Modified market conditions: in the money" << std::endl;
286	        std::cout << dblrule << std::endl;
287	        std::cout << std::setw(widths[0]) << std::left << "Option"
288	                  << std::setw(widths[1]) << std::left << "NPV"
289	                  << std::setw(widths[2]) << std::left << "Error"
290	                  << std::endl;
291	        std::cout << rule << std::endl;
292	
293	        underlying->setValue(90.0);
294	
295	        referenceValue = referenceOption.NPV();
296	        std::cout << std::setw(widths[0]) << std::left
297	                  << "Original barrier option"
298	                  << std::fixed
299	                  << std::setw(widths[1]) << std::left << referenceValue
300	                  << std::setw(widths[2]) << std::left << "N/A"
301	                  << std::endl;
302	        portfolioValue = portfolio1.NPV();
303	        error = portfolioValue - referenceValue;
304	        std::cout << std::setw(widths[0]) << std::left
305	                  << "Replicating portfolio (12 dates)"
306	                  << std::fixed
307	                  << std::setw(widths[1]) << std::left << portfolioValue
308	                  << std::setw(widths[2]) << std::left << error
309	                  << std::endl;
310	        portfolioValue = portfolio2.NPV();
311	        error = portfolioValue - referenceValue;
312	        std::cout << std::setw(widths[0]) << std::left
313	                  << "Replicating portfolio (26 dates)"
314	                  << std::fixed
315	                  << std::setw(widths[1]) << std::left << portfolioValue
316	                  << std::setw(widths[2]) << std::left << error
317	                  << std::endl;
318	        portfolioValue = portfolio3.NPV();
319	        error = portfolioValue - referenceValue;
320	        std::cout << std::setw(widths[0]) << std::left
321	                  << "Replicating portfolio (52 dates)"
322	                  << std::fixed
323	                  << std::setw(widths[1]) << std::left << portfolioValue
324	                  << std::setw(widths[2]) << std::left << error
325	                  << std::endl;
326	
327	        // Finally, a word of warning for those (shame on them) who
328	        // run the example but do not read the code.
329	        std::cout << dblrule << std::endl;
330	        std::cout
331	            << std::endl
332	            << "The replication seems to be less robust when volatility and \n"
333	            << "risk-free rate are changed. Feel free to experiment with \n"
334	            << "the example and contribute a patch if you spot any errors."
335	            << std::endl;
336	
337	        return 0;
338	    } catch (std::exception& e) {
339	        std::cerr << e.what() << std::endl;
340	        return 1;
341	    } catch (...) {
342	        std::cerr << "unknown error" << std::endl;
343	        return 1;
344	    }
345	}