P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
iv
P1: JYS FM JWBK392-Duffy
August 12, 2009 ...
329 downloads
1888 Views
4MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
iv
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Monte Carlo Frameworks Building customisable high-performance C++ applications
Daniel J. Duffy J¨org Kienitz
A John Wiley and Sons, Ltd., Publication
i
P1: JYS FM JWBK392-Duffy
C
August 12, 2009
16:11
Printer: Yet to come
2009 John Wiley & Sons, Ltd
Registered office John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex, PO19 8SQ, United Kingdom For details of our global editorial offices, for customer services and for information about how to apply for permission to reuse the copyright material in this book please see our website at www.wiley.com. The right of the author to be identified as the author of this work has been asserted in accordance with the Copyright, Designs and Patents Act 1988. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording or otherwise, except as permitted by the UK Copyright, Designs and Patents Act 1988, without the prior permission of the publisher. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books. Designations used by companies to distinguish their products are often claimed as trademarks. All brand names and product names used in this book are trade names, service marks, trademarks or registered trademarks of their respective owners. The publisher is not associated with any product or vendor mentioned in this book. This publication is designed to provide accurate and authoritative information in regard to the subject matter covered. It is sold on the understanding that the publisher is not engaged in rendering professional services. If professional advice or other expert assistance is required, the services of a competent professional should be sought. Library of Congress Cataloging-in-Publication Data Duffy, Daniel J. Monte Carlo frameworks : building customisable high performance C++ applications / Daniel J. Duffy, Joerg Kienitz. p. cm. ISBN 978-0-470-06069-8 (cloth) 1. Finance–Mathematical models. 2. Monte Carlo method. 3. C++ (Computer program language) I. Kienitz, Joerg. II. Title. HG106.D84 2009 518 .28202855133–dc22 2009021640 A catalogue record for this book is available from the British Library. ISBN 978-0-470-06069-8 Typeset in 10/12pt Times by Aptara Inc., New Delhi, India Printed in Great Britain by Antony Rowe, Chippenhan, Wiltshire
ii
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
To Brendan and Ilona Daniel To Amberley, Beatrice and Benoˆıt Joerg
iii
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
iv
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents Notation
xix
Executive Overview
xxiii
0 My First Monte Carlo Application One-Factor Problems 0.1 0.2 0.3 0.4 0.5
0.6 0.7 0.8 0.9 0.10 0.11 0.12 0.13 PART I
Introduction and objectives Description of the problem Ordinary differential equations (ODE) Stochastic differential equations (SDE) and their solution Generating uniform and normal random numbers 0.5.1 Uniform random number generation 0.5.2 Polar Marsaglia method 0.5.3 Box-Muller method 0.5.4 C++ code for uniform and normal random variate generation 0.5.5 Other methods The Monte Carlo method Calculating sensitivities The initial C++ Monte Carlo framework: hierarchy and paths The initial C++ Monte Carlo framework: calculating option price The predictor-corrector method: a scheme for all seasons? The Monte Carlo approach: caveats and nasty surprises Summary and conclusions Exercises and projects
1 1 1 2 3 4 4 4 5 5 8 8 9 10 19 23 24 25 25
FUNDAMENTALS
1 Mathematical Preparations for the Monte Carlo Method 1.1 Introduction and objectives 1.2 Random variables 1.2.1 Fundamental concepts 1.2.2 Relative frequency and the beginnings of probability 1.2.3 Random variables
v
31 31 31 31 32 32
P1: JYS FM JWBK392-Duffy
vi
August 12, 2009
16:11
Printer: Yet to come
Contents
1.3 1.4 1.5 1.6 1.7 1.8 1.9
1.10 1.11 1.12 1.13 1.14 1.15
Discrete and continuous random variables Multiple random variables A short history of integration σ -algebras, measurable spaces and measurable functions Probability spaces and stochastic processes The Ito stochastic integral Applications of the Lebesgue theory 1.9.1 Convergence theorems 1.9.2 Fubini’s theorem Some useful inequalities Some special functions Convergence of function sequences Applications to stochastic analysis Summary and conclusions Exercises and projects
2 The Mathematics of Stochastic Differential Equations (SDE) 2.1 Introduction and objectives 2.2 A survey of the literature 2.3 Mathematical foundations for SDEs 2.3.1 Metric spaces 2.3.2 Cauchy sequences, complete metric spaces and convergence 2.3.3 Continuous and Lipschitz continuous functions 2.4 Motivating random (stochastic) processes 2.5 An introduction to one-dimensional random processes 2.6 Stochastic differential equations in Banach spaces: prologue 2.7 Classes of SIEs and properties of their solutions 2.8 Existence and uniqueness results 2.9 A special SDE: the Ito equation 2.10 Numerical approximation of SIEs 2.11 Transforming an SDE: the Ito formula 2.12 Summary and conclusions 2.13 Appendix: proof of the Banach fixed-point theorem and some applications 2.14 Exercises and projects
3 Alternative SDEs and Toolkit Functionality 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9
Introduction and objectives Bessel processes Random variate generation The exponential distribution The beta and gamma distributions The chi-squared, Student and other distributions Discrete variate generation The Fokker-Planck equation The relationship with PDEs 3.9.1 The Fichera function 3.10 Alternative stochastic processes
34 37 38 39 40 41 43 43 45 45 46 48 49 50 50 53 53 53 55 55 56 57 59 59 62 62 63 64 66 68 69 69 71 73 73 73 74 74 75 79 79 80 81 81 84
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
3.11 3.12 3.13
3.14
3.10.1 The constant elasticity of variance (CEV) model 3.10.2 Exact, quasi-exact and numerical solutions of CEV equation 3.10.3 Monte Carlo simulation of CEV models 3.10.4 American option pricing and hedging with the CEV model 3.10.5 Test cases and numerical results Using associative arrays and matrices to model lookup tables and volatility surfaces Summary and conclusion Appendix: statistical distributions and special functions in the Boost library 3.13.1 The gamma functions 3.13.2 The error function 3.13.3 An overview of statistical distributions in Boost Exercises and projects
4 An Introduction to the Finite Difference Method for SDE 4.1 Introduction and objectives 4.2 An introduction to discrete time simulation, motivation and notation 4.3 Foundations of discrete time approximation: ordinary differential equations 4.4 Foundations of discrete time approximation: stochastic differential equations 4.4.1 Absolute error criterion 4.4.2 Confidence intervals for the absolute error 4.4.3 Dependence of the absolute error on the step size 4.4.4 Strong and weak convergence 4.5 Some common schemes for one-factor SDEs 4.6 The Milstein schemes 4.7 Predictor-corrector methods 4.8 Stiff ordinary and stochastic differential equations 4.8.1 Robust schemes for stiff systems 4.8.2 Stiff stochastic differential equations 4.9 Software design and C++ implementation issues 4.10 Computational results 4.11 Aside: the characteristic equation of a difference scheme 4.12 Summary and conclusions 4.13 Exercises and projects
vii
85 86 87 91 92 93 96 97 97 98 99 102 107 107 107 109 113 113 114 115 116 117 117 118 119 121 123 125 126 127 128 128
5 Design and Implementation of Finite Difference Schemes in Computational Finance 5.1 Introduction and objectives 5.2 Modelling SDEs and FDM in C++ 5.3 Mathematical and numerical tools 5.3.1 Analytical solution and numerical solution of SDEs 5.3.2 Brownian Bridge 5.3.3 Finite difference methods for Brownian Bridges
137 137 137 138 139 140 142
P1: JYS FM JWBK392-Duffy
viii
August 12, 2009
16:11
Printer: Yet to come
Contents
5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11
The Karhunen-Loeve expansion Cholesky decomposition Spread options with stochastic volatility The Heston stochastic volatility model Path-dependent options and the Monte Carlo method A small software framework for pricing options Summary and conclusions Exercises and projects
6 Advanced Finance Models and Numerical Methods 6.1 Introduction and objectives 6.2 Processes with jumps 6.2.1 Specific choices for jump processes 6.2.2 Simulating jumps, fixed dates 6.2.3 Simulating jump times 6.2.4 Finite difference approximations 6.3 L´evy processes 6.4 Measuring the order of convergence 6.4.1 A general convergence principle 6.4.2 Applications to ordinary differential equations 6.4.3 Applications to stochastic differential equations 6.5 Mollifiers, bump functions and function regularisation 6.6 When Monte Carlo does not work: counterexamples 6.6.1 How good is the random number generator rand()? 6.6.2 Special stochastic differential equations 6.7 Approximating SDEs using strong Taylor, explicit and implicit schemes 6.7.1 Stability analysis of SDEs with multiplicative and additive noise 6.7.2 Strong Taylor approximants 6.7.3 Explicit strong schemes 6.7.4 Implicit strong schemes 6.8 Summary and conclusions 6.9 Exercises and projects
7 Foundations of the Monte Carlo Method 7.1 7.2 7.3 7.4
Introduction and objectives Basic probability The Law of Large Numbers The Central Limit Theorem 7.4.1 Lindeberg-Feller Central Limit Theorem 7.4.2 Explicit calculations of the confidence intervals 7.5 Quasi Monte Carlo methods 7.5.1 Uniform distribution and its geometric interpretation 7.6 Summary and conclusions 7.7 Exercises and projects
143 144 146 153 160 161 162 162 167 167 168 169 169 169 170 171 172 172 174 175 176 177 177 179 179 180 181 182 183 183 184 189 189 189 190 191 192 193 194 196 198 198
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
ix
PART II DESIGN PATTERNS
8 Architectures and Frameworks for Monte Carlo Methods: Overview 8.1 8.2 8.3 8.4
Goals of Part II of this book Introduction and objectives of this chapter The advantages of domain architectures Software Architectures for the Monte Carlo method 8.4.1 Market model systems 8.4.2 Numerical simulator systems 8.4.3 Pricing, hedge and risk systems 8.5 Summary and conclusions 8.6 Exercises and projects
9 System Decomposition and System Patterns 9.1 Introduction and objectives 9.2 Software development process; a critique 9.3 System decomposition, from concept to code 9.3.1 Phases 9.4 Decomposition techniques, the process 9.4.1 A special case: geometric decomposition 9.4.2 Examples of task and data decomposition 9.5 Whole-part 9.6 Whole-part decomposition; the process 9.6.1 Task-based decomposition 9.6.2 Data decomposition 9.7 Presentation-Abstraction Control (PAC) 9.8 Building complex objects and configuring applications 9.8.1 The Factory Method pattern 9.8.2 Abstract Factory pattern 9.8.3 Builder pattern 9.9 Summary and conclusions 9.10 Exercises and projects
10 Detailed Design using the GOF Patterns 10.1 Introduction and objectives 10.2 Discovering which patterns to use 10.2.1 Whole-Part structure for a finite difference scheme 10.2.2 The Preprocessor agent 10.2.3 The Conversion agent 10.2.4 The Display agent and Top-Level agent 10.3 An overview of the GOF patterns 10.3.1 Strengths and limitations of GOF patterns 10.4 The essential structural patterns 10.4.1 Facade pattern 10.4.2 Bridge pattern, template version 10.4.3 Bridge pattern, run-time version 10.4.4 Adapter pattern 10.4.5 Layers pattern
203 203 203 204 207 207 209 211 212 213 217 217 217 217 218 220 221 222 222 223 223 224 226 229 229 234 237 239 239 243 243 244 245 246 251 254 255 257 257 258 258 262 266 266
P1: JYS FM JWBK392-Duffy
x
August 12, 2009
16:11
Printer: Yet to come
Contents
10.5 The essential creational patterns 10.5.1 Factory Method pattern 10.5.2 Builder pattern 10.6 The essential behavioural patterns 10.6.1 Visitor pattern 10.6.2 Strategy and Template Method patterns 10.7 Summary and conclusions 10.8 Exercises and projects
11 Combining Object-Oriented and Generic Programming Models 11.1 11.2 11.3 11.4
11.5
11.6 11.7 11.8 11.9 11.10
Introduction and objectives Using templates to implement components: overview Templates versus inheritance, run-time versus compile-time Advanced C++ templates 11.4.1 Default values for template parameters 11.4.2 Template nesting 11.4.3 Template member functions 11.4.4 Partial template specialisation 11.4.5 Template template parameters Traits and policy-based design 11.5.1 Traits 11.5.2 Policy-based design (PBD) 11.5.3 When to use inheritance and when to use generics Creating templated design patterns A generic Singleton pattern Generic composite structures 11.8.1 Applications of generic composites Summary and conclusions Exercises and projects
12 Data Structures and their Application to the Monte Carlo Method 12.1 Introduction and objectives 12.2 Arrays, vectors and matrices 12.3 Compile-time vectors and matrices 12.3.1 One-dimensional data structures: vectors 12.3.2 Two-dimensional data structures: matrices 12.3.3 Application: modelling N-factor SDEs 12.4 Creating adapters for STL containers 12.5 Date and time classes 12.5.1 Basic functionality in date class 12.5.2 Creating sets of dates and using set operations 12.5.3 Mapping dates to mesh points 12.5.4 Calendars, business days and business conventions 12.6 The class string 12.6.1 String constructors and string properties 12.6.2 Extracting characters and substrings
266 267 270 270 271 271 276 276 281 281 281 283 286 286 287 289 290 291 294 294 301 304 306 307 310 314 314 314 319 319 319 324 324 327 328 331 334 335 335 338 339 339 340 342
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
12.7 Modifying strings 12.7.1 Searching and finding in strings 12.7.2 Conversions between strings and other data types 12.8 A final look at the generic composite 12.9 Summary and conclusions 12.10 Exercises and projects
13 The Boost Library: An Introduction 13.1 Introduction and objectives 13.2 A taxonomy of C++ pointer types 13.2.1 The smart pointer types 13.2.2 Scoped pointers 13.2.3 Shared pointers 13.2.4 Using smart pointers in Monte Carlo applications 13.3 Modelling homogeneous and heterogeneous data in Boost 13.3.1 Tuples 13.3.2 Variants and discriminated unions 13.3.3 Any and undiscriminated types 13.3.4 A property class 13.3.5 Boost arrays 13.4 Boost signals: notification and data synchronisation 13.5 Input and output 13.5.1 Boost.Serialisation 13.5.2 Boost.Filesystem 13.6 Linear algebra and uBLAS 13.7 Date and time 13.8 Other libraries 13.8.1 String and text processing 13.8.2 Function objects and higher-order programming 13.8.3 Concurrent and multi-threading programming 13.8.4 Interval arithmetic 13.9 Summary and conclusions 13.10 Exercises and projects
xi
343 343 344 345 348 348 353 353 353 354 354 357 361 361 361 362 363 365 366 367 368 368 370 371 372 372 373 374 374 374 374 374
PART III ADVANCED APPLICATIONS
14 Instruments and Payoffs 14.1 Introduction and objectives 14.2 Creating a C++ instrument hierarchy 14.2.1 Instrument hierarchy 14.2.2 Underlyings and derivatives 14.3 Modelling payoffs in C++ 14.3.1 Simple property sets 14.3.2 Extending the payoff class 14.3.3 Heterogeneous property sets 14.3.4 The payoff base class
379 379 379 380 380 383 383 386 386 388
P1: JYS FM JWBK392-Duffy
xii
August 12, 2009
16:11
Printer: Yet to come
Contents
14.3.5 Abstract factories for payoff classes 14.3.6 Exception handling 14.4 Summary and conclusions 14.5 Exercises and projects
15 Path-Dependent Options 15.1 Introduction and objectives 15.2 Monte Carlo – a simple general-purpose version 15.2.1 The structure 15.2.2 Adding models 15.2.3 Adding schemes 15.2.4 The Monte Carlo evaluation 15.3 Asian options 15.3.1 Mapping Asian options into our framework 15.3.2 Approximation formulae for Asian options 15.3.3 Control variates 15.4 Options on the running Max/Min 15.5 Barrier options 15.5.1 Mapping barrier options into our framework 15.5.2 Approximation formulae for barrier options 15.5.3 Importance sampling 15.5.4 Antithetic variables 15.5.5 Numerical results 15.6 Lookback options 15.6.1 Approximation formulae for lookback options 15.6.2 Results 15.7 Cliquet Options 15.7.1 Remarks on cliquet options 15.7.2 C++ implementation 15.7.3 Version of the basic cliquet option 15.7.4 Results 15.8 Summary and conclusions 15.9 Exercises and projects
16 Affine Stochastic Volatility Models 16.1 Introduction and objectives 16.2 The volatility skew/smile 16.3 The Heston model 16.3.1 Implementing the Heston model 16.3.2 Euler scheme 16.3.3 Full truncation Euler scheme 16.3.4 Andersen’s QE scheme 16.3.5 A biased-free scheme 16.4 The Bates/SVJ model 16.5 Implementing the Bates model 16.6 Numerical results – European options
389 391 392 393 395 395 396 396 397 398 400 401 402 405 406 411 412 413 414 415 416 417 418 420 421 422 422 423 423 424 424 424 427 427 427 429 432 434 434 435 441 441 443 444
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
16.7 Numerical results – skew-dependent options 16.7.1 European options – digital options 16.7.2 Path-dependent options – cliquet options 16.7.3 Results 16.8 XLL – using DLL within Microsoft Excel 16.8.1 What is an xll? 16.8.2 XLW – A framework for creating xll 16.8.3 Developing using XLW 16.9 Analytic solutions for affine stochastic volatility models 16.10 Summary and conclusions 16.11 Exercises and projects
17 Multi-Asset Options 17.1 17.2 17.3 17.4
17.5 17.6 17.7 17.8
17.9 17.10 17.11
Introduction and objectives Modelling in multiple dimensions Implementing payoff classes for multi-asset options Some multi-asset options 17.4.1 Spread options 17.4.2 Approximation formulae 17.4.3 Quanto options Basket options Min/Max options Mountain range options The Heston model in multiple dimensions 17.8.1 Extending the QE scheme 17.8.2 Spread options Equity interest rate hybrids Summary and conclusions Exercises and projects
18 Advanced Monte Carlo I – Computing Greeks 18.1 18.2 18.3 18.4
Introduction and objectives The finite difference method The pathwise method The likelihood ratio method 18.4.1 Examples 18.5 Likelihood ratio for finite differences – proxy simulation 18.6 Summary and conclusions 18.7 Exercises and projects
19 Advanced Monte Carlo II – Early Exercise 19.1 19.2 19.3 19.4 19.5
Introduction and objectives Description of the problem Pricing American options by regression C++ design Linear least squares regression
xiii
446 446 448 449 449 452 452 452 455 457 458 461 461 461 465 466 466 466 468 469 471 475 480 481 482 482 486 486 489 489 489 492 497 499 503 504 506 511 511 511 512 513 516
P1: JYS FM JWBK392-Duffy
xiv
August 12, 2009
16:11
Printer: Yet to come
Contents
19.6 19.7 19.8 19.9 19.10 19.11
19.5.1 The regression function 19.5.2 The exercise decision Example – step by step Analysis of the method and improvements 19.7.1 Selecting basis functions Upper bounds Examples Summary and conclusions Exercises and projects
20 Beyond Brownian Motion 20.1 Introduction and objectives 20.2 Normal mean variance mixture models 20.2.1 The normal inverse Gaussian model 20.2.2 C++ implementation 20.2.3 The variance gamma model 20.2.4 Matching underlying assets and martingale dynamics 20.3 The multi-dimensional case 20.4 Summary and conclusions 20.5 Exercises and projects
518 519 520 521 522 525 527 528 528 531 531 531 532 532 535 535 536 536 538
PART IV SUPPLEMENTS
21 C++ Application Optimisation and Performance Improvement 21.1 Introduction and objectives 21.2 Modelling functions in C++: choices and consequences 21.2.1 Function pointers 21.2.2 Generic classes that model functions 21.2.3 Function objects in STL 21.2.4 What is polymorphism? 21.3 Performance issues in C++: classifying potential bottlenecks 21.3.1 Inlining 21.3.2 Static and dynamic casting 21.3.3 Preventing unnecessary object construction 21.3.4 Exception handling 21.3.5 Templates versus inheritance 21.3.6 Performance and the STL 21.3.7 Some final tips 21.4 Temporary objects 21.5 Special features in the Boost library 21.6 Boost multiarray library 21.7 Boost random number library 21.8 STL and Boost smart pointers: final remarks 21.9 Summary and conclusions 21.10 Exercises, projects and guidelines
543 543 543 544 547 549 550 552 553 554 554 557 558 559 559 560 562 563 564 566 568 569
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
22 Random Number Generation and Distributions 22.1 Introduction and objectives 22.2 Uniform number generation 22.2.1 Pseudo random number generators 22.2.2 Quasi random number generators 22.2.3 Sobol numbers 22.3 The Sobol class 22.4 Number generation due to given distributions 22.4.1 Methods for computing variates 22.4.2 The inverse method 22.4.3 Acceptance/Rejection and ratio of uniforms 22.4.4 C++ implementation 22.4.5 Generating normal variates 22.4.6 Generating gamma distributed variates 22.4.7 Generating χ 2 -distributed variates 22.4.8 Generating Poisson distributed variates 22.5 Jump processes 22.5.1 The Poisson process 22.5.2 Simple generalisations 22.5.3 Compensation and compounding 22.5.4 Poisson random measures 22.5.5 Jump measures 22.6 The random generator templates 22.7 Tests for randomness 22.8 Summary and conclusions 22.9 Exercises and projects
23 Some Mathematical Background 23.1 Introduction and objectives 23.2 A matrix class 23.3 Matrix functions 23.3.1 The Cholesky decomposition 23.3.2 The spectral decomposition 23.3.3 Singular value decomposition 23.4 Functional analysis 23.4.1 The basics 23.4.2 Fourier transform 23.4.3 Hilbert spaces and L 2 -basis 23.4.4 Measures and Fourier transform 23.4.5 The characteristic function of a random variable 23.5 Applications to option pricing 23.5.1 Semi-analytical prices and their C++ implementation 23.6 Summary and conclusions 23.7 Exercises and projects
xv
571 571 571 572 576 576 578 580 581 581 581 582 583 583 587 587 588 588 590 590 591 592 593 596 596 597
601 601 601 601 601 603 607 608 608 609 609 609 610 610 611 614 614
P1: JYS FM JWBK392-Duffy
xvi
August 12, 2009
16:11
Printer: Yet to come
Contents
24 An Introduction to Multi-threaded and Parallel Programming 24.1 24.2 24.3 24.4 24.5
24.6 24.7
24.8
24.9 24.10 24.11
Introduction and objectives Shared memory models Sequential, concurrent and parallel programming 101 How fast is fast? Performance analysis of parallel programs An introduction to processes and threads 24.5.1 The life of a thread 24.5.2 How threads communicate What kinds of applications are suitable for multi-threading? 24.6.1 Suitable tasks for multi-threading The multi-threaded application lifecycle 24.7.1 Finding concurrency and decomposition patterns 24.7.2 Algorithm structure 24.7.3 Supporting structures, models and patterns 24.7.4 Implementation mechanisms Some model architectures 24.8.1 The Monte Carlo engine 24.8.2 The market model system 24.8.3 What’s next? Analysing and designing large software systems: a summary of the steps Conclusions and summary Exercises and projects
617 617 617 619 623 625 625 626 626 626 627 627 627 628 628 629 631 632 633 633 634 634
25 An Introduction to OpenMP and its Applications to the Monte Carlo Method 25.1 Introduction and objectives 25.2 Loop optimisation 25.2.1 Loop interchange 25.2.2 Loop fission and fusion 25.2.3 Loop unrolling 25.2.4 Loop tiling 25.2.5 Serial loop optimisation in Monte Carlo applications 25.3 An overview of OpenMP 25.4 Threads in OpenMP 25.5 Loop-level parallelism 25.6 Data sharing 25.6.1 Ensuring private variable initialisation and finalisation 25.6.2 Reduction operations 25.6.3 The copyin clause and threadprivate directive 25.6.4 The flush directive 25.7 Work-sharing and parallel regions 25.7.1 Work-sharing constructs 25.7.2 The nowait clause 25.8 Nested loop optimisation 25.9 Scheduling in OpenMP
637 637 637 638 639 640 641 642 644 644 646 646 648 649 650 651 651 652 653 654 656
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Contents
25.10 OpenMP for the Monte Carlo method 25.11 Conclusions and summary 25.12 Exercises and projects
26 A Case Study of Numerical Schemes for the Heston Model 26.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 26.10
Introduction and objectives Test scenarios Numerical approximations for the Heston model Testing different schemes and scenarios Results Lessons learned Extensions, calibration and more Other numerical methods for Heston Summary and conclusions Exercises and projects
27 Excel, C++ and Monte Carlo Integration 27.1 Introduction and objectives 27.2 Integrating applications and Excel 27.3 ATL architecture 27.3.1 Interfaces and data structures 27.3.2 The structure of an ATL project and its classes 27.3.3 Implementing the methods in IDTExtensibility2 27.4 Creating my first ATL project: the steps 27.5 Creating automation add-ins in Excel 27.5.1 Automation interfaces 27.6 Useful utilities and interoperability projects 27.7 Test Case: a COM add-in and complete code 27.7.1 COM add-in 27.7.2 Automation add-in 27.7.3 The utilities class 27.8 Summary and conclusions 27.9 Exercises and projects
xvii
657 661 661 665 665 666 667 672 675 678 679 680 681 681 685 685 686 686 686 688 691 693 695 695 696 697 697 701 704 707 707
References
711
Index
719
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
xviii
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Notation This section contains a list of the notation used in Chapters 7, 14 to 20, 22, 23, and 26 which are written by Joerg Kienitz. The notation for the remaining chapters, written by Daniel Duffy, is in situ. (·)+ {t1 , t2 , . . . , t N } α χ2 ∂ ∂φ
Cˆ tE (x) ˆ Cov ˆI Vˆ VˆIS VˆC κ λ λi C E N P R R+ V F Ft N (µ, σ 2 ) R T TE x
max(·, 0) A discrete set of time points Parameter χ 2 distribution Small number Partial derivative with respect to φ Gamma distribution, second order Greek Expected continuation value estimator Estimator for covariance Estimator Estimator of the payoff V Importance sampling estimator Control variate estimator of the payoff V Mean reversion rate (Heston/Bates model) Jump intensity Eigenvalue Complex numbers Expectation Positive integers Probability measure Real line Positive real line Variance σ algebra Filtration Normal distribution with mean µ and variance σ 2 Real part of a complex number A discrete set of time points Exercise schedule
xix
P1: JYS FM JWBK392-Duffy
xx
µJ
ω ωModel ⊕ φ π ψi ρ σ σJ τ ξ < ·, · > 1{ . . .} AT C tR (x) Cov d ∗ D∞ diag dJ dW f, g H h h(·) i K Kλ L(t) M(t) max min N (t) r r (t) Ri RSC S(t) S TA A SGT A SC T tn
August 12, 2009
16:11
Printer: Yet to come
Notation
Mean jump rate for (log)normal jumps Probability space Realisation Martingale correction Integer arithmetic + Long-term variance Characteristic function Transition kernel Basis function Correlation Volatility Correlation matrix Volatility of jumps for (log)normal jumps Stopping time Volatility of variance Scalar product Indicator function Transposed matrix Realised continuation value Covariance Dividend *-discrepancy Diagonal matrix Jump part of stochastic differential equation White noise Functions Barrier level Payoff function Payoff function √ Imaginary number i = −1 Strike Bessel function L´evy process Martingale process Maximum of several variables Minimum of several variables Counting process Riskless rate Short rate process Return relative Reverse Swing Cliquet payoff Spot price process Arithmetic average with respect to the set T Geometric average with respect to the set T Swing Cliquet payoff Maturity Time point
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Notation
vi , m i Vt (·) W X (t) X, S, Y, Z Y (t) Z
Direction numbers (different representation) Value of derivative at time t Brownian motion Logarithm of the spot price Random variable Stochastic process Gaussian random variable
xxi
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
xxii
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Executive Overview WHAT IS THIS BOOK? The goal of this book is to price one-factor and multi-factor equity options using the Monte Carlo method. In this essentially self-contained book we define the financial models and the underlying mathematical theory for this class of options and we then design the corresponding algorithms using a number of numerical techniques (such as the finite difference method). Having created the algorithms we design the software applications using design and system patterns in C++. Finally, we use the Standard Template Library (STL) and the Boost library suite whenever possible because of their robustness and suitability for applications in computational finance. In short, we have attempted to trace the steps that produce a working software program in C++ from a given financial model.
WHAT’S SPECIAL ABOUT THIS BOOK? This is the first book in our opinion that discusses the complete software lifecycle of the Monte Carlo simulation process for computational finance. In particular, the book introduces the most important issues and topics in Monte Carlo simulation: • • • • • • •
The mathematical theory of stochastic differential equations. The Finite Difference Method (FDM) for Monte Carlo. One-factor and n-factor option pricing problems. Option sensitivities; early exercise features. Stochastic volatility and jump models. System and design patterns (GOF, POSA). Standard libraries (STL, Boost, OpenMP).
Furthermore, we provide working source code for the examples in the book and each chapter has numerous practical exercises and projects that you work on and will be helpful when you wish to extend the software framework. Each exercise is ranked according to its level of difficulty using a ‘star system’; simple exercises are denoted as ‘*’ and the most difficult exercises are ‘*****’. We have attempted to make the book as self-contained as possible by introducing the financial and mathematical underpinnings of the Monte Carlo method. We also give a discussion of advanced C++ and design patterns. This book assumes C++ knowledge to the level discussed in Duffy (2006a), for example.
xxiii
P1: JYS FM JWBK392-Duffy
xxiv
August 12, 2009
16:11
Printer: Yet to come
Executive Overview
WHO IS THIS BOOK FOR? This hands-on book is for those developers, quantitative analysts, designers and modellers who wish to understand the Monte Carlo method, apply it to computational finance and improve their C++ and software design skills. We have written the book in such a way that the reader can learn the material by examining and running test models before moving to more advanced ones. This book is also of interest to those finance professionals who work in model validation and risk management. Finally, we expect the book to be useful to non-financial people such as engineers, mathematical and software developers who wish to gain an understanding of financial models and how to implement them in C++. We assume that the reader has a working knowledge of C++; this is not a book for C++ novices!
THE STRUCTURE OF THIS BOOK This book contains four major parts and these comprise 27 chapters in total. Part I deals with the mathematical and numerical background to the Monte Carlo method. We discuss Lebesgue integration, stochastic differential equations, the Finite Difference Method (FDM) as well as specific finance examples such as stochastic volatility models. The added value of Part I is that it contains much of the mathematical foundation needed for an understanding of Monte Carlo simulation. Part II is devoted to state-of-the-art object-oriented (OOP) and generic (C++ template) programming (GP) techniques, how to use them, how to combine them and how to apply them to computational finance. We show how the appropriate use of OOP and GP can improve the flexibility and robustness of applications. Furthermore, in this part we review the famous GOF and POSA patterns and we show how a subset of these patterns is vital to the creation of a flexible software framework, in particular Whole-Part, Presentation-Abstraction-Control, Bridge and Adapter, to name a few. The added value of Part II is that we use advanced C++ programming models and design patterns to produce flexible designs for Monte Carlo applications. Part III focuses on the application of the Monte Carlo methods to financial applications. We consider path-dependent and multi-asset options. We apply popular stochastic volatility models, models based on exponential L´evy processes and we apply variance reduction techniques to calculate prices of options. Finally, we show how to obtain Greeks and prices for options including early exercise features. The added value of Part III is that it introduces a range of option pricing models and maps them to C++. Part IV contains background information on a number of topics that are related to the chapters in the first three parts of the book. First, we discuss how to improve the performance of C++ code by avoiding temporary object creation, loop optimisation and by using function objects instead of C-style function pointers. Furthermore, we give an introduction to the design of parallel programs and how to implement them in the OpenMP library, a de facto standard for the creation of multi-threaded applications in shared memory computers. We also devote a chapter to describing how to integrate C++ code with the Excel spreadsheet program using COM and Automation addins. Finally, we devote two chapters to random number generation and other mathematical methods that are needed in this book. The added value of Part IV is the detailed discussion of a number of supporting techniques that add to the robustness, efficiency and flexibility of C++ applications.
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
Executive Overview
xxv
HOW CAN I USE THIS BOOK? After having studied this book, and reviewed and run the code on the CD, you should then have a good understanding of how to create your own Monte Carlo models. There are different ways to achieve this end and seeing that the book consists of 27 chapters we think it is necessary to discuss how to read these chapters (and in which order). Some scenarios are: • Reading the chapters in Parts I, II and III in that order. This is the standard route and it is suitable for those readers who wish to learn the Monte Carlo method in a step-by-step fashion. • For those readers who wish to start developing their own applications as soon as possible, we advise reading Chapters 4 and 5, moving to the chapters in Part II and then finally examining the code and models for the one-factor and n-factor problems in Part III. • The small software framework in Chapter 0 can be generalised to more complex applications, especially when this process is executed in conjunction with the design and system patterns of Chapters 9, 10, 11 and 12. Of course, there are many other ways to use the book but the above list may be a useful starting point.
WHAT THIS BOOK IS NOT This is not a book on how to learn C++. We assume that the reader has a good working knowledge of object-oriented aspects of the language (such as inheritance, composition and polymorphism). We assume some knowledge of STL and template programming to the level that is discussed in Duffy (2004a) and Duffy (2006a). The code on the CD is not a software package.
SOURCE CODE, SUPPORT AND CONTACT You may use the code on the CD for your personal use and in your own applications only. For feedback, (constructive) criticisms and suggestions, please send to www.datasimfinancial.com where you can join our forum free of charge. We have done our utmost to check for typos and errors in the book; if you find any we would be most grateful if you bring them to our attention. We will correct them in the next edition of the book.
ACKNOWLEDGEMENTS Daniel Duffy would like to thank all those finance professionals whom he has trained and been in contact with. He thanks Ilona and his son Brendan for their patience during the writing and preparation of this book. Joerg Kienitz is indebted to his children Amberley and Benoît and his wife Beatrice for their patience and their encouragement. Sometimes it was a burden for them also. He furthermore thanks Daniel Wetterau for fruitful discussions about financial modelling and coding, and finally, Guido Behrendt, Albrecht Flues and Horst K¨upker for their (job related) support.
P1: JYS FM JWBK392-Duffy
August 12, 2009
16:11
Printer: Yet to come
xxvi
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
0 My First Monte Carlo Application One-Factor Problems Get it working, then get it right, then get it optimised
0.1 INTRODUCTION AND OBJECTIVES The goal of this book is to develop algorithms for pricing a range of derivatives products and then mapping these algorithms to C++ code. The technique that we use is the Monte Carlo method. Part I of this book introduces the fundamental mathematical concepts, algorithms and a number of C++ programming techniques that are needed when using the Monte Carlo method. The main goal in this chapter is to design and implement an initial C++ framework – consisting of a set of loosely coupled classes – that calculate the price of plain one-factor options. The framework has limited functionality and scope but it is structured in such a way that it can be – and will be – extended and generalised to n-factor and path-dependent problems as well as to problems with early exercise features. Some of the features discussed in this chapter are:
r r r
Simple one-dimensional stochastic differential equations (SDE), their formulation and how to find exact and approximate solutions to them. Generation of uniform and normal random numbers using random number generators such as Polar Marsaglia and Box-Muller. A short introduction to the Monte Carlo method and we apply it to finding the price of a one-factor European option.
In general, we partition the Monte Carlo application into three main subsystems. The core process in the application is to calculate the price of an option by simulation of the path of the underlying variable. We can also develop functionality that displays other relevant information, for example sensitivities or statistics. This chapter is a self-contained introduction to the Monte Carlo method and its realisation in C++. It can be read by those who are new to the subject as well as by those who have programming experience. You can test your knowledge of C++ by examining and running the corresponding code on the CD. If the syntax is difficult to understand, then this means that your C++ knowledge needs to be refreshed!
0.2 DESCRIPTION OF THE PROBLEM We focus on a linear, constant-coefficient, scalar (one-factor) problem. In particular, we examine the case of a one-factor European call option using the assumptions for the original Black Scholes equation (see Clewlow and Strickland, 1998). We give an overview of the process.
1
P1: JYS c00 JWBK392-Duffy
2
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks
At the expiry date t = T the option price is known as a function of the current stock price and the strike price. The essence of the Monte Carlo method is that we carry out a simulation experiment by finding the solution of a stochastic differential equation (SDE) from time t = 0 to time t = T . This process allows us to compute the stock price at t = T and then the option price using the payoff function. We carry out M simulations or draws by finding the solution of the SDE and we calculate the option price at t = T . Finally, we calculate the discounted average of the simulated payoff and we are done. Summarising, the process is: 1. Construct a simulated path of the underlying stock. 2. Calculate the stock price at t = T . 3. Calculate the call price at t = T (use the payoff function). Execute steps 1–3 M times. 4. Calculate the averaged call price at t = T . 5. Discount the price found in step 4 to t = 0. We elaborate this process in the rest of this chapter. We first need to provide some background information.
0.3 ORDINARY DIFFERENTIAL EQUATIONS (ODE) We examine some simple ODEs. In general, the specification of an initial value problem (IVP) for an ODE is given by du + a(t)u = f (t), 0 < t ≤ T dt u(0) = A
(0.1)
We see that the IVP consists of a linear ODE with a corresponding initial condition A. The term f (t) is sometimes called the inhomogeneous forcing term. We note that all functions in system (0.1) are deterministic. We can find an exact solution to the system (0.1) by using the integrating factor method; in the case when the forcing term is identically zero the solution to (0.1) is given by: t a(s)ds u(t) = A exp −
(0.2)
0
ODEs can be used to model simple problems in quantitative finance, for example bond modelling where the interest rate r (t) is a deterministic function of time. If V is the price of the security, then it satisfies the terminal value problem (TVP) (Wilmott, Howison and Dewynne, 1995, page 267): dV + K (t) = r (t)V, dt V (T ) = Z
K (t) = coupon payment
(0.3)
We see that the solution is given at t = T . This is in contrast to system (0.1) where the value is given at t = 0 (we can reduce (0.3) to an initial value problem of the type (0.1) by using a
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
3
change of variables τ = T − t). We see that the solution of system (0.3) is given by: T T T V (t) = exp − r (s)ds Z+ K (y) exp r (s)ds dy
(0.4)
t
t
y
If we have a look at system (0.1) again we can see that it is possible to integrate it between times 0 and t: t t a(s)u(s)ds = f (s)ds, 0 < t ≤ T (0.5) u(t) − u(0) + 0
0
This is called a Volterra integral equation of the second kind and is given formally as: t a(s)u(s)ds = F(t) (0.6) u(t) + 0 t t f (s)ds + u(0) = f (s)ds + A where F(t) = 0
0
In this case the function a = a(s) plays the role of the kernel and the limit of integration t is variable.
0.4 STOCHASTIC DIFFERENTIAL EQUATIONS (SDE) AND THEIR SOLUTION We now generalise the deterministic equations that we introduced in section 0.3. In this case we add some random or stochastic terms to the ODE. To this end, we introduce notation that is used in texts on stochastic equations. In general, we denote dependence on time t for a stochastic process X as follows: X t ≡ X (t)
(0.7)
Both forms are used in the literature. We must be aware of each form because they are used in many places, including this book. Our first example of an SDE is d X t = a X t dt + bX t Wt a, b constant Wt = W (t) (one-dimensional Brownian motion)
(0.8)
In this case the equation describes the changes in the stochastic process X t . The constants a and b are called the drift and diffusion terms, respectively. Furthermore, we see the presence of the Wiener process Wt . We shall deal with these topics in more detail in later chapters. A more general SDE is d St = µ(t)St dt + σ (t)St dWt where
(0.9)
µ(t) is the drift coefficient σ (t) is the diffusion coefficient This is a model for the evolution of a stock in a certain time interval. Again, we note the presence of a Wiener process in the equation. We usually write the SDE in the ‘differential’
P1: JYS c00 JWBK392-Duffy
4
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks
form (0.9); we can also write the SDE in the integral form: t t St = S0 + µ(y)Sy dy + σ (y)Sy dW y 0
(0.10)
0
This equation characterises the behaviour of the continuous time stochastic process St as the sum of a Lebesgue integral and an Ito integral. A heuristic explanation of the SDE (0.10) is that the stochastic process St changes by an amount that is normally distributed. We say that the stochastic process is a diffusion process and is an example of a Markov process. When the drift and diffusion terms in system (0.9) are constant we can express the solution in analytic form: St = S0 exp((µ − 12 σ 2 ) t + σ Wt )
(0.11)
Finally, the values of the stochastic process at two different points are related by St+t = St exp((µ − 12 σ 2 )t + σ (Wt+t − Wt )) where t > 0 is arbitrary
(0.12)
You can check that this result is correct.
0.5 GENERATING UNIFORM AND NORMAL RANDOM NUMBERS We discuss the generation of random numbers. In particular, we generate random Gaussian numbers for the Wiener process appearing in equations (0.8) and (0.9). 0.5.1 Uniform random number generation Our starting point is the generation of numbers having a uniform distribution. To this end, let us suppose that X is a continuous random variable assuming all values in the closed interval [a, b], where a and b are finite. If the probability density function (pdf) of X is given by ⎧ 1 ⎨ b−a , a ≤ x ≤ b f (x) = (0.13) ⎩ 0, otherwise then we say that X is uniformly distributed over the interval [a, b]. A shorthand notation is to say that X is U (a, b). We generate uniformly distributed random numbers by using an algorithm that has been programmed in C or C++. We now introduce two methods that were popular a number of years ago. We include a discussion of them for historical and pedagogical reasons. We also introduced them in the context of the numerical solution of SDEs in Duffy (2004a). 0.5.2 Polar Marsaglia method This method uses the fact that if the random variable U is U (0, 1) then the random variable V defined by V = 2U − 1 is U (−1, 1). We now choose two variables defined by V j = 2U j − 1, U j ∼ U (0, 1),
j = 1, 2
(0.14)
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
5
Then we define W = V12 + V22 ≤ 1,
W ∼ U (0, 1)
We keep trying with different values until the above inequality is satisfied. Continuing, we define the intermediate value: Y = −2 log(W )/W Finally, the pair of values defined by N j = V j Y,
j = 1, 2
constittutes two standard normally (Gaussian) distributed random variables, and we are done. 0.5.3 Box-Muller method This method is based on the observation that if r and ϕ are two independent U (0, 1) random variables then the variables √ N1 = −2 log r cos(2π ϕ) (0.15) √ N2 = −2 log r sin(2π ϕ) are two independent standard Gaussian random variables. 0.5.4 C++ code for uniform and normal random variate generation Central to the accuracy of the Monte Carlo method is the ability to generate normal random variates. In this section we create C++ classes that compute these numbers. In general, we first generate uniform random variates and based on these variates we then generate the corresponding normal variates. We discuss these issues in more detail in Chapter 22. At this stage, however, we just need to use the corresponding generators. Please note that we use the authors’ classes for vectors and matrices (as described in Duffy, 2004a; Duffy 2006a). The abstract base class for uniform generators is class UniformGenerator { private: public: UniformGenerator(); // Initialisation and setting the seed virtual void init(long Seed) = 0; // Getting random structures (Template Method pattern) virtual double getUniform() = 0;// Number in range (0,1), variant Vector<double, long> getUniformVector(long N); // Invariant part
};
P1: JYS c00 JWBK392-Duffy
6
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks
Derived classes must implement the pure virtual functions for defining a seed and a single random number. For example, the generator for uniform random variate generation based on the rand() function is class TerribleRandGenerator : public UniformGenerator { // Based on the infamous rand(), that’s why it’s terrible private: double factor; public: TerribleRandGenerator(); // Initialise the seed, among others void init(long Seed_); // Implement (variant) hook function double getUniform(); };
We have defined other generators and the C++ code can be found on the CD. Continuing, the abstract base class for normal random variate generation is given by class NormalGenerator { protected: UniformGenerator* ug;
// This is a strategy object
public: NormalGenerator(UniformGenerator& uniformGen); // Getting random structures (Template Method pattern) virtual double getNormal() = 0; // Get a number in (0,1) Vector<double, long> getNormalVector(long N); NumericMatrix<double, long> getNormalMatrix(long N, long M); };
The code that generates a vector of normal random variates is // Getting random structures (Template Method Pattern) Vector<double, long> NormalGenerator::getNormalVector(long N) { // Invariant part Vector<double, long> vec(N); for(long i=vec.MinIndex(); igetUniform(); U2 = ug->getUniform(); W = sqrt( -2.0 * log(U1)); N1 = W * cos(tpi * U2); N2 = W * sin(tpi * U2); return N1; }
We give an example of use. First, we define a uniform random variate and then use this object to generate a normal random variate: // Based on rand() TerribleRandGenerator myTerrible; myTerrible.init(0); NormalGenerator* myNormal = new BoxMuller(myTerrible); Vector<double, long> arr2 = myNormal->getNormalVector(100); NumericMatrix<double, long> mat = myNormal -> getNormalMatrix(5, 6); delete myNormal;
Finally, here is an example using a numerical recipes (Press et al., 2002) algorithm: Ran1 myRan1; // This is a derived class myRan1.init(447); Vector<double, long> arrRan1 = myRan1.getUniformVector(20);
P1: JYS c00 JWBK392-Duffy
8
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks
0.5.5 Other methods The above methods are somewhat outdated. They have been superseded by other methods such as Mersenne-Twister and lagged Fibonacci generators and by methods for generating random numbers on multi-processor computers. We shall discuss these issues in more detail in later chapters.
0.6 THE MONTE CARLO METHOD In this section we describe the steps to price a one-factor option using the Monte Carlo method. We have already assembled the building blocks in the previous sections. We describe the algorithm and create working C++ code that computes pricing information for a simple one-factor model. There are several advantages associated with this approach. First, it is a concrete problem that we solve in detail while the simple software framework will be generalised to one based on design and system patterns in later chapters. We recall the SDE that describes the behaviour of a dividend-paying stock. The SDE is given by d St = (r − D)St dt + σ St dWt
(0.16)
where r = (constant) interest rate D = constant dividend σ = constant volatility dWt = increments of the Wiener process For the current problem it is possible to transform the SDE to a simpler one. To this end, define the variable: x t = log(St )
(0.17)
Then the modified SDE is described as d x t = νdt + σ dWt ,
1 ν ≡ r − D − σ2 2
(0.18)
We now discretise this equation by replacing the continuously-defined quantities d xt , dt and dWt by their discrete analogues. This gives the following discrete stochastic equation: xt = νt + σ Wt or
(0.19)
x t+t = xt + νt + σ (Wt+t − Wt ) Since xt = log(St ) we can see that equation (0.19) is equivalent to a discrete equation in the stock price St : St+t = St exp(νt + σ (Wt+t − Wt ))
(0.20)
In this case the Wiener increments have distribution N (0, t)
(0.21)
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
9
Formulae (0.19) and (0.20) constitute the basic path-generation algorithm: we calculate the value in equation (0.20) at a set of discrete mesh points: 0 = t0 < t1 < . . . < t N −1 < t N = T tn = nt, n = 0, . . . , N t = N /T Then equation (0.20) takes the more computationally attractive form: √ xtn = xtn−1 + νt + σ tn , n = 1, . . . , N where
(0.22)
n is a sample from N (0, 1) and Stn = exp(x tn ) The next step is to run the algorithm in equation (0.22) M times (M is called the number of simulations or draws); for each price of the stock at t = T we calculate the payoff function for a call option, namely: payoff = max(0, ST − K )
(0.23)
This formula gives the value of the payoff, and we are done, almost. Finally, we calculate the average call price over all call prices (evaluated at t = T ) and we take the discounted average of these simulated paths. Summarising, the basic algorithm for a call option is given by For each j = 1, . . . , M calculate C T, j = max(0, ST, j − K )
(0.24)
M 1
Cˆ = exp(−r T ) max(0, ST, j − K ) M j=1
(0.25)
and
Then Cˆ is the desired call price.
0.7 CALCULATING SENSITIVITIES The Monte Carlo method calculates the price of an option for a specific value of the underlying stock. In some applications we wish to calculate the derivative’s hedge sensitivities (also known as the Greeks). These quantities are the partial derivatives of the price with respect to one of the option’s parameters. Two of the most important ones are the delta and the gamma; in order to calculate these quantities we perturb the underlying price by a small amount and use centred finite difference schemes to approximate the derivatives. For example, the formulae for delta and gamma are δ=
C(S + S) − C(S − S) ∂C ≡ delta ∼ ∂S 2S
(0.26) ∂δ ∂ 2C δ(S + S) − δ(S − S) =
= = gamma ∼ ∂ S2 ∂S 2S In the above examples we have used centred-difference schemes to approximate the derivative. The approximations are second-order accurate if the security is sufficiently smooth.
P1: JYS c00 JWBK392-Duffy
10
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks
Failing that, we sometimes take first-order one-sided finite difference approximations (see Duffy, 2006a, for a discussion). We need values for sensitivities in order to manage risk. This is a major challenge for a Monte Carlo engine, from both a theoretical and a computational point of view. If we use finite difference methods, for example, we tend to get biased estimates (Glasserman, 2004). We discuss some of the issues when computing sensitivities and we examine how to compute the delta as a representative example. To this end, we deploy the Monte Carlo engine with initial estimates of S + S and S − S, where S is a small fraction of S. We thus have to run the engine twice and we use the computed values in equation (0.26). On a single-processor CPU we must run the engine twice whereas on multi-processor CPUs we can run the calculations in parallel. Performance is an important issue when developing Monte Carlo code and we shall discuss this topic in more detail in Chapters 24 and 25. The problems associated with estimating sensitivities in the Monte Carlo method and the associated techniques for approximating them are discussed in Part III.
0.8 THE INITIAL C++ MONTE CARLO FRAMEWORK: HIERARCHY AND PATHS Since this is a book on the Monte Carlo method, its mathematical foundations and its implementation in C++, we now discuss how to integrate these threads into a working C++ program. In order to reduce the scope we create the code that computes the price of a onefactor plain option. We exclude non-essential details from the discussion and we focus on those issues that will help the reader understand the ‘big picture’ as it were. To this end, we start with the design of the problem, which we have created using design patterns (we discuss these in more detail in Part II of this book) and documented using a UML (Unified Modeling Language) class diagram, as shown in Figure 0.1. Each box represents a class (this is usually an abstract base class) and it has a clearly defined responsibility; each class is assigned a code for convenience and it corresponds to one of the following activities:
r r r r
A1: Defining and initialising the SDE (class B). A2: Random number generator (RNG) (class D). A3: Approximating the solution of the SDE using finite differences (class C). A4: Displaying the results and statistics (in class A).
We have defined a sophisticated factory class E (called a builder) that is responsible for the creation of the other objects, inter-object links and data in the application. Each class in Figure 0.1 has services (in the form of member functions) that it offers to other classes (called clients) while each class uses the services of other classes (called servers). We describe the process for calculating an option price as follows: We model a nonlinear one-factor SDE that describes the behaviour of an underlying asset. We approximate its solution by discretising the SDE using a finite-difference scheme (FDM), for example the Euler method. The FDM class uses the services of the RNG class that is an implementation of a random number generator (this is needed for the Wiener increments). The control of the program is the responsibility of the Mediator. Finally, the output is the responsibility of the Datasim Excel visualisation driver.
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems A
11
E MC Mediator
FDM Builder
>
D B Random NumberGen
One FactorSDE
> C One FactorSDE Visitor
Figure 0.1 Top level class diagram for simple MC framework (including code names)
We now discuss classes B and C. These are the classes that model the various kinds of one-factor SDEs and the finite difference methods that approximate them, respectively. The class hierarchy for SDEs is shown in Figure 0.2; the derived classes are defined in terms of whether the drift and diffusion terms are linear or nonlinear. For example, for type D equations both terms are nonlinear. We mention that there are various ways to create class hierarchies. The interface for the base class SDE is given by class OneFactorSDE { private: double ic; // Initial condition Range<double> ran; // Interval where SDE ‘lives’ public: OneFactorSDE(); OneFactorSDE(double initialCondition, const Range<double>& interval)
One FactorSDE
SDE TypeA
Figure 0.2 SDE hierarchy
SDE TypeB
SDE TypeC
SDE TypeD
P1: JYS c00 JWBK392-Duffy
12
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks const double& InitialCondition() const; const Range<double>& Interval() const; double getExpiry() const; // Functional extensions (Visitor pattern, see Part II) virtual void Accept(OneFactorSDEVisitor& visitor) = 0;
};
You should understand the syntax of this code because this book assumes that you are already a C++ developer. We examine the type D class in this section. Its interface is given by class SDETypeD : public OneFactorSDE { // Nonlinear/nonlinear case private: // General function pointers double (*drift) (double t, double X); double (*diffusion) (double t, double X); public: SDETypeD() : OneFactorSDE(); SDETypeD(double initialCondition, const Range<double>& interval, double (*driftFunction) (double t, double X), double (*diffusionFunction) (double t, double X)); // Selector functions double calculateDrift (double t, double X) const; double calculateDiffusion (double t, double X) const virtual void Accept(OneFactorSDEVisitor& visitor); };
We instantiate this class by defining the initial condition, the interval in which the SDE is defined as well as its drift and diffusion functions. In this chapter we define this information in a namespace defined by namespace ExactSDE { // Known solution, dS = aSdt + bSdW double a; // Drift double b; // Diffusion double drift(double t, double X) { return a*X; }
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
13
One FactorSDEVisitor
FDMVisitor
Explicit Euler
Another Visitor
...
Crank Nicolson Milstein Derivative Free FRKI ...
Figure 0.3 FDM hierarchy
double diffusion(double t, double X) { return b*X; } } // End ExactSDE
We shall see how this information is used to instantiate a type D class. Turning to the finite difference schemes, we show the class hierarchy in Figure 0.3. We have implemented it as a Visitor design pattern (GOF, 1995) because this allows us to add new functionality to an SDE in a nonintrusive way. We discuss this pattern in more detail in Part II. The top-level abstract base class in Figure 0.3 has the interface: class OneFactorSDEVisitor { // Inline code private: public: // Constructors and Destructor OneFactorSDEVisitor() {} // Default constructor OneFactorSDEVisitor(const OneFactorSDEVisitor& source) {} virtual ˜OneFactorSDEVisitor() {} // The visit functions virtual void Visit(SDETypeA& sde)=0; //virtual void Visit(SDETypeB& sde)=0;
// Linear/Linear // L/NL (for reader)
P1: JYS c00 JWBK392-Duffy
14
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks //virtual void Visit(SDETypeC& sde)=0; virtual void Visit(SDETypeD& sde)=0;
// NL/L (for reader) // NL/NL
// Operators OneFactorSDEVisitor& operator = (const OneFactorSDEVisitor& source) {} };
The base class for all finite difference schemes has the interface class FDMVisitor : public OneFactorSDEVisitor { // Base class for all schemes //protected: public: // For convenience, ONLY // Initial conditions double initVal, VOld; // Solution at time level n+1 double VNew; // Mesh data (Vector is authors’ class) Vector<double, long> x; double k; // Time step double sqrk; // Square root of k (for dW stuff) // Result path Vector<double, long> res; // Random numbers Vector<double, long> dW; // Number of steps long N; public: FDMVisitor(long NSteps, const Range<double>& interval, double initialValue); FDMVisitor(long NSteps, const OneFactorSDE& sde); void SetRandomArray(const Vector<double,long>& randomArray); virtual Vector<double, long> path() const; long getNumberOfSteps() const; };
We can now define (many) specific finite difference schemes to approximate the various SDE types. We examine the explicit Euler scheme for convenience; its interface is defined by
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
15
class ExplicitEuler : public FDMVisitor { public: ExplicitEuler(long NSteps, const Range<double> & interval, double initialValue); ExplicitEuler(long NSteps, const OneFactorSDE& sde); void Visit(SDETypeA& sde); void Visit(SDETypeD& sde); };
The corresponding code file is // Euler Method ExplicitEuler::ExplicitEuler(long NSteps, const Range<double> & interval,double initialValue ) : FDMVisitor(NSteps, interval, initialValue) {
} ExplicitEuler::ExplicitEuler(long NSteps, const OneFactorSDE& sde) : FDMVisitor(NSteps, sde) {
} void ExplicitEuler::Visit(SDETypeA& sde) { VOld = initVal; res[x.MinIndex()] = VOld; for (long index = x.MinIndex()+1; index dW = myNormal->getNormalVector(N+1); delete myNormal;
// Create the basic SDE (Context class) double T = 1.0; cout > T; Range<double> ran (0.0, T);
P1: JYS c00 JWBK392-Duffy
18
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks Vector<double, long> x = ran.mesh(N); double ic = 1.0; // Choose the drift and diffusion functions // using namespace GenericNLDiffusion; using namespace ExactSDE; cout > a; cout > b; // Create the nonlinear SDE object SDETypeD sde(ic, ran, drift, diffusion); // Choose the FDM scheme (Visitor pattern) DerivativeFree visitor (N, ran, ic); // or Euler method . . . // Choose the array of N(0,1) numbers visitor.SetRandomArray(dW); // Calculate the FDM ‘path’ sde.Accept(visitor); Vector<double, long> result = visitor.path(); try { printOneExcel(x, result, string("Derivative Free"), string("time"), string("Underlying"), string("Value"));
// Abscissa array // // // //
The title of the chart The title of x axis The title of y axis Legend describing the line graph
} catch(DatasimException& e) { // Catch logical errors e.print(); } Vector<double, long> exactSolution = GBMRandomWalk(ic, a, b, T, N, dW); try { printOneExcel(x, exactSolution, string("Exact path solution"), string("time"), string("Underlying"), string("Value"));
// Abscissa array // // // //
The title of the chart The title of x axis The title of y axis Legend describing the line graph
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
19
} catch(DatasimException& e) { // Catch logical errors e.print(); } return 0; }
You can run this program to see the results. The output is presented in Excel. You can easily adapt the code to test other schemes, for example the Euler method.
0.9 THE INITIAL C++ MONTE CARLO FRAMEWORK: CALCULATING OPTION PRICE We now extend the results of section 0.8. In particular, we focus on:
r r r
Modelling option data and payoff functions. The structure of Monte Carlo algorithm. Initialising and creating the object network in Figure 0.1.
First, since we are interested in calculating option prices it is useful to encapsulate all relevant information in a structure. To this end, we define the structure: struct OptionData { // Option data + behaviour double double double double
K; T; r; sig;
double myPayOffFunction(double S) { // Call option
return max (S - K, 0); } };
All data and functions are public (by default). Second, the MCMediator class integrates all control and data flow in the application. Its internal structure and public interface reflect the UML class diagram in Figure 0.1: class MCMediator { private: FDMTypeDBuilder* bld; long NSim;
// Creates SDE and FDM objects // Number of simulations,for discounting
P1: JYS c00 JWBK392-Duffy
20
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks OptionData* opt; double (*payoff) (double S);
OneFactorSDE* sde; FDMVisitor* fdm; public: MCMediator(FDMTypeDBuilder& builder, long NSimulations, OptionData& optionData); double price() const; };
Here we see that this class has a member function price() for calculating the option price. We break the body of this function into logical blocks and we explain each block in turn:
r r r r
A: Loop over each iteration. B: Find value at t = T . C: Return the vectors and calculate payoff vectors and average. D: Discount the value.
We first need to define arrays, variables and other ‘work’ data structures: // The critical variables in the MC process double price; // Option price // Create the random numbers long N = fdm->getNumberOfSteps(); // The array of values of the payoff function at t = T Vector<double, long > TerminalValue(NSim, 1); // The vector of UNDERLYING values at t = T; Vector<double, long> result(N+1, 1); // Array of normal random numbers Vector<double, long> dW(N+1, 1); // Create a U(0,1) and N(0,1) array MSSecureRandGenerator myUniform; // .NET generator //TerribleRandGenerator myUniform; // rand() // OR YOUR FAVOURITE! myUniform.init(0); NormalGenerator* myNormal = new BoxMuller(myUniform); // Work variables double sqrT = sqrt(opt->T);
Step A involves calculating the paths based on the SDE and finite difference method that we have already discussed in section 0.8. We produce a vector TerminalValue of size NSim containing the values of the underlying stock at t = T :
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
21
// A. for (long i = 1; i Accept(*fdm); result = fdm->path(); // Size is N+1 // Now us this array in the payoff function TerminalValue[i] = result[result.MaxIndex()];
}
Step B involves the evaluation of the payoff function at t = T : // B. Calculate the payoff function for each asset price for (long index = TerminalValue.MinIndex(); index myPayOffFunction(TerminalValue[index]); }
Step C involves taking the average option price: // C. Take the average price = TerminalValue[TerminalValue.MinIndex()]; for (long ii = TerminalValue.MinIndex()+1; ii r * opt->T);
P1: JYS c00 JWBK392-Duffy
22
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Frameworks // Print out critical values cout NSimulations;
try { MCMediator mediator(fdmBuilder, NSimulations, callOption);
P1: JYS c00 JWBK392-Duffy
July 27, 2009
20:52
Printer: Yet to come
Monte Carlo Application One-Factor Problems
23
cout x} P(x1 < X ≤ x2 ) = P {ζ ∈ S : x1 < X (ζ ) ≤ x2 } We take the example from section 1.2.1 in order to define some random variables. We recall that this is a problem of tossing a coin three times. The complete sample space consists of eight sample points (a set with n elements had 2n subsets; this is called the power set) and we define X to be the r.v. that gives two heads returned. First, we define the event A to be X = 2. Thus, using our new notation we see that (Hsu, 1997) A = (X = 2) = {ζ ∈ S : X (ζ ) = 2} = {HHT, HTH, THH} In this case the sample points are equally likely (this means that they all have an equal probability of occurring), from which we can conclude that 3 8 Finally, let us consider the event B that is defined by X < 2. Then P(X = 2) = P( A) =
P(X < 2) = {ζ ∈ S : X (ζ ) < 2} = {HTT, THT, TTH, TTT} from which we can deduce that P(X < 2) =
1 4 = 8 2
P1: JYS c01 JWBK392-Duffy
34
July 27, 2009
11:24
Printer: Yet to come
Monte Carlo Frameworks
We have now finished the example. An important function in the context of random variables is the distribution function (also known as the cumulative distribution function or cdf ) of a r.v. defined by FX (x) = P(X ≤ x)
(1.3)
Much information concerning a random experiment described by a random variable is determined by the behaviour of its cdf. Finally, we can determine probabilities from the cdf, again basing the analysis on equation (1.3). Some examples are P(a < X ≤ b) = FX (b) − FX (a) P(X > a) = 1 − FX (a) P(X < b) = FX (b− ), where b− =
lim b −
(1.4)
0 GaussLegendre, 2 -> GaussLobatto, 3 -> Adaptive GaussLobatto"}, {"CallPut","1: Call 2: Put"} }; // The following is an explanation of the function // appearing in Excel’s function wizard XLRegistration::XLFunctionRegistrationHelper
P1: JYS c16 JWBK392-Duffy
456
August 7, 2009
18:35
Printer: Yet to come
Monte Carlo Frameworks registerHeston_Price("xlHeston_Price", "Heston_Price", "Evaluates European Calls/Puts within a Heston model", LibraryName, Heston_PriceArgs, "RRRRRRRRRRRR" );
}
All the code has been placed into an unnamed namespace to avoid any confusion during the linking phase. The last line needs explanation. It specifies the data types using a code which is • R for LPXLOPER by reference • P for LPXLOPER by value • B for double In the current distribution of XLW only R and P are used. Next, since the XLW framework uses the C API, we have to provide the function to be exported with the extern "C" statement as a C linkage: extern "C" { // Input from Excel used to convert and put into C++ function LPXLOPER EXCEL_EXPORT xlHeston_Price(LPXLOPER xlTime_, LPXLOPER xlStrike_, LPXLOPER xlSpot_, LPXLOPER xlRate_, LPXLOPER xlDividend_, LPXLOPER xlvInst_, LPXLOPER xlvLong_, LPXLOPER xlKappa_, LPXLOPER xlRho_, LPXLOPER xlOmega_, LPXLOPER xlMethod_, LPXLOPER xlCallPut_) { EXCEL_BEGIN; if (XlfExcel::Instance().IsCalledByFuncWiz()) return XlfOper(true); // Transform XlfOper to standard or custom data types // used with the function to compute XlfOper xlTime(xlTime_); double Time(xlTime.AsDouble("Time")); XlfOper xlStrike(xlStrike_); double Strike(xlStrike.AsDouble("Strike")); XlfOper xlSpot(xlSpot_); double Spot(xlSpot.AsDouble("Spot")); XlfOper xlRate(xlRate_); double Rate(xlRate.AsDouble("Rate")); XlfOper xlDividend(xlDividend_); double Dividend(xlDividend.AsDouble("Dividend")); XlfOper xlvInst(xlvInst_); double vInst(xlvInst.AsDouble("vInst")); XlfOper xlvLong(xlvLong_); double vLong(xlvLong.AsDouble("vLong")); XlfOper xlKappa(xlKappa_); double Kappa(xlKappa.AsDouble("Kappa")); XlfOper xlRho(xlRho_);
P1: JYS c16 JWBK392-Duffy
August 7, 2009
18:35
Printer: Yet to come
Affine Stochastic Volatility Models
457
double Rho(xlRho.AsDouble("Rho")); XlfOper xlOmega(xlOmega_); double Omega(xlOmega.AsDouble("Omega")); XlfOper xlMethod(xlMethod_); double Methoda(xlMethod.AsDouble("Methoda")); int Method(static_cast(Methoda)); XlfOper xlCallPut(xlCallPut_); double CallPuta(xlCallPut.AsDouble("CallPuta")); int CallPut(static_cast(CallPuta)); // Compute the Price using C++ function double result(exp(-(Rate-Dividend)*Time)* Heston_Price(CallPut,Time,Strike,Spot,Rate,Dividend, vLong,vInst,Kappa,Rho,Omega,Method)); return XlfOper(result); EXCEL_END } }
The code starts with the macro EXCEL BEGIN which uses the class XlfExcel as follows: #define EXCEL_BEGIN XlfExcel::Instance().FreeMemory();\try\{..}
EXCEL BEGIN initialises the library and frees all memory previously allocated by the framework. Then it attempts to execute the commands following the try statement until EXCEL END. The latter statement is for error handling. Another macro which is used in the code above is #define EXCEL_EXPORT __declspec(dllexport)
This line of code tells the compiler that the function is to be exported. To start up Excel and use your own spreadsheet for testing purposes and debugging Visual Studio offers a method to attach arguments on the current projects using the project settings. In our example we start Excel and supply the objects StochasticVol.xll and StochasticVol.xls. After that we choose the settings for debugging and add the path where Excel is located on the machine as well as the arguments.
16.10 SUMMARY AND CONCLUSIONS We discussed two state of the art stochastic volatility models, namely the Heston and Bates models. After discussing their mathematical properties we gave a detailed description for implementing the models. The methods can then be applied to price all kinds of options on one underlying. We considered simple call options for benchmarking the algorithm as well as options depending on the volatility skew such as digital and cliquet options. Together with the results in Chapter 23 the reader may build up a whole pricing library for exotic equity and index options. In the second part of this chapter we described how to use the XLW framework to create add-ins to be used with Microsoft Excel. Such add-ins, called xll, are special types of a simple dll. The first step in the development of an xll is to program the function you want to use in C++. In the second step you use the interface generator to create the files to your project which can be compiled into an xll.
P1: JYS c16 JWBK392-Duffy
458
August 7, 2009
18:35
Printer: Yet to come
Monte Carlo Frameworks
We have shown all the steps necessary to cope with putting your own functions to work and use proprietary data types within the XLW framework. Finally, we provided a detailed example for computing prices of European call and put options within the stochastic volatility models proposed by Heston and Bates. Such functionality is then the starting point for an application for pricing and calibration.
16.11 EXERCISES AND PROJECTS 1. (****) Improving the QE Scheme Implement the improvement on the standard QE scheme as described in this chapter. The details can be found in Andersen (2006) . The improvement is for small values of the variance. It involves changing the second case of the switching rule in the QE scheme. Therefore, the algorithm stays the same if
≤ c but differs in the case > c . Suppose you wish to generate the value Vˆ (t + ) given Vˆ (t). We consider the second case of the switching rule. To this end we denote the time step by and replace the inverse given in equation (16.10) by first defining the constants: 4κ exp(−κ) − exp(−κ)) exp(−κ) k= (1 − exp(−κ)) 4κ d = 4κθω2 4κ exp(−κ) λ = Vˆ (t) 2 ω (1 − exp(−κ)) d + 2λ c= d +λ d +λ −1 q= d +λ n=
ω2 (1
Using this set of definitions we compute
(q + 1)(3q + 4) 2 q +2 (q + 1)(3q + 4) q + 1 k1 = q 2 −2 − 4(q + 1)(q + 2) q +2 (q + 2)2 2q 2 k2 = (q + 3)(q + 2)2
k0 = 2
And finally y=
−k1 −
k12 − 4k2 k0
2k2 c1 = (1 − y)(q + 1)(−q)−(q+1)
P1: JYS c16 JWBK392-Duffy
August 7, 2009
18:35
Printer: Yet to come
Affine Stochastic Volatility Models
β=
2q + 2 −
459
−1 c1 (−q)q+2 y −1 + q q +2
c2 = yβ exp(−βq) In the refined version of the algorithm random number generation is realised as follows: ⎧ (q + 1)u 1/(q+q) ⎪ ⎨ , 0 ≤ u ≤ uc c1 H −1 (u) = ⎪ ⎩ −β −1 log exp(βq) − u−u c , u < u < 1 c c2 2.
3.
4.
5.
6.
c1 (−q)q+1 with u c = q+1 (**) Martingale Correction Implement the martingale correction method as described in section 16.3.4. Compare the results of the original QE scheme with the martingale corrected version. (**) Options Study other volatility-dependent options. A good example is a digital cliquet option. Digital cliquet options with yearly reset pay an amount of money, for example 1 or S(tn ) − S(tn−1 ) n) if the performance, S(tS(tn−1 , is bigger than 1. We therefore consider the payoff 1{S(tn+1 )>S(tn )} , ) respectively (S(tn+1 ) − S(tn )) · 1{S(tn+1 )>S(tn )} . (**) Moment-Matched Euler Scheme The moment-matched Euler scheme uses the following discretisation of the variance: + 1 − exp(−2κn ) vn+1 = vn + κ(θ − vn )n + ξ vn n Z n (16.20) 2κ Account for the moment-matched version of the Euler scheme by implementing this scheme into the Monte Carlo simulation framework and compare the results to the simple Euler, the fully truncated Euler and the QE scheme. (****) Monte Carlo and XLW We have set up several methods for applying the Monte Carlo method. We wish to make the method available in Excel. To this end we use the XLW framework. There are a number of steps to achieve this: – Think about the Excel interface. What are the input parameters? Necessary inputs are the numbers of simulations or the seed of the random number generator. Do you wish to make the model or the scheme a parameter? – Do you need data structures that must be made available to the XLW framework? If this is the case we have to set them up in the declaration files. – Make sure your C++ code compiles. Then, use the interface generator to create an interface. – Edit the generated file. For example, you may wish to display more information when the user invokes the function using Excel’s function manager. – The final step is to test the new functionality using your function for Monte Carlo simulation. (***) Boost and XLW Take a new class not currently available within the XLW framework: for example, some of the Boost classes for statistical distributions, multi-array or special functions. Make the class known to the XLW framework by following the steps used to handle the NumericMatrix class. Use the interface generator to create your add-in. You can use the code from the CD corresponding to Chapters 4 and 13. Use the add-in to display convergence tables or compute the prices using different parameter settings.
P1: JYS c16 JWBK392-Duffy
August 7, 2009
18:35
Printer: Yet to come
460
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
17 Multi-Asset Options 17.1 INTRODUCTION AND OBJECTIVES The Monte Carlo method is the method of choice for multi-dimensional problems. For high dimensional problems finite difference methods or trees become unmanageable from a computational point of view. The old rule of thumb ‘if the dimension of the underlying problem is greater than 3 then use Monte Carlo’ describes the way of thinking. Financial applications – for example, basket option modelling – may involve many underlying assets. To this end we start this chapter by introducing derivatives depending on more than one underlying. We define spread options and quanto options. Such options are popular, for instance options on equity baskets. We are able to benchmark our implementation since there exist analytic approximation formulae. The data structure is very important for the implementation of multi-asset models. On the one hand it could be designed to be very flexible, allowing for parameter lists that are initialised at run-time, and on the other hand the data could be hard coded, for example a Vector<double> that stores the volatilities. To combine flexibility with stability we have chosen to model member data as property sets. We discuss a range of options in detail and we give several examples on how to code them using our instrument hierarchy developed in Chapter 14. Thus, the main objective of this chapter is to introduce types of options involving risk from several risk factors and their implementation in C++. We give numerical results and supply several figures to illustrate characteristics of the option worked out using our Monte Carlo framework.
17.2 MODELLING IN MULTIPLE DIMENSIONS First, we model multi-asset options in a Black-Scholes framework in order to be able to benchmark our implementation with analytic approximation formulae. We later consider more complex models including stochastic volatilities and stochastic rates. For the multi-asset Black-Scholes model, we consider d correlated Brownian motions Wi (t), i = 1, . . . , d for the d underlying assets with spot prices Si (t) and constant volatilities σi , dividend yields di and correlations (ρi j )1≤i, j≤d . The constant risk-free rate is assumed to be r . In the basic setting the rate is the same for all assets because we assume the assets trade in the same market. Later, when we consider quanto options, the risk-free rate differs since the asset trades in another market. The SDE is given by d Si (t) = (r − di )Si (t)dt + σi Si (t)dWi (t), , 1≤i ≤d (17.1) Si (0) = si For options on multiple assets there are closed form pricing formulae available and for other option types we can use approximation formulae. A rule of thumb is to use Monte Carlo valuation for options depending on more than three assets. If we consider path-dependent options it might be the only applicable method.
461
P1: JYS c17 JWBK392-Duffy
462
July 28, 2009
18:10
Printer: Yet to come
Monte Carlo Frameworks
In order to gain an intuition for the influence of correlation we consider a basket option and a min/max option. For these options we give the modelling in C++ in sections 17.5 and 17.6. The payoff for the first type of option is determined by two risk factors. Increasing the dispersion of the individual assets leads to higher prices since the chance of any asset reaching high values gets bigger. This effect increases with declining correlation. The payoff of a basket option is determined by a weighted sum of the basket components. The influence of dispersion is marginal. The correlation of the assets effects the overall volatility of the basket and thus is one of the main drivers for the price. We mainly observe two impacts of dependencies among the individual assets: • The influence of correlation on the volatility of a basket option. • The influence of correlation on the dispersion of individual assets of a basket. These factors influence the hedging positions in the corresponding options. The reader can use our code to examine the effects and their influence on hedging portfolios respectively. First, we have to set up a model to support multiple dimensions. For example, we model a multi-dimensional Black-Scholes set-up, (17.1), as class MCBlackScholesMulti : public NFactorModel
{ public: MCBlackScholesMulti(); MCBlackScholesMulti(Vector<double> r, Vector<double> d, Vector<double> sigma, NumericMatrix<double> Corr, double Maturity, Vector<double> Spot); virtual MCBlackScholesMulti(); // Get functions Vector<double> getdrift() const; Vector<double> getvol() const; NumericMatrix<double> getcorr() const; Vector<double> getdividend() const; Vector<double> getmartcorrection() const; double getmaturity() const; Vector<double> getspot() const; int getfactors() const;
private: Vector<double> drift; // Vector<double> vol; // NumericMatrix<double> corr; // Vector<double> martcorrection; Vector<double> dividend; // double maturity; // Vector<double> spot; // int factors; // };
Vector of Drifts Vector of Volatilities Correlation Matrix // Martingale Correction Vector of Dividends Maturity Vector of Spot Prices Number of Factors
We define the vector for the multiple spots that represent the outcome of the simulation Vector > ST(Path). Furthermore, we need an object
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
Multi-Asset Options
463
holding the Gaussians for each simulation step. This is realised by defining the object NumericMatrix<double> W(Factors, Steps). Before starting the algorithm we compute constants: // Precalculate the drift and diffusion constants Vector<double> sigmasigma(sigma.Size()); for(int i =sigma.MinIndex(); i rdh = (r-d-0.5* sigmasigma)*h; Vector<double> sdh = sigma * sqrt(h);
Then, the algorithm for the multi-dimensional exact solution is given by for(int i = minindex Sims; i PayOffType = "call"; static Wrapper<std::string> Type = "max"; Vector<double> weights (5); for(long i=weights .MinIndex(); i Weights = weights ; mc myset multi.add("Strike", &Strike); mc myset multi.add("PayOffType", &PayOffType); mc myset multi.add("Weights", &Weights);
// add properties // add properties // add properties
P1: JYS c17 JWBK392-Duffy
464
July 28, 2009
18:10
Printer: Yet to come
Monte Carlo Frameworks mc myset multi.add("MinMax",&Type);
// add properties
// Specify the name of payoff used for registration with the factory string mc name multi = "minmax"; // Create a pointer to the payoff for Multi Factor PayOff<double, NumericMatrix<double> >* minmaxptr = PayOffFactory<double, NumericMatrix<double> >:: Instance().CreatePayOff(mc name multi, mc myset multi); // Define the parameters for your assets and for the option double Maturity = 2.0; Vector<double> Spot(5); Spot[1]=10.0; Spot[2]=10.0; Spot[3]=10.0; Spot[4]=10.0; Spot[5]=10.0; Vector<double> r(5); r[1]=0.03; r[2]=0.03;r[3]=0.03;r[4]=0.03;r[5]=0.03; Vector<double> d(5); d[1]=0.0;d[2]=0.0;d[3]=0.0;d[4]=0.0;d[5]=0.0; Vector<double> sigma(5); sigma[1]=0.3303; sigma[2]=0.3126; sigma[3]=0.3212;sigma[4]=0.269; sigma[5]=0.2648; NumericMatrix<double> corr(5,5); corr(1,1)=1; corr(1,2)=0.4417; corr(1,4)=0.4366; corr(1,5)=0.4524; corr(2,1)=0.4417; corr(2,2)=1; corr(2,4)=0.3922; corr(2,5)=0.4051; corr(3,1)=0.4307; corr(3,2)=0.3549; corr(3,4)=0.3586; corr(3,5)=0.3999; corr(4,1)=0.4366; corr(4,2)=0.3922; corr(4,4)=1; corr(4,5)=0.4713; corr(5,1)=0.4524; corr(5,2)=0.4051; corr(5,4)=0.4713; corr(5,5)=1;
corr(1,3)=0.4307; corr(2,3)=0.3549; corr(3,3)=1; corr(4,3)=0.3586; corr(5,3)=0.3999;
// Define the Timer DatasimClock myclock; // Define the model MCBlackScholesMulti MCBS(r, d, sigma, corr, Maturity, Spot); // Define the scheme MCExactGeoBrownianMulti, MCBlackScholesMulti> MCE;
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
Multi-Asset Options
465
// Define the Monte Carlo object MCMonteCarlo> mc; // Define the path Vector> mc path multi; // The variable for outputting mean and standard deviation Vector<double> mcvalue(2); mcvalue[1] = 0.0; mcvalue[2] = 0.0; int NoOfBatches = 10; long NoOfPaths = 100; long Timesteps = 1; unsigned long Seed = 123456;
// // // //
Batches Paths per batch Number of grid points The Seed
RandGen<MersenneTwister> rangen(Seed); myclock.start(); // Start // The main Monte Carlo engine for(int i = 1; i PayOff Spread Properties; private: // No private data
};
P1: JYS c17 JWBK392-Duffy
468
July 28, 2009
18:10
Printer: Yet to come
Monte Carlo Frameworks Table 17.1 Numerical results for spread option pricing using Monte Carlo and antithetic sampling I
II
III
call 101.5 100.0 3% 20% 16% 0% 0% −0.9 0.5
put 101.5 100.0 3% 20% 16% 0% 0% −0.9 0.5
call 102 99 3% 20% 16% 1% 2% 0.5 1.0
14.553 14.6128 (0.070453) 14.5451 (0.0496918)
13.5382 13.4482 (0.0644618) 13.5353 (0.0457415)
8.8295 8.8402 (0.0404852) 8.83034 (0.028615)
Type Spot 1 Spot 2 r σ1 σ2 d1 d2 ρ Strike Approx. Price MC Price MC Price (Anti)
The following code is for registering the payoff to the unnamed namespace of the file PayoffRegistration.cpp: PayOffConstructor<double, NumericMatrix<double>, PayOff Spread> RegisterSpread("spread");
Let us state some numerical results for the spread option case. We have applied our framework to pricing spread options using 10 000 paths and with antithetic sampling. The results are summarised in Table 17.1. Other examples can be studied using our analytical approximation for spread options. The reader may wish to apply other models for the asset price dynamics to price spread options. 17.4.3 Quanto options Quanto options serve as a good test case because an analytical solution using the Black-Scholes framework is available. Assume a European bank acquires a European call option on a share quoted in a foreign currency, for example in dollars ($). The bank does not want any exposure in $. The premium of the option should be paid in the domestic currency, for example euro (€). The value of the option should furthermore not be exposed to the exchange rate dollar against euro ((FX) $/€). This contract is known as a Quanto option. We have the following two factor model: d S(t) = r f dt + σ S dW1 (t) S(t)
(17.3)
S(0) = s0 d F(t) = rd dt + σ F dW2 (t) F(t) F(0) = f 0
(17.4)
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
Multi-Asset Options
469
with correlated Brownian motion (W1 , W2 ). The drift is determined by rd (the domestic currency rate) and r f (the foreign currency rate). The volatility of the exchange rate is denoted by σ F . The price process starts at the spot s0 and with an initial exchange rate of f 0 . Thus, we simulate two risk factors and then take the payoff: F(T )(S(T ) − K )
(17.5)
The analytical solution to the problem, the so-called quanto adjustment, can be directly applied via a Black-Scholes type formula. First, we have to derive the inputs d1 and d2 supplied to the cumulative normal distribution function. The C++ code is double d1 = + + double d2 =
(log(Spot / Strike) (r f - d - rho * sigma * sigma fx sigma*sigma / 2.0) * T) / (sigma * sqrt(Mat)); d1 - sigma * sqrt(Mat);
if(payofftype == "call") result = rate fx * (Spot * exp((r f - r d - d - rho * sigma * sigma fx) * Mat) * CumulativeNormal(d1) - Strike * exp(-r d * Mat) * CumulativeNormal(d2)); else result = rate fx * (Strike * exp(-r d * Mat) * CumulativeNormal(-d2) - Spot * exp((r f - r d - d - rho * sigma * sigma fx) * Mat) * CumulativeNormal(-d1)); return result;
17.5 BASKET OPTIONS Basket options are options where the underlying is a portfolio of assets. We consider a portfolio of d assets Si (t), i = 1, . . . , d. This portfolio is determined by the weight ωi of each asset. We denote the price of the portfolio at time t by B(t). Thus, we have B(t) =
d
ωi Si (T )
(17.6)
i=1
Using the portfolio as the underlying we consider options on this portfolio. The simplest one is a European call option given by the payoff: d max(B(T ) − K , 0) = max ωi Si (t) − K , 0 (17.7) i=1
The only thing which changes is that we have to collect a vector of weights from the corresponding property set. To this end we declare a wrapper object, already defined in Chapter 14, as follows: Wrapper >* result Vector;
P1: JYS c17 JWBK392-Duffy
470
July 28, 2009
18:10
Printer: Yet to come
Monte Carlo Frameworks
This can be used to retrieve the data computed for the present value calculation which is given by double PayOff Basket::operator()(double Discount, NumericMatrix<double>& Spot) const
{ // Defining all the objects necessary for this PayOff double strike; Vector<double> weights; std::string paytype; AnyType* anytype; Wrapper<double>* result double; Wrapper<std::string>* result string; Wrapper >* result Vector; double WeightedSpot=0.0; double result; // Starting to initialise the data anytype = PayOff Basket Properties.value("Strike"); result double = dynamic cast<Wrapper<double>*> (anytype); strike = (*result double).GetObj(); anytype = PayOff Basket Properties.value("PayOffType"); result string = dynamic cast<Wrapper<std::string>*> (anytype); paytype = (*result string).GetObj(); anytype = PayOff Basket Properties.value("Weights"); result Vector = dynamic cast<Wrapper >*> (anytype); weights = (*result Vector).GetObj(); for(int i = Spot.MinRowIndex(); i& Spot) const
{ // Defining all the objects necessary for this PayOff double strike; double MinMax; std::string paytype; std::string minmax; AnyType* anytype; Wrapper<double>* result double; Wrapper<std::string>* result string; double result; // Starting to initialise the data anytype = PayOff MinMax Properties.value("Strike");
0%
1%
2%
3%
4%
5%
6%
7%
8%
NoOfAssets=3
Probability
0%
1%
2%
3%
4%
5%
6%
NoOfAsset=2 NoOfAssets=5
NoOfAsset=1 NoOfAssets=4
Value
Distribution of Maximum of Correlated Assets
ts NoOfAssets=3
NoOfAssets=5
NoOfAssets=4
NoOfAsset=1
NoOfAsset=2
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3
NoOfAsset=2
NoOfAsset=1
Value
NoOfAssets=3
Figure 17.1 Distribution for the maximum for 1 to 5 assets with mainly negative, zero and mainly positive correlation structure
NoOfAsset=2
NoOfAssets=5
NoOfAsset=1
20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
NoOfAssets=4
Value
NoOfAsset=1
NoOfAsset=2
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3
m Nu
7% Probability 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
7% 6% 5% 4% 3% 2% 1% 0% sse
fA
8%
ts
9% 8%
sse
ber o
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3 NoOfAsset=1
NoOfAsset=2
Distribution of Maximum of Correlated Assets
m Nu
Probability
20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
of A
Distribution of Maximum of Correlated Assets
m Nu
18:10
ber
sse fA
472
July 28, 2009
ber o
P1: JYS c17 JWBK392-Duffy Printer: Yet to come
ts
NoOfAsset=2
NoOfAssets=5
NoOfAssets=4
Value
0%
2%
4%
6%
8%
10%
12%
NoOfAssets=3
0%
2%
4%
6%
8%
NoOfAsset=2 NoOfAssets=5
NoOfAsset=1 NoOfAssets=4
Value
NoOfAssets=3
NoOfAsset=1
NoOfAsset=2
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3
NoOfAsset=2 NoOfAssets=5
NoOfAssets=4
Value
NoOfAsset=1
Distribution of Maximum of Correlated Assets
20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
NoOfAsset=1
NoOfAsset=1
NoOfAsset=2
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3
ts
Probability
NoOfAssets=3
Figure 17.2 Distribution for the minimum for 1 to 5 assets with mainly negative, zero and mainly positive correlation structure
0%
2%
4%
6%
8%
m Nu
10% Probability 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
10%
sse
fA ber o
12%
ts
12%
sse
14%
NoOfAsset=1
NoOfAsset=2
NoOfAssets=5 NoOfAssets=4 NoOfAssets=3
m
Distribution of Maximum of Correlated Assets
m Nu
Probability
20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 > 335
fA
18:10
ber o
July 28, 2009
Nu
Distribution of Maximum of Correlated Assets
sse ber of A
P1: JYS c17 JWBK392-Duffy Printer: Yet to come
473
ts
0%
Max
120
110
Value
130
90
230
150
220
160 170
0%
2%
4%
6%
8%
70
210
200
190
180
20 30 40 50 60
Max
Value
Min
140
Min Max
150 Min
220
210
200
190
180
170
160
140
130
120
110
100
90
70 80
50 60
20 30 40
Min Max
Figure 17.3 Distribution for the minimum and the maximum for 5 assets with mainly negative, zero and mainly positive correlation structure
Probability
10%
80 90
Distribution of the Maximum and the Minimum of a Basket with 5 Assets 12%
> 335 100
Min
110
Max
Min Max
120
Value
Probability 130
0%
2%
140
2%
4%
150
4%
6%
160
6%
8%
170
8%
10%
20 30 40 50 180
10%
60 190
Probability
12%
200
12%
230
Distribution of the Maximum and the Minimum of a Basket with 5 Assets
> 335
Distribution of the Maximum and the Minimum of a Basket with 5 Assets
70 80 210
14%
100
220
18:10
230
474
July 28, 2009
> 335
P1: JYS c17 JWBK392-Duffy Printer: Yet to come
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
Multi-Asset Options
475
result double = dynamic cast<Wrapper<double>*> (anytype); strike = (*result double).GetObj(); anytype = PayOff MinMax Properties.value("PayOffType"); result string = dynamic cast<Wrapper<std::string>*> (anytype); paytype = (*result string).GetObj(); anytype = PayOff MinMax Properties.value("MinMax"); result string = dynamic cast<Wrapper<std::string>*> (anytype); minmax = (*result string).GetObj(); MinMax = Spot(Spot.MinRowIndex() ,Spot.MaxColumnIndex()); if(minmax == "min") for(int i = Spot.MinRowIndex(); i >
{ public: // Default constructor PayOff Altiplano(); // User constructor PayOff Altiplano(const SimplePropertySet<string,AnyType*>& pset); virtual PayOff, NumericMatrix<double> >* clone() const; virtual double operator()(Vector<double> Discount, NumericMatrix<double>& Spot) const; virtual double PayOff Value(Vector<double> Discount, NumericMatrix<double> Spot, Vector<double>& Strike) const; virtual ∼ PayOff Altiplano(){} SimplePropertySet<string, AnyType*> PayOff Altiplano Properties; private: // No private data
}; The evaluation operator for our example is given by
P1: JYS c17 JWBK392-Duffy
July 28, 2009
18:10
Printer: Yet to come
Multi-Asset Options
479
double PayOff Altiplano::operator()(Vector<double> Discount, NumericMatrix<double>& Spot) const
{ // Defining all the objects necessary for this PayOff AnyType* anytype; Wrapper<std::string>* result string; Wrapper >* result Vector; Wrapper* result int; Wrapper<double>* result double; // Starting to initialise the data // Example for string anytype = PayOff Altiplano Properties.value("PayOffType"); result string = dynamic cast<Wrapper<std::string>*> (anytype); std::string paytype = (*result string).GetObj(); // Example for Vector<double> anytype = PayOff Altiplano Properties.value("Weights"); result Vector = dynamic cast<Wrapper >*> (anytype); Vector<double> weights = (*result Vector).GetObj(); // Example for int (barrier1, barrier2) anytype = PayOff Altiplano Properties.value("barrier1"); result int = dynamic cast<Wrapper*> (anytype); int barrier1 = (*result int).GetObj(); // Example for double (coupon1, coupon2, level1, level2) anytype = PayOff Altiplano Properties.value("coupon1"); result double = dynamic cast<Wrapper<double>*> (anytype); double coupon1 = (*result double).GetObj();
double coupon = 0.0; Vector<double> Spots(Spot.MaxColumnIndex()Spot.MinColumnIndex()+1); for(int i = Spot.minindex Factors; i 0. We already computed the derivative with respect to the spot price s0 . To implement this sensitivity we have to implement another payoff. Therefore, the implementation of the class is essentially the same as for a payoff: class PW Greeks Call Delta : public PayOff<double, double>
{ public: PW Greeks Call Delta(); PW Greeks Call Delta(const SimplePropertySet <string,AnyType*>& pset); virtual PayOff<double, double>* clone() const; virtual double operator()(double Discount, double Spot) const; virtual double PayOff Value(double Discount, double Spot, double Strike) const; virtual PW Greeks Call Delta() SimplePropertySet<string, AnyType*> PW Greeks Call Delta Properties; private: // No private data nor member functions };
The code for calculating the delta is double PW Greeks Call Delta::operator()(double Discount, double& Spot) const
{ double strike; double startspot; std::string paytype; if(paytype == "call") if(Spot > strike) return Spot / startspot; else return 0; else if(Spot < strike) return - Spot / startspot; else return 0.0;
};
P1: JYS c18 JWBK392-Duffy
496
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks
We now consider the pathwise estimator with respect to the implied volatility σBS , the vega of the option. It is given by 2 S(T ) σBS −1 GreekPW log − r + = exp(−r T )σ (18.19) T S(T )1{S(T )>K } BS σBS s0 2 Example: Black-Scholes Asian call The same procedure can be applied to compute estimates for path-dependent options. We show how to adapt the implementation of the operator () to cover arithmetic Asian options. To compute the Greeks with respect to the spot and the implied volatility σBS we implement the formulae: ¯ ) S(T 1{ S(T (18.20) GreekPW ¯ )>K } s0 = exp(−r T ) s0 N 2 S(ti ) σBS 1 log − r + = exp(−r T ) T (18.21) GreekPW σBS σBS N i=1 s0 2 ¯ )1{ S(T · S(T ¯ )>K }
(18.22)
To this end we pass parameter values to the operator (). This can be done using the SimplePropertySet. For example, we wish to add the volatiliy to a given property set. We use the key ‘Volatility’ together with a pre-defined variable vol which is of type double: Property<string,AnyType*> ("Volatility", vol)
We can use σBS to calculate vega which is done as follows: double PW Greeks ArithAsian Vega::operator()(double Discount, Vector<double>& Spot) const
{ double strike, startspot, maturity, vol, r; long NumberOfSpots; double Average = 0.0; double vega = 0.0; // Declaration of the variables as done for Payoffs... for(long i=0; i strike)
{ for(size t j = 1; j K } S2 (0) 2
(18.23)
GreekPW S2 (0) = exp(−r T )
S1 (T ) 1{S (T )−S1 (T )>K } S1 (0) 2
(18.24)
We leave the implementation as an exercise for the reader.
18.4 THE LIKELIHOOD RATIO METHOD The likelihood ratio method is based on score functions for a given model. The score function is a function that is multiplied with the payoff of the option such that the Greek can be represented by GreekLR (φ) := E[h(S(φ))ω(φ, S(φ))]
(18.25)
ω(·, ·) is the score function. The corresponding Monte Carlo estimator is given by N 1 LR h(S(φ)i )ω(φ, S(φ)i ) Greek (φ) := N i=1
(18.26)
To apply the likelihood ratio method we need additional information about the model, namely we must have an expression for the score function. The likelihood ratio method (18.26) is an unbiased estimator for the Greek. The likelihood ratio method can be used to compute Greeks for options with discontinuous payoff functions because the derivative of the payoff function is not needed. To see why discontinuous payoffs cause no problems we show how the integration by parts formula is applied. The basic idea is to shift the derivative operator from the payoff function to the density of the probability measure which in most cases is sufficiently smooth to apply the derivative operator. Several authors have studied the likelihood ratio method in a very general setting. It can be seen as an application of the calculus of variation on path space or Malliavin calculus. The key observation is that by using this calculus, an analogue to the integration by parts formula can be derived and the score function is a Skorohod integral, which can be approximated by simulation. In this book we do not cover the theory of Malliavin calculus. We give an introduction to likelihood ratio methods and a finite difference implementation of it. An introduction to Malliavin calculus and the Skorohod integral is given in Nualart (1995).
P1: JYS c18 JWBK392-Duffy
498
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks
To introduce the underlying mathematics we give a basic example which only uses the integration by parts formula from ordinary calculus. We work within the Black-Scholes model. Then, the measure of logarithmic returns is normally distributed and the calculations can be carried out explicitly. We start with the integration by parts. For differentiable functions f, g : R → R the integration by parts formula is the following relationship: b b f (s)g(s)ds + f (s)g (s)ds (18.27) f (b)g(b) − f (a)g(a) = a
a
Writing the expectation E[h(S(T ))] as an integral and denoting the density by ϕ, the expectation can be derived by E [h(ST )] = h(s)ϕ(φ, s)ds (18.28) The payoff function h and therefore the density ϕ depend on model parameters. Let us fix the parameter φ (for example, the spot price φ = s0 ). Now, to evaluate the Greek with respect to φ we consider ∂ ∂ E h(ST ) = h(φ)(s) ϕ(φ)(s) ds ∂φ ∂φ g f
With the notation above we can apply the integration by parts rule which leads to ∂ ϕ(φ, s) ∂ ∂φ ϕ(φ)(s)ds h(s) ϕ(φ, s)ds = h(s) ∂φ ϕ(φ, s) =:ω(φ,s)
The calculation can be seen as an option pricing problem with a new payoff function, which is the initial one multiplied by the score ω(φ). Having carried out the calculation of the weights the calculation of the Greek, for instance with respect to the spot price s0 , is straightforward: GreeksL0R =
N 1 h s (S i )ω(s0 , S i ) N i=1 0
Let us now give the explicit calculation for the Black-Scholes model. By denoting the logarithmic asset value X (t) := ln(S(t)), the explicit form for the density is given by 1 1 ln(s) − X (0) exp − ϕs0 (s, X (0)) = √ 2 σ σ 2π s0 Thus, s − X (0) s − X (0) ∂s0 ϕs0 = · ∂s0 X (0) = √ √ ϕs0 σ T s0 σ T and the score function is ω(s0 , s) =
s √ s0 σ T
(18.29)
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
499
PropertySet
LR Greek
Abstract LR Greek {abstract}
{abstract}
European Call Greek PayOffConstructor Arithmetic Asian Greek Spread Option Greek
...
Figure 18.3 UML diagram for the likelihood ratio Greeks
Another property of the likelihood ratio method is that the score function does not depend on the payoff but on the underlying model. Therefore, we can compute the Greek with respect to the spot value for any payoff using the derived score function. This makes it possible to use the Abstract Factory design pattern again. The corresponding UML diagram is shown in Figure 18.3. Let us assume the option has maturity T and the model is the standard Black-Scholes one. To compute the Greeks we multiply the payoff under consideration by the following score functions: s (18.30) ω(s0 , s) = √ s0 σ T √ s 2 − sσ T − 1 (18.31) ω(s0 , s0 , s) = s02 σ 2 T ω(σBS , s) =
√ s2 − 1 −s T σ
(18.32)
The score functions are evaluated at s = Z N with Z N being the Gaussian variate used to generate the final value S(T ) = S(t N ). 18.4.1 Examples Let us consider a European call option. Figure 18.4 shows the different approximation methods for the option under consideration. We have chosen the following model parameters: s0 = 100, K = 101, r = 3%, σBS = 25% and T = 0.75. We did the same analysis for the second order
P1: JYS c18 JWBK392-Duffy
18:44
Printer: Yet to come
Monte Carlo Frameworks 0,526
2,0%
0,524
1,8%
0,522
1,6%
0,520
1,3%
0,518
1,1%
0,516
0,9%
0,514
0,7%
0,512
0,4%
0,510
0,2%
0,508 8192
58192
108192
158192
finite differencing BS D Relative Error FD
208192
Relative Error (%)
Delta
500
August 7, 2009
0,0% 258192
likelihood ratio Pathwise Delta Relative Error LR
Figure 18.4 -convergence diagram for a European call option using different estimation methods
Greek with respect to the spot, the of the option. The pathwise method cannot be applied since it would correspond to applying it to computing the Greek with respect to the spot for a digital. Figure 18.5 illustrates the results. Path-dependence and options on multiple assets We illustrate the possibilities by considering an arithmetic Asian call option and we consider a discrete set of time points T = {0 = t0 < t1 < t2 < . . . < tn = T }. To simulate the underlying for the given set T of time points we use the exact solution, which for the Black-Scholes model is
2 /2 i + σBS i Z i , Z i ∼ N (0, 1), i = 1, . . . , N Si+1 = Si exp r − σBS (18.33) This implies that the score functions needed to compute and are the same as for the call and the put option. For computing the vega we have to use the full vector of Gaussian variates used to construct the path: ω(s0 , Z 1 ) =
Z1 √ , s0 σBS t1
Z 1 ∼ N (0, 1)
(18.34)
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
501
0,030 73% 87%
0,025
60% 53%
0,020
Gamma
40%
0,015
33% 27%
0,010
Relative Error (%)
47%
20% 13%
0,005
7% 0,000 8192
58192
108192
158192
finite differencing BS G Relative Error LR
208192
0% 258192
likelihood ratio Relative Error FD
Figure 18.5 -convergence diagram for a European call option using different estimation methods
√ Z 12 − Z 1 σBS t1 − 1 ω(s0 , s0 , Z 1 ) = , Z 1 ∼ N (0, 1) 2 s02 σBS t1 ω(s0 , σBS , Z 1, . . . , Z N ) =
N Z 2j − 1 j=1
σBS
− Z N N −1 ,
Z j ∼ N (0, 1),
(18.35) (18.36)
j = 1, . . . , N
Further applications and new developments are covered in Benhamou (2002), Gobet and Kohatsu Higa (2003), Kohatsu Higa and Montero (2003), J¨ackel (2005), Fries and Joshi (2006), Fu (2007), Glasserman and Chen (2007), and Kienitz (2008). We illustrate the application to estimate the Greeks for a path-dependent option by considering a two year arithmetic Asian call option. We have chosen the model parameters: s0 = 100, K = 110,
r = 3%,
σ = 29%,
d = 1%, Averaging p.a. = 12
Figure 18.6 summarises the results using the finite difference method as well as the likelihood ratio method. Again, we applied the likelihood ratio method to compute (see Figure 18.7).
P1: JYS c18 JWBK392-Duffy
502
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks 0,415
0,410
Delta
0,405
0,400
0,395
Number of Simulations
0,390 0
50000
100000
finite differencing
150000
200000
250000
likelihood ratio
Figure 18.6 -convergence diagram for an arithmetic Asian call option using different estimation methods
0,021
Gamma
0,019
0,017
0,014
0,012 Number of Simulations 0,010 0
50000
100000
finite differencing
150000
200000
250000
likelihood ratio
Figure 18.7 -convergence diagram for an arithmetic Asian call option using different estimation methods
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
503
Finally, we give an example in a multi-asset setting. We assume a discretisation of a multidimensional SDE of the form d 2 ˆSi (tn+1 ) = Sˆi (tn ) 1 + r − di − σi n + aik n Z k , Z k ∼ N (0, 1) 2 k=1 The vector Z =√(Z 1 , Z 2 , . . . , Z n ) is a vector of independent standard Gaussian random variables. A˜ = (aik t)ik and the matrix B = (bk,i )k,i is given by B = A˜ −1 . We get the following scores for and cross- :
t Z A−1 i (18.37) ω(Si (0), Z ) = √ Si (0) T where for a given vector V = (v1 , v2 , . . . , vd ) ∈ Rd , the notation (V )i , i = 1, 2, . . . , d denotes the ith component of the vector V , that is (V )i = vi . Denoting by δi the Kronecker symbol, the score function for the cross- is given by ω(Si (0), Z ) bki bk j − S j (0) S (0)S j (0) k=1 i d
ω(Si (0), S j (0), Z ) = ω(Si (0), Z)ω(S j (0), Z ) − δi j
(18.38)
For other score functions in the multi-dimensional setting, see J¨ackel (2005). The likelihood ratio method has been applied to derive Greeks for other models than the Black-Scholes model, for example the Heston model (see Broadie and Kaya, 2006). Other authors have applied the Malliavin calculus to obtain score functions for more general models, for example Kohatsu Higa and Montero (2003) or Benhamou (2002).
18.5 LIKELIHOOD RATIO FOR FINITE DIFFERENCES – PROXY SIMULATION The Proxy Simulation Scheme was introduced by Fries and Kampen (2005). We consider two discretisations of the stochastic processes S. The first process, called the target scheme X , is a discretisation of the dynamics under consideration and the second one, called the proxy scheme Y , is a discretisation that is easily computable. We wish to use the transition density. For the corresponding densities ϕ X and ϕY used to compute expectations we require for almost all y that ϕ X (y) = 0 ⇒ ϕY (y) = 0. Applying an importance sampling argument we have for the expectation given a payoff function h: ϕ S (s) EϕS [h(S)] = h(s)ϕS (s)ds = h(s) ϕ X (s) = Eϕ X [h(X )ω] ϕ X (s) =:ω
Suppose we wish to compute some sensitivity with respect to a model-parameter φ. We simulate the proxy process Y . The sensitivity is then determined as in the likelihood ratio method: GreekProxy (φ) := E[h(φ)(S)ω(φ)]
(18.39)
P1: JYS c18 JWBK392-Duffy
504
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks
The difference is that we do not compute the likelihood ratio or score function analytically using the proxy scheme. The corresponding Monte Carlo estimator is N ωi (φ + ) − ωi (φ − ) 1 h(X ) N i=1 2
(18.40)
with weight function ωn+1 =
n π X (t j , Y j ; t j+1 , Y j ) j=1
π Y (t j , Y j ; t j+1 , Y j )
(18.41)
Here π denotes the transition kernel for either the target or the proxy. In practice we take two discretisation schemes: tn+1 → X n+1
(Target)
(18.42)
tn+1 → Yn+1
(Proxy)
(18.43)
The target scheme is chosen such that it is a reasonable approximation of the dynamics of the process S and that we can compute the transition density of the target scheme. A crucial observation in this case is that we do not need to sample from the scheme for S but we only need the transition densities to compute the weight function. This enables us to use transition densities that in some cases are readily available, whereas to sample from such densities might be a complex task. In the Monte Carlo simulation computing the weights is easy if we use an Euler or predictor-corrector scheme. In these cases the transition probabilities are (multi)-normal densities and therefore the weights can be computed explicitly. We have computed the delta and the gamma for a digital option using the proxy method. Figure 18.8 illustrates the convergence of the proxy estimator for the delta. Figure 18.9 illustrates the convergence of the proxy estimator for the gamma but with a different value for the initial distrubance.
18.6 SUMMARY AND CONCLUSIONS We have reviewed three important methods to compute Greeks within a Monte Carlo framework and we have also given guidelines on which one to use in a certain application. Difference estimators are easy to set up but extra simulations are needed and often the bias is large especially if the payoff is discontinuous. The pathwise method is computationally less expensive if it is possible to break it down to evaluating a payoff function. To this end we need the exact solution of the underlying stochastic differential equation. If this is not the case we have to simulate the dynamics of the sensitivity under consideration, which makes the method also computationally expensive. Finally, the likelihood ratio method can be applied to any kind of payoff if the probability density is known and smooth. This is the main drawback since for complex models at least it is not easy to compute the score function. A finite difference version of the likelihood ratio method, the proxy simulation scheme, uses a discretisation to explicitly simulate the score function. This representation is then used to perform the Monte Carlo simulation. This method can be adapted and leads to stable and reasonable results for multi-dimensional and complex models such as stochastic volatility L´evy models.
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
505
0,024 0,022 0,02 0,018 0,016 0,014 0,012
Proxy Simulation
15000
14000
13000
12000
11000
10000
9000
8000
7000
6000
5000
4000
3000
2000
Delta
1000
Number of Simulations 0,01
Likelihood Ratio
Figure 18.8 Proxy simulation for a (non-discounted) digital payoff with strike 50; = 0.5% of the initial spot price, 0,03 0,028 0,026 0,024 0,022 0,02 0,018 0,016 0,014 0,012
Proxy Simulation
15000
14000
13000
12000
11000
10000
9000
8000
7000
6000
5000
4000
3000
2000
Number of Simulations 1000
Gamma
0,01
Likelihood Ratio
Figure 18.9 Proxy simulation for a (non-discounted) digital payoff with strike 50; = 1% of the initial spot price,
P1: JYS c18 JWBK392-Duffy
506
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks
All of the discussed methods have their strengths and weaknesses. We argue that the problem under consideration should be analysed as thoroughly as possible to combine the methods and further apply variance reduction techniques to get efficient and stable estimation. Let us summarise the pros and cons of each method to compute the Greeks: • Finite Difference Method: – No additional information from the model is needed. We only need the discretisation of the underlying stochastic differential equation. – We do not need any further information on the simulation scheme. – The method cannot be applied to discontinuous payoffs, therefore the results are highly biased. – Computationally burdensome (calculation of two additional Monte Carlo estimators for the central differences). – Generic sensitivities. – The bias is of order because the finite difference approximation is of order . • Pathwise Method: – We do need additional information from the model since we may have to simulate the dynamic of the Greek directly. To this end we need the corresponding partial derivatives for the drift and diffusion coefficients of the stochastic differential equation. – We do not need any further information on the simulation scheme. – The method cannot be applied to discontinuous payoffs, therefore the results are highly biased and we need to know the partial derivative of the payoff function. – Computationally burdensome (calculation of two additional Monte Carlo estimators for the central differences). – No generic sensitivities. – The estimator is unbiased. • Likelihood Ratio Method: – We need additional information from the model. Especially, we do need the score function which can be computed from the probability density corresponding to the model under consideration. – We do not need any further information on the simulation scheme. – The method can be applied to discontinuous payoffs. – Computationally effective since only multiplication of the score function is involved. – No generic sensitivity. – The method leads to an unbiased estimator of the Greek. With the C++ implementation given on the CD the reader can easily adapt the methods to some specific setting.
18.7 EXERCISES AND PROJECTS 1. (**) Pathwise Method We have outlined a general procedure to compute Greeks using the pathwise method. To apply it a simulation of another process, (18.15), might be necessary. Use the general framework for modelling this process and test it for the Black-Scholes model.
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
2. (***) Mollifiers Consider the mollifier
h(x) =
0 1 exp − 1−x 2
507
, |x| ≥ 1 , |x| < 1
If we multiply the function h by a constant C we can ensure that C h(y)dy = 1. We denote the normalised function by ρ(x) := C −1 h(x). Given a small real number α consider ρ(x/α) α Figure 18.10 illustrates the shape of the function for different parameters of α. The function t α (y) = ρα (y − x)Digital(x)d x Digital ρα (x) =
−∞
can be used to approximate the payoff of a digital option. Apply the finite difference method as well as the pathwise method discussed in this chapter to approximate the payoff and compare it to the results obtained from applying the likelihood ratio method. Discontinuous payoffs can be approximated using such functions and the technique of convolution. Figure 18.11 illustrates this for approximating the payoff of a digital option. 3,5
3
2,5
2
1,5
1
0,5
α=0
Figure 18.10 The function ρα
α=0,75
α=0,5
α=0,25
1
0,88
0,75
0,63
0,5
0,38
0,25
0,13
0
–0,1
–0,2
–0,4
–0,5
–0,6
–0,8
–0,9
–1
0
P1: JYS c18 JWBK392-Duffy
508
August 7, 2009
18:44
Printer: Yet to come
Monte Carlo Frameworks
1
0.8
0.6
0.4
0.2
49.5
50
50.5
51
Figure 18.11 Smoothed payoff by applying convolution with ρα for a digital payoff with strike 50
3. (**) Digital Option Consider the payoff of a digital option with strike K . It is given by 1{S(T )>K } . Consider the smoothed payoff using the methods given in exercise 2. Implement a payoff function for the smoothed payoff and compute the different estimators for and of this digital option. Compare the results to the exact solution. 4. (**) Likelihood Ratio We stated the formulae for likelihood ratio score functions in multiple dimensions. Use formulas (18.37) and (18.38) to implement Greeks for a multi-factor geometric Brownian model by coding the corresponding payoff classes. 5. (***) Discontinuous Payoffs Consider an option with a discontinuous payoff function. To optimise the calculation we can use a hybrid method to compute Greeks. Near the discontinuity we can apply the likelihood ratio method and elsewhere we apply the pathwise method. Design a class that allows you to combine the pathwise method and the likelihood ratio method. This enables you to specify the region in which to apply a certain method. This amounts to specifying the discontinuities and selecting ranges around these discontinuities where the likelihood ratio method is valid. For example consider some payoff function h which has a discontinuity at x 0 (for example, a digital around its strike x0 ). Take some function A(x) which has the following properties: – A(x) = 1, x ∈ [x0 − 0 , x0 + 0 ] – some interpolation between 0 and 1, x ∈ (x0 − 1 , x 0 − 0 ) ∪ (x0 + 0 , x 0 + 1 ) – A(x) = 0, x ∈ (−∞, x0 − 1 ] ∪ [x0 + 1 , ∞)
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
Advanced Monte Carlo I
509
Then, consider the payoff function h new (x) = A(x)h(x) + (1 − A(x))h(x) I
(18.44)
II
Simulate sample paths and compute two Monte Carlo estimators. One estimator for I and one for II from equation (18.44) with respect to the appropriate method. 6. (****) Proxy Simulation Consider the proxy simulation. Assume the processes (18.42) and (18.43). Compute the transition densities π S and π Y . Use the results to compute the weight function ω in this case. Hint: the transition probabilities follow a (multi-dimensional) Gaussian distribution. To approximate the sensitivity with respect to some parameter φ compute the estimators: – Generate paths due to the schemes. – Compute the weights corresponding to formula (18.41). – Compute the Monte Carlo estimators with the realisations taken from the proxy scheme (18.43) and compute the scores with respect to the target scheme (18.42): N 1 h(Y )ω(φ + ), Vˆ = N i=1
N 1 Vˆ = h(Y )ω(φ − ) N i=1
– Compute Vˆ (φ + ) − Vˆ (φ − ) 2
P1: JYS c18 JWBK392-Duffy
August 7, 2009
18:44
Printer: Yet to come
510
P1: JYS c19 JWBK392-Duffy
July 29, 2009
15:26
Printer: Yet to come
19 Advanced Monte Carlo II – Early Exercise 19.1 INTRODUCTION AND OBJECTIVES Many options, especially options based on interest rates, include early exercise, early termination or callable features. Such features can be seen as further rights for the holder of the option. Such options can be classified as Bermudan or American options. Bermudan options can be exercised at predetermined times in the future whereas American options can be exercised at any time in the future until maturity. The market participant who is long the contract has to decide at each date whether he exercises the option or not. Therefore, the time to exercise the option is itself a random variable depending on the value of the underlying. Several methods have been introduced to approximate the price of Bermudan or American options using simulation. Among the methods are state space partitioning (Jin, Tan and Sun, 2007), stochastic mesh methods (Broadie and Glasserman, 2004), stochastic backward equations (Gobet, 2004), Malliavin calculus (Fournie et al., 1999), least squares regression (Longstaff and Schwartz, 2001) or dual methods (Rogers, 2002; Haugh and Kogan, 2001). We have decided to implement the method introduced in Longstaff and Schwartz (2001) based on linear least squares regression and the method considered in Rogers (2002) and Haugh and Kogan (2001). To this end we numerically approximate an optimal stopping problem based on a collection of simulated paths. The method is a combination of simulation and backward induction. The chapter is organised as follows. First, we introduce Bermudan and American options and proceed by introducing the optimal stopping problem. After defining the necessary concepts we describe the algorithm based on regression and show how we map the numerical concepts in C++ classes. The algorithm we consider leads to lower bounds on the price of a Bermudan or American option. We suggest improving the results by separating the regression from the pricing. Finally, we discuss several improvements and a method to compute upper bounds.
19.2 DESCRIPTION OF THE PROBLEM Suppose we have an option with payoff function h. We consider a discrete set of points in the interval [0, T ] and denote it by TEx = {t0 , t1 , . . . , t N = T }. At each time point ti , i = 1, 2, . . . , N we have the opportunity to execute the option. Because we allow exercise at predetermined times in [0, T ] we consider a Bermudan option. Pricing an American option can be done by considering many exercise opportunities. To tackle the problem of pricing a Bermudan option using simulation we formulate the problem in terms of an optimal stopping problem. To this end let (S(t))t∈[0,T ] be a stochastic process on the filtered probability space (, F, P, (Ft )t ). A random variable T given by T :
→
[0, T ]
ω
→
T (ω)
511
P1: JYS c19 JWBK392-Duffy
512
July 29, 2009
15:26
Printer: Yet to come
Monte Carlo Frameworks
is called a stopping time with respect to the filtration (Ft )t if it is adapted to it, that is {T ≤ t} ∈ Ft for all t ∈ [0, T ]. Let us denote the price of a Bermudan option at time tn , tn ∈ TEx , by Vn . The value at t0 , the present value, is given by V (0) = sup E [DF(0, τ )h[Sτ ]] τ
(19.1)
where we take the sup with respect to all stopping times τ and let DF(t1 , t2 ) denote the discount factor for discounting from t2 to t1 . For the optimal stopping time τ ∗ corresponding to equation (19.1) we have (19.2) V (0) = E DF(0, τ ∗ )h[Sτ ∗ ] We may think of applying the following stopping rule τ + which maximises the discounted option price for each simulated path: τ + = {τ |DF(τ, t)h(Sτ ) ≥ DF(s, t)h(Ss ); s, τ ∈ [t, T ]} Because the random variable τ + is not adapted it is not a stopping time and we implicitly use more information at time t than actually available. In the following we review numerical methods to approximate the optimal stopping time τ ∗ and discuss how to map these methods to C++ code. The first method leads to a lower bound for the price of a Bermudan/American option. The second one we review, called the dual method, is used to derive an upper bound for the option value.
19.3 PRICING AMERICAN OPTIONS BY REGRESSION Suppose we have simulated the option on a given mesh: T = {t0 , t1 , . . . , tNTime = T } The possibility to exercise the option is given at discrete times TEx ⊂ T . The algorithm to compute a lower bound is based on a collection of NSim paths represented by the two-dimensional array S = S jk jk , tk ∈ TEx , j = 1, 2, . . . , NSim. S jk is the value of the jth simulated path at time step tEx ∈ T . We start from the values at maturity S N ,l and use an induction argument based on regression to work backward until the start date of the option. To describe the induction we consider the expected continuation value at time tk , k = 1, 2, . . . , N and denote it by CkE (x). It is given as the conditional expectation of the option value at time tk+1 prevailing so that the asset price at time tk is equal to x: CkE (x) := E[h tk+1 (Sk+1 )|Sk = x], k ∈ T
(19.3)
The value CkE (x) is the value of the option resulting from not exercising it until the next possibility. In contrast to the expected continuation value, we consider the realised continuation value at time tk ∈ TEx and denote it by C kR (x). It is given by CkR (x) = E [h(Sk+1 )|Sk+1 = x]
(19.4)
The realised continuation value is the value of the option evolving the current path into the future and evaluating the payoff with the realised asset price.
P1: JYS c19 JWBK392-Duffy
July 29, 2009
15:26
Printer: Yet to come
Advanced Monte Carlo II
513
We can express the expected continuation value at time tk in terms of the expected and the realised continuation value as follows: E (Sk+1 )|Sk = x (19.5) CkE (x) = E CkR (Sk ), Ck+1 Let us verify that the continuation value satisfies a dynamic programming relation, which further clarifies the backward nature of the problem. We know the continuation value at maturity C NE (x) = 0
(19.6)
because there will be no continuation after reaching maturity. For tk ∈ TEx and using equation (19.5) we can interpret it as a newly issued option starting at tk . Applying this relation until we reach t0 the option value is the continuation value at time t = 0, which is C0E (S(0)). Conversely, for the option values Vk we find Vk (x) = max(C kR (x), CkE (x)) If the equations (19.6) and (19.5) are satisfied we say a dynamic programming relation holds.
19.4 C++ DESIGN Before we proceed we discuss the C++ template class AmericanOption. template class AmericanOption
{ public: AmericanOption(); AmericanOption(const Vector& MC ExerciseSchedule, VectorFunction<double, double>& MC Regressors, const Vector& MC Reg,const Vector& MC Price); virtual ˜AmericanOption(); Vector<double> Price(); // Calls the regression algorithm void Regress(); // Set Exercise Schedule void SetExerciseSchedule(Vector& MC ExerciseSchedule); // Set Discount Factors void SetDiscountFactors(Vector<double>& MC DiscountFactors); // Set Regressor Functions void SetRegressors(VectorFunction<double, double>& MC Regressors); // Paths used for regression void SetRegressionPaths(const Vector& MC Reg); // Paths used for pricing void SetPricingPaths(const Vector& MC Price); private: int NumberOfRegressors;
// Number of functions used in regression
P1: JYS c19 JWBK392-Duffy
514
July 29, 2009
15:26
Printer: Yet to come
Monte Carlo Frameworks int NumberOfExerciseDates;
// Number of Exercise possibilities Vector MonteCarloPath Regression;// implicitly stores number of regression paths // implicitly stores number Vector MonteCarloPath Pricing; of pricing paths int NumberOfRegPaths; // Number of regression paths int NumberOfPricingPaths; // Number of pricing paths VectorFunction<double, double> Regressors; // RegressorValues // Realised NumericMatrix<double> OptValues Current; continuation values Vector<double> DiscountFactors; // The Discount Factors Vector ExerciseSchedule; // The exercise schedule NumericMatrix<double> RegCoeff; // The regression coefficients NumericMatrix<double> RegCoeffLater; // The regression coefficients // for regression later // Function to generate the paths void Calculate(const Vector& MC Path, std::string method); double OptionPrice Lower; double OptionPrice Upper;
// Lower bound // Upper bound
}; We have designed the class to be able to consider different sets of paths for applying regression and pricing. This is reflected by the private member data: • Vector MonteCarloPath Regression • Vector MonteCarloPath Pricing. The function Regress() is called to perform the regression given the exercise schedule represented by the vector ExerciseSchedule and the pricing of the option. The results are then stored in the variables OptionPrice Lower and OptionPrice Upper. Before we describe the theory and the mathematical concepts we show how the class AmericanOption can be applied to price options: int main()
{ int NumberOfDates=12; // Number of Columns of Matrix int NumberOfAssets=1; // Number of Rows of Matrix int Seed=123456; // Seed for Random Generator cout > Seed; cout u01(NumberOfDates); Vector<double, long> result(NumberOfDates);
P1: JYS c19 JWBK392-Duffy
516
July 29, 2009
15:26
Printer: Yet to come
Monte Carlo Frameworks // Init class AmericanOption > TestAmerican(ExerciseSchedule, myvecfunction, MC Org, MC Org Pricing); // Set discount structure TestAmerican.SetDiscountFactors(DiscountFactors); double lowerbound = 0.0; double upperbound = 0.0; TestAmerican.SetRegressionPaths(MC Org);
// Set regression paths TestAmerican.SetPricingPaths(MC Org Pricing); // Set pricing paths TestAmerican.Regress(); // Start regression Vector<double> out = TestAmerican.Price(); // Call pricing func cout calcST(RanGen& rg, Model& model, long Paths, int Factors, long Steps) const;
P1: JYS c20 JWBK392-Duffy
534
July 27, 2009
20:2
Printer: Yet to come
Monte Carlo Frameworks Vector> calcST anti(RanGen& rg, Model& model, long Paths, int Factors, long Steps) const;
private:
};
The main loop in the member function calcST generating one asset path is given by the following piece of code:
// Precompute some constants used within the scheme double nudt = (r-d)* deltaT - mue * deltaT + deltaT * nigmartingalecorrection; // Define the subordinator IG<double> subordinator(model.nigsubordinator); // Inverse Gaussian // Main loop to generate all the paths for(int i = minindex Sims; i input; input[1] = 2.0; input[2] = 2.0; Range<double> range(0.0, 1.0); SDE<double, dim, dim2> result(range, input);
P1: IFM c21 JWBK392-Duffy
546
July 29, 2009
20:50
Printer: Yet to come
Monte Carlo Frameworks
It now remains to define the SDE’s drift and diffusion components: // Define the drift terms result.setDriftComponent(func1, 1); result.setDriftComponent(func2, 2); // Define the diffusion matrix result.setDiffusionComponent(func11, result.setDiffusionComponent(func22, result.setDiffusionComponent(func21, result.setDiffusionComponent(func12,
1, 2, 2, 1,
1); 2); 1); 2);
where each of the function arguments in the calls to the SDE’s member functions are ‘real’ functions, for example (the other functions’ code can be found on the CD): // Drift function double func1(double x, const VectorSpace<double,2>& input) { return - 1.0; }
and double func22(double x, const VectorSpace<double,2>& input) { return -(input[2] - input[1]); }
Finally, we can calculate the values of the drift and diffusion functions (notice that these are vector-valued functions) as follows: VectorSpace<double, dim> input2; input2 [1] = 1.0; input2 [2] = 3.0; VectorSpace<double, dim2> dW; dW[1] = 1.0; dW[2] = 2.0; VectorSpace<double, dim> output = result.calculateDiffusion(1.0, input2, dW); print(output); VectorSpace<double, dim> output2 = result.calculateDrift(1.0, input2); print(output2);
We have now shown – by using an example – how to use function pointers in C++ application code.
P1: IFM c21 JWBK392-Duffy
July 29, 2009
20:50
Printer: Yet to come
C++ Application Optimisation and Performance Improvement
547
Function Class Thing
...
D, R
Generic Function
D, R, N
Vector Function
D, R, N Scalar Valued Function
D, N, R, M
Vector Valued Function
N
Real Valued Function
Figure 21.1 Generic function classification
21.2.2 Generic classes that model functions Another way to model functions is to create a C++ class hierarchy as shown in Figure 21.1. The main types are vector functions (map scalars into vectors), scalar-valued functions (mapping vectors to scalars) and vector-valued functions (functions that map vectors to vectors). Let us examine some of the code that implements the classes in Figure 21.1. The base class is // Base class for all function categories class FunctionClassThing { // Base class for all function classes private: public: };
The above class is empty at the moment. It is also possible to derive your own classes from it. We note that it has no template parameters. The second-level base class represents a generic function mapping a domain space to a range space and is defined by // Mathematical function template // D == Domain, R == Range class GenericFunction : public FunctionClassThing { private: R (*f) (const D& d); protected: GenericFunction(); public: GenericFunction(R (*myFunction) (const D& d));
P1: IFM c21 JWBK392-Duffy
548
July 29, 2009
20:50
Printer: Yet to come
Monte Carlo Frameworks R evaluate (const D& value); // Using STL function object; competitor of evaluate() R operator ()(const D& value) const;
};
This class encapsulates a function pointer with a generic range and a generic domain; please note that we have two ways of evaluating the function for a given input parameter, one of which is a standard STL technique (overloading the operator ()) whereas the other solution uses evaluate(). The body of these functions consists of ‘calling’ the function pointer: template R GenericFunction::evaluate (const D& value) { return (*f)(value); } template R GenericFunction::operator ()(const D& value)const { return (*f)(value); }
Having discussed the base classes, we define derived classes in which the domain and range have special structures and where the underlying data elements can be doubles, complex numbers and other types. In order to motivate the code we focus on one class, namely the class of vector functions: // Mapping from Scalar to Array template class VectorFunction:public GenericFunction { public: // Constructor VectorFunction(VectorSpace (*myFunction) (const D& d)); };
This class would have more member functions in applications (and possibly member data) but the essential principles are more important at this stage. The code for this class is template VectorFunction::VectorFunction( VectorSpace (*myFunction) (const D& d)) : GenericFunction (myFunction) { }
In this case we use the colon syntax to initialise the private member data of the base class. Finally, we give an example of use. To this end, define a specific function of the correct signature and then use it to initialise an instance of VectorFunction:
P1: IFM c21 JWBK392-Duffy
July 29, 2009
20:50
Printer: Yet to come
C++ Application Optimisation and Performance Improvement
549
VectorSpace<double,3> vectorFunc(const double& input) { // Simple example to show use VectorSpace<double, 3> result; result[1] = input; result[2] = input; result[3] = input; return result; }
We can now use this function as follows: // Vector function GenericFunction<double, VectorSpace<double,dim> > vf2(vectorFunc); print (vf2.evaluate(2.0)); cout { public : DECLARE_LIBID(LIBID_AUTO999Lib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_AUTO999, "{11673BE6-472B-42D9-806D-9166EC516F44}") };
P1: JYS c27 JWBK392-Duffy
702
July 29, 2009
16:16
Printer: Yet to come
Monte Carlo Frameworks
CAUTO999Module _AtlModule;
#ifdef _MANAGED #pragma managed(push, off) #endif // DLL Entry Point extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { hInstance; return _AtlModule.DllMain(dwReason, lpReserved); } #ifdef _MANAGED #pragma managed(pop) #endif
// Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void) { return _AtlModule.DllCanUnloadNow(); }
// Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _AtlModule.DllGetClassObject(rclsid, riid, ppv); }
// DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { // registers object, typelib and all interfaces in typelib HRESULT hr = _AtlModule.DllRegisterServer(); return hr; }
// DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { HRESULT hr = _AtlModule.DllUnregisterServer(); return hr; }
P1: JYS c27 JWBK392-Duffy
July 29, 2009
16:16
Printer: Yet to come
Excel, C++ and Monte Carlo Integration
703
The source code for the header file for the simple ATL object contains one method in this case (you may define any number of methods in this object). In this case we just return a number but in your case you can add code that is relevant to your application: // Comp999.h : Declaration of the CComp999 #pragma once #include "resource.h" // main symbols #include "AUTO999.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #endif
// CComp999 class ATL_NO_VTABLE CComp999 : public CComObjectRootEx, public CComCoClass, public IDispatchImpl { public: CComp999() { } DECLARE_REGISTRY_RESOURCEID(IDR_COMP999)
BEGIN_COM_MAP(CComp999) COM_INTERFACE_ENTRY(IComp999) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { }
P1: JYS c27 JWBK392-Duffy
704
July 29, 2009
16:16
Printer: Yet to come
Monte Carlo Frameworks
public: STDMETHOD(myPI999)(void); STDMETHOD(func999)(DOUBLE* myarg); }; OBJECT_ENTRY_AUTO(_ _uuidof(Comp999), CComp999)
The code file for the ATL simple object is given by // Comp999.cpp : Implementation of CComp999 #include "stdafx.h" #include "Comp999.h"
// CComp999 STDMETHODIMP CComp999::myPI999(void) { // TODO: Add your implementation code here
return S_OK; } STDMETHODIMP CComp999::func999(DOUBLE* myarg) { // TODO: Add your implementation code here *myarg = 1.42; return S_OK; }
27.7.3 The utilities class We have provided a number of useful functions to ease the pain of writing Excel applications in C++. We include the following functionality (which was included in Duffy, 2004a and Duffy, 2006a) for registration/unregistration, for interfacing with Excel and for creating buttons and menu items in the Excel user interface. The first class has functions for registering and unregistering the component in the Windows registry: #ifndef ComAddinUtils_hpp #define ComAddinUtils_hpp #include "atlsafe.h" #include "atlbase.h" #include "Excel\ExcelImports.h" class ComAddinUtils { public: // Register a COM add-in
P1: JYS c27 JWBK392-Duffy
July 29, 2009
16:16
Printer: Yet to come
Excel, C++ and Monte Carlo Integration
705
static HRESULT RegisterCOMAddin(CComBSTR officeApp, CComBSTR progID, CComBSTR friendlyName, DWORD dwStartupContext); // Unregister a COM add-in static HRESULT UnRegisterCOMAddin(CComBSTR officeApp, CComBSTR progID); // Set a key in the registry static BOOL SetKeyAndValue(HKEY hKeyRoot, CComBSTR path, CComBSTR subkey, CComBSTR value); // Recursively delete a key in the registry static LONG RecursiveDeleteKey(HKEY hKeyParent, CComBSTR keyChild); };
#endif ComAddinUtils_hpp
The second file contains application-specific functionality: #ifndef ExcelUtils_hpp #define ExcelUtils_hpp #include "atlsafe.h" #include "Excel\ExcelImports.h" // _IDTExtensibity2 import #import "C:\Program Files\Common Files\Designer\MSADDNDR.DLL" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search #include "VectorsAndMatrices\Vector.hpp" #include "VectorsAndMatrices\NumericMatrix.hpp" class ExcelUtils { public: // Add menu item to Excel static Office::_CommandBarButtonPtr AddMenuItem(Excel::_ApplicationPtr xl, Office::COMAddInPtr addin, CComBSTR menuName, CComBSTR menuItemCaption, CComBSTR menuItemKey); // Remove menu item from Excel static void RemoveMenuItem(Excel::_ApplicationPtr xl, ext_DisconnectMode removeMode, CComBSTR menuName, CComBSTR menuItemCaption); // Convert variant to vector with doubles
P1: JYS c27 JWBK392-Duffy
706
July 29, 2009
16:16
Printer: Yet to come
Monte Carlo Frameworks static Vector ExcelRangeToVector(VARIANT* range); // Convert Excel range to vector with doubles static Vector ExcelRangeToVector(Excel::RangePtr pRange); // Convert variant to STL vector with doubles static std::vector ExcelRangeToStlVector(VARIANT* range); // Convert Excel range to STL vector with doubles static std::vector ExcelRangeToStlVector(Excel:: RangePtr pRange); // Convert variant to numeric matrix with doubles static NumericMatrix ExcelRangeToNumericMatrix(VARIANT* range); // Convert Excel range to matrix with doubles static NumericMatrix ExcelRangeToNumericMatrix(Excel:: RangePtr pRange); // Retrieve a value from an Excel cell static int GetIntFromCell(Excel::_WorksheetPtr sheet, CComBSTR cell); static long GetLongFromCell(Excel::_WorksheetPtr sheet, CComBSTR cell); static float GetFloatFromCell(Excel::_WorksheetPtr sheet, CComBSTR cell); static double GetDoubleFromCell(Excel::_WorksheetPtr sheet, CComBSTR cell); // Put a value in an Excel cell static void SetCellValue(Excel::_WorksheetPtr sheet, CComBSTR cell, int value); static void SetCellValue(Excel::_WorksheetPtr sheet, CComBSTR cell, long value); static void SetCellValue(Excel::_WorksheetPtr sheet, CComBSTR cell, float value); static void SetCellValue(Excel::_WorksheetPtr sheet, CComBSTR cell, double value); static void SetCellValue(Excel::_WorksheetPtr sheet, CComBSTR cell, CComBSTR value);
};
#endif ExcelUtils_hpp
You can use these classes in your applications. The complete source code is on the CD.
P1: JYS c27 JWBK392-Duffy
July 29, 2009
16:16
Printer: Yet to come
Excel, C++ and Monte Carlo Integration
707
27.8 SUMMARY AND CONCLUSIONS We have given a detailed account of how to create C++ applications that interface with Excel and we paid particular attention to COM add-ins and Automation add-ins. The latter add-ins are used for worksheet functions where response time is important, whereas the former add-ins are more suitable for compute-intensive applications. We described the steps that you need to execute in order to create an add-in and we gave examples of the C++ code that implements them. We have provided several nontrivial examples and applications on the CD.
27.9 EXERCISES AND PROJECTS 1. (***) Curve Fitting and Cubic Splines The objective of this exercise is to integrate C++ code for cubic spline interpolation (as developed in Duffy, 2006a) with Excel. We wish to write an Automation add-in to calculate the value of the spline for a specific value of the independent variable. Design the program in Excel based on the following input: r An array of x values. r An array of y values (these two arrays x,y must have the same size). r An x value whose spline value we wish to calculate. r An array of x values whose spline values we wish to calculate. r The kind of boundary conditions used (Duffy, 2006a; Press et al., 2002). The class interface that we need is given by enum CubicSplineBC {SecondDeriv, FirstDeriv}; class CubicSplineInterpolator { private: // ... private: // Private member functions public: CubicSplineInterpolator(const Vector<double, long> xarr, const Vector<double, long> yarr, CubicSplineBC BCType, double alpha = 0.0, double beta = 0.0); // Find the interpolated valued at a value x double Solve(double xvar) const; // Create the interpolated curve, MEMBER DATA AS ABSCISSAE Vector<double, long> Curve() const; };
Test your add-in using examples from your own work. The source code for the CubicSpline is on the CD.
P1: JYS c27 JWBK392-Duffy
708
July 29, 2009
16:16
Printer: Yet to come
Monte Carlo Frameworks
2. (**) My First Automation Add-in In this exercise we use the exact solution of the Black-Scholes formula for put and call options, including the calculation of call and put prices and the sensitivities such as delta, gamma and theta. Use the full C++ code from the CD. Answer the following questions: (a) Design the user interface for this problem, in particular the input and output aspects; you will need to define option parameters (such as expiry and strike price), give them values and determine in which cells they are defined. Furthermore, the output cells contain the put and call option prices. (b) Create an Automation add-in for the design in part (a). Use STL to hold your data structures. (c) We now extend the add-in to support calculation of the option sensitivities: delta, gamma and vega. Print these values in Excel. (d) Compare the solution with the solution if you had to do the exercise in VBA. Do you notice performance improvements and what can you say about code maintainability in these two languages? 3. (*****) COM Add-in In Chapter 0 we developed a simple Monte Carlo framework to price one-factor plain options. We now wish to integrate this code with Excel using a COM add-in. In this case we wish to use the same data as in exercise 2 (namely, option parameters). The C++ code using the console for input and output was int main() { // Create the basic SDE (Context class) double T = 30.0; Range<double> range (0.0, T); double initialCondition = 100.0; // Discrete stuff long N = 100; cout > N;
// Tell the Builder what kinds of SDE and FDM Types you want //SDEType {A, B, C, D}; //FDMType {Euler, PC, CN, MIL, SIE, IE, DerivFree, FRKIto, Fit}; FDMTypeDBuilder fdmBuilder(FDMTypeDBuilder::D, FDMTypeDBuilder::PC, N, range, initialCondition,drift, diffusion, diffusionDerivative);
// V2 mediator stuff long NSimulations = 50000; cout > NSimulations; double r = 0.08; cout