Replication.cpp
This example uses the CompositeInstrument class to perform static replication of a down-and-out barrier option.
00001 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 00002 00020 /* This example showcases the CompositeInstrument class. Such class 00021 is used to build a static replication of a down-and-out barrier 00022 option, as outlined in Section 10.2 of Mark Joshi's "The Concepts 00023 and Practice of Mathematical Finance" to which we refer the 00024 reader. 00025 */ 00026 00027 // the only header you need to use QuantLib 00028 #define BOOST_LIB_DIAGNOSTIC 00029 # include <ql/quantlib.hpp> 00030 #undef BOOST_LIB_DIAGNOSTIC 00031 00032 #ifdef BOOST_MSVC 00033 /* Uncomment the following lines to unmask floating-point 00034 exceptions. Warning: unpredictable results can arise... 00035 00036 See http://www.wilmott.com/messageview.cfm?catid=10&threadid=9481 00037 Is there anyone with a definitive word about this? 00038 */ 00039 // #include <float.h> 00040 // namespace { unsigned int u = _controlfp(_EM_INEXACT, _MCW_EM); } 00041 #endif 00042 00043 #include <boost/timer.hpp> 00044 #include <iostream> 00045 #include <iomanip> 00046 00047 using namespace QuantLib; 00048 00049 #if defined(QL_ENABLE_SESSIONS) 00050 namespace QuantLib { 00051 00052 Integer sessionId() { return 0; } 00053 00054 } 00055 #endif 00056 00057 int main(int, char* []) 00058 { 00059 try { 00060 QL_IO_INIT 00061 00062 boost::timer timer; 00063 std::cout << std::endl; 00064 00065 Date today(29, May, 2006); 00066 Settings::instance().evaluationDate() = today; 00067 00068 // the option to replicate 00069 Barrier::Type barrierType = Barrier::DownOut; 00070 Real barrier = 70.0; 00071 Real rebate = 0.0; 00072 Option::Type type = Option::Put; 00073 Real underlyingValue = 100.0; 00074 boost::shared_ptr<SimpleQuote> underlying( 00075 new SimpleQuote(underlyingValue)); 00076 Real strike = 100.0; 00077 boost::shared_ptr<SimpleQuote> riskFreeRate(new SimpleQuote(0.04)); 00078 boost::shared_ptr<SimpleQuote> volatility(new SimpleQuote(0.20)); 00079 Date maturity = today + 1*Years; 00080 00081 std::cout << std::endl ; 00082 00083 // write column headings 00084 Size widths[] = { 45, 15, 15 }; 00085 Size totalWidth = widths[0]+widths[1]+widths[2]; 00086 std::string rule(totalWidth, '-'), dblrule(totalWidth, '='); 00087 00088 std::cout << dblrule << std::endl; 00089 std::cout << "Initial market conditions" << std::endl; 00090 std::cout << dblrule << std::endl; 00091 std::cout << std::setw(widths[0]) << std::left << "Option" 00092 << std::setw(widths[1]) << std::left << "NPV" 00093 << std::setw(widths[2]) << std::left << "Error" 00094 << std::endl; 00095 std::cout << rule << std::endl; 00096 00097 // bootstrap the yield/vol curves 00098 DayCounter dayCounter = Actual365Fixed(); 00099 Handle<Quote> h1(riskFreeRate); 00100 Handle<Quote> h2(volatility); 00101 Handle<YieldTermStructure> flatRate( 00102 boost::shared_ptr<YieldTermStructure>( 00103 new FlatForward(0, NullCalendar(), 00104 h1, dayCounter))); 00105 Handle<BlackVolTermStructure> flatVol( 00106 boost::shared_ptr<BlackVolTermStructure>( 00107 new BlackConstantVol(0, NullCalendar(), 00108 h2, dayCounter))); 00109 00110 // instantiate the option 00111 boost::shared_ptr<Exercise> exercise( 00112 new EuropeanExercise(maturity)); 00113 boost::shared_ptr<StrikedTypePayoff> payoff( 00114 new PlainVanillaPayoff(type, strike)); 00115 00116 boost::shared_ptr<StochasticProcess> stochasticProcess( 00117 new BlackScholesProcess(Handle<Quote>(underlying), 00118 flatRate, flatVol)); 00119 00120 BarrierOption referenceOption(barrierType, barrier, rebate, 00121 stochasticProcess, payoff, exercise); 00122 00123 Real referenceValue = referenceOption.NPV(); 00124 00125 std::cout << std::setw(widths[0]) << std::left 00126 << "Original barrier option" 00127 << std::fixed 00128 << std::setw(widths[1]) << std::left << referenceValue 00129 << std::setw(widths[2]) << std::left << "N/A" 00130 << std::endl; 00131 00132 // Replicating portfolios 00133 CompositeInstrument portfolio1, portfolio2, portfolio3; 00134 00135 // Final payoff first (the same for all portfolios): 00136 // as shown in Joshi, a put struck at K... 00137 boost::shared_ptr<Instrument> put1( 00138 new EuropeanOption(stochasticProcess, payoff, exercise)); 00139 portfolio1.add(put1); 00140 portfolio2.add(put1); 00141 portfolio3.add(put1); 00142 // ...minus a digital put struck at B of notional K-B... 00143 boost::shared_ptr<StrikedTypePayoff> digitalPayoff( 00144 new CashOrNothingPayoff(Option::Put, barrier, 1.0)); 00145 boost::shared_ptr<Instrument> digitalPut( 00146 new EuropeanOption(stochasticProcess, digitalPayoff, exercise)); 00147 portfolio1.subtract(digitalPut, strike-barrier); 00148 portfolio2.subtract(digitalPut, strike-barrier); 00149 portfolio3.subtract(digitalPut, strike-barrier); 00150 // ...minus a put option struck at B. 00151 boost::shared_ptr<StrikedTypePayoff> lowerPayoff( 00152 new PlainVanillaPayoff(Option::Put, barrier)); 00153 boost::shared_ptr<Instrument> put2( 00154 new EuropeanOption(stochasticProcess, lowerPayoff, exercise)); 00155 portfolio1.subtract(put2); 00156 portfolio2.subtract(put2); 00157 portfolio3.subtract(put2); 00158 00159 // Now we use puts struck at B to kill the value of the 00160 // portfolio on a number of points (B,t). For the first 00161 // portfolio, we'll use 12 dates at one-month's distance. 00162 Integer i; 00163 for (i=12; i>=1; i--) { 00164 // First, we instantiate the option... 00165 Date innerMaturity = today + i*Months; 00166 boost::shared_ptr<Exercise> innerExercise( 00167 new EuropeanExercise(innerMaturity)); 00168 boost::shared_ptr<StrikedTypePayoff> innerPayoff( 00169 new PlainVanillaPayoff(Option::Put, barrier)); 00170 boost::shared_ptr<Instrument> putn( 00171 new EuropeanOption(stochasticProcess, 00172 innerPayoff, innerExercise)); 00173 // ...second, we evaluate the current portfolio and the 00174 // latest put at (B,t)... 00175 Date killDate = today + (i-1)*Months; 00176 Settings::instance().evaluationDate() = killDate; 00177 underlying->setValue(barrier); 00178 Real portfolioValue = portfolio1.NPV(); 00179 Real putValue = putn->NPV(); 00180 // ...finally, we estimate the notional that kills the 00181 // portfolio value at that point... 00182 Real notional = portfolioValue/putValue; 00183 // ...and we subtract from the portfolio a put with such 00184 // notional. 00185 portfolio1.subtract(putn, notional); 00186 } 00187 // The portfolio being complete, we return to today's market... 00188 Settings::instance().evaluationDate() = today; 00189 underlying->setValue(underlyingValue); 00190 // ...and output the value. 00191 Real portfolioValue = portfolio1.NPV(); 00192 Real error = portfolioValue - referenceValue; 00193 std::cout << std::setw(widths[0]) << std::left 00194 << "Replicating portfolio (12 dates)" 00195 << std::fixed 00196 << std::setw(widths[1]) << std::left << portfolioValue 00197 << std::setw(widths[2]) << std::left << error 00198 << std::endl; 00199 00200 // For the second portfolio, we'll use 26 dates at two-weeks' 00201 // distance. 00202 for (i=52; i>=2; i-=2) { 00203 // Same as above. 00204 Date innerMaturity = today + i*Weeks; 00205 boost::shared_ptr<Exercise> innerExercise( 00206 new EuropeanExercise(innerMaturity)); 00207 boost::shared_ptr<StrikedTypePayoff> innerPayoff( 00208 new PlainVanillaPayoff(Option::Put, barrier)); 00209 boost::shared_ptr<Instrument> putn( 00210 new EuropeanOption(stochasticProcess, 00211 innerPayoff, innerExercise)); 00212 Date killDate = today + (i-2)*Weeks; 00213 Settings::instance().evaluationDate() = killDate; 00214 underlying->setValue(barrier); 00215 Real portfolioValue = portfolio2.NPV(); 00216 Real putValue = putn->NPV(); 00217 Real notional = portfolioValue/putValue; 00218 portfolio2.subtract(putn, notional); 00219 } 00220 Settings::instance().evaluationDate() = today; 00221 underlying->setValue(underlyingValue); 00222 portfolioValue = portfolio2.NPV(); 00223 error = portfolioValue - referenceValue; 00224 std::cout << std::setw(widths[0]) << std::left 00225 << "Replicating portfolio (26 dates)" 00226 << std::fixed 00227 << std::setw(widths[1]) << std::left << portfolioValue 00228 << std::setw(widths[2]) << std::left << error 00229 << std::endl; 00230 00231 // For the third portfolio, we'll use 52 dates at one-week's 00232 // distance. 00233 for (i=52; i>=1; i--) { 00234 // Same as above. 00235 Date innerMaturity = today + i*Weeks; 00236 boost::shared_ptr<Exercise> innerExercise( 00237 new EuropeanExercise(innerMaturity)); 00238 boost::shared_ptr<StrikedTypePayoff> innerPayoff( 00239 new PlainVanillaPayoff(Option::Put, barrier)); 00240 boost::shared_ptr<Instrument> putn( 00241 new EuropeanOption(stochasticProcess, 00242 innerPayoff, innerExercise)); 00243 Date killDate = today + (i-1)*Weeks; 00244 Settings::instance().evaluationDate() = killDate; 00245 underlying->setValue(barrier); 00246 Real portfolioValue = portfolio3.NPV(); 00247 Real putValue = putn->NPV(); 00248 Real notional = portfolioValue/putValue; 00249 portfolio3.subtract(putn, notional); 00250 } 00251 Settings::instance().evaluationDate() = today; 00252 underlying->setValue(underlyingValue); 00253 portfolioValue = portfolio3.NPV(); 00254 error = portfolioValue - referenceValue; 00255 std::cout << std::setw(widths[0]) << std::left 00256 << "Replicating portfolio (52 dates)" 00257 << std::fixed 00258 << std::setw(widths[1]) << std::left << portfolioValue 00259 << std::setw(widths[2]) << std::left << error 00260 << std::endl; 00261 00262 // Now we modify the market condition to see whether the 00263 // replication holds. First, we change the underlying value so 00264 // that the option is out of the money. 00265 std::cout << dblrule << std::endl; 00266 std::cout << "Modified market conditions: out of the money" 00267 << std::endl; 00268 std::cout << dblrule << std::endl; 00269 std::cout << std::setw(widths[0]) << std::left << "Option" 00270 << std::setw(widths[1]) << std::left << "NPV" 00271 << std::setw(widths[2]) << std::left << "Error" 00272 << std::endl; 00273 std::cout << rule << std::endl; 00274 00275 underlying->setValue(110.0); 00276 00277 referenceValue = referenceOption.NPV(); 00278 std::cout << std::setw(widths[0]) << std::left 00279 << "Original barrier option" 00280 << std::fixed 00281 << std::setw(widths[1]) << std::left << referenceValue 00282 << std::setw(widths[2]) << std::left << "N/A" 00283 << std::endl; 00284 portfolioValue = portfolio1.NPV(); 00285 error = portfolioValue - referenceValue; 00286 std::cout << std::setw(widths[0]) << std::left 00287 << "Replicating portfolio (12 dates)" 00288 << std::fixed 00289 << std::setw(widths[1]) << std::left << portfolioValue 00290 << std::setw(widths[2]) << std::left << error 00291 << std::endl; 00292 portfolioValue = portfolio2.NPV(); 00293 error = portfolioValue - referenceValue; 00294 std::cout << std::setw(widths[0]) << std::left 00295 << "Replicating portfolio (26 dates)" 00296 << std::fixed 00297 << std::setw(widths[1]) << std::left << portfolioValue 00298 << std::setw(widths[2]) << std::left << error 00299 << std::endl; 00300 portfolioValue = portfolio3.NPV(); 00301 error = portfolioValue - referenceValue; 00302 std::cout << std::setw(widths[0]) << std::left 00303 << "Replicating portfolio (52 dates)" 00304 << std::fixed 00305 << std::setw(widths[1]) << std::left << portfolioValue 00306 << std::setw(widths[2]) << std::left << error 00307 << std::endl; 00308 00309 // Next, we change the underlying value so that the option is 00310 // in the money. 00311 std::cout << dblrule << std::endl; 00312 std::cout << "Modified market conditions: in the money" << std::endl; 00313 std::cout << dblrule << std::endl; 00314 std::cout << std::setw(widths[0]) << std::left << "Option" 00315 << std::setw(widths[1]) << std::left << "NPV" 00316 << std::setw(widths[2]) << std::left << "Error" 00317 << std::endl; 00318 std::cout << rule << std::endl; 00319 00320 underlying->setValue(90.0); 00321 00322 referenceValue = referenceOption.NPV(); 00323 std::cout << std::setw(widths[0]) << std::left 00324 << "Original barrier option" 00325 << std::fixed 00326 << std::setw(widths[1]) << std::left << referenceValue 00327 << std::setw(widths[2]) << std::left << "N/A" 00328 << std::endl; 00329 portfolioValue = portfolio1.NPV(); 00330 error = portfolioValue - referenceValue; 00331 std::cout << std::setw(widths[0]) << std::left 00332 << "Replicating portfolio (12 dates)" 00333 << std::fixed 00334 << std::setw(widths[1]) << std::left << portfolioValue 00335 << std::setw(widths[2]) << std::left << error 00336 << std::endl; 00337 portfolioValue = portfolio2.NPV(); 00338 error = portfolioValue - referenceValue; 00339 std::cout << std::setw(widths[0]) << std::left 00340 << "Replicating portfolio (26 dates)" 00341 << std::fixed 00342 << std::setw(widths[1]) << std::left << portfolioValue 00343 << std::setw(widths[2]) << std::left << error 00344 << std::endl; 00345 portfolioValue = portfolio3.NPV(); 00346 error = portfolioValue - referenceValue; 00347 std::cout << std::setw(widths[0]) << std::left 00348 << "Replicating portfolio (52 dates)" 00349 << std::fixed 00350 << std::setw(widths[1]) << std::left << portfolioValue 00351 << std::setw(widths[2]) << std::left << error 00352 << std::endl; 00353 00354 // Finally, a word of warning for those (shame on them) who 00355 // run the example but do not read the code. 00356 std::cout << dblrule << std::endl; 00357 std::cout 00358 << std::endl 00359 << "The replication seems to be less robust when volatility and \n" 00360 << "risk-free rate are changed. Feel free to experiment with \n" 00361 << "the example and contribute a patch if you spot any errors." 00362 << std::endl; 00363 00364 Real seconds = timer.elapsed(); 00365 Integer hours = int(seconds/3600); 00366 seconds -= hours * 3600; 00367 Integer minutes = int(seconds/60); 00368 seconds -= minutes * 60; 00369 std::cout << " \nRun completed in "; 00370 if (hours > 0) 00371 std::cout << hours << " h "; 00372 if (hours > 0 || minutes > 0) 00373 std::cout << minutes << " m "; 00374 std::cout << std::fixed << std::setprecision(0) 00375 << seconds << " s\n" << std::endl; 00376 00377 return 0; 00378 } catch (std::exception& e) { 00379 std::cout << e.what() << std::endl; 00380 return 1; 00381 } catch (...) { 00382 std::cout << "unknown error" << std::endl; 00383 return 1; 00384 } 00385 }