helper variables, and actual payments from assignments, with the keyword pays.
To value a script in the context of path‐wise Monte‐Carlo simulations means to evaluate it against a number of scenarios, each scenario providing different values for spot on the event dates in 1y, 2y, and 3y. For every such scenario generated by the model, we evaluate the script and record the final value of all its variables. In the end, we average those final variables' values across scenarios to estimate the values of the corresponding products. If we also require risk sensitivities, we compute the derivatives of the final variable values to changes in the model parameters. Evidently, the derivatives of prices are averages of the path‐wise derivatives, which permits an efficient path‐wise computations of sensitivities, in particular with adjoint propagation. See for instance Giles and Glasseman's “Smoking Adjoints,” which introduced adjoint techniques to finance [14], and our publication [27], which explains automatic adjoint differentiation (AAD) and provides professional differentiation code.
We remind the reader, however, that evaluation (including of sensitivities) is only one thing we can do with the script. The purpose of this library is to parse scripts into visitable data structures and implement a framework that enables all types of visitors, not only the evaluator, to traverse and manipulate scripts in many ways.
We split the implementation in five steps.
First, we describe in chapter 2 the data structure for the internal representation of the script, ready for evaluation and other forms of visits. We will use expression trees as a data structure, and we describe these in detail. The discussion and code for the actual parsing (that turns a text script into a collection of expression trees) is left to the appendix.
Then, we introduce in chapter 3 the evaluator that values expression trees during simulations, pre‐processors that optimize evaluation before simulations, and other visitors, objects that traverse expression trees and perform calculations and actions depending on the visited node, while maintaining internal state. We explain the visitor pattern, a common framework for all types of visitors, which encapsulates traversal logic and makes the development of specific visitors particularly simple.
Third, in chapter 4, we bring the pieces together and develop a (very) basic model to test the scripting library.
Fourth, we improve our framework with the addition of the keyword pays in chapter 5 and take this opportunity to illustrate how a core extension is made to the language.
NOTES
1 1 Continuous barriers are somehow outside of this logic and require specific support that is not discussed. Support for early exercises is discussed in chapter 15.
2 2 This is an overly simplified version of the autocallable product and one that is purposely structured to illustrate the implementation and application of scripting. It is significantly different from actual autocallable transactions, which can also be scripted with our language, but in a more complicated manner.
3 3 We make some arbitrary choices regarding the syntax of our scripting language. Readers can easily implement their own preferred grammar once they are comfortable with the idioms explained here.
CHAPTER 1 Opening Remarks
INTRODUCTION
In the early stages of derivative markets, dedicated models were typically put together to value and risk manage new transaction types as they emerged. After Black and Scholes [5] published in 1973 a closed‐form formula for European options under a constant volatility assumption, alternative models—like the Cox‐Ross‐Rubinstein binomial tree [7] in 1979, later replaced by more efficient finite difference grids—were developed to value American options under the same assumptions.
As trading in derivatives matured, the range of complex transactions expanded and models increased in complexity so that numerical methods became necessary for all but the simplest vanilla products. Models were typically implemented in terms of finite difference grids for transactions with early exercise and Monte‐Carlo simulations for products with path‐dependency. Notably, models increased in dimension as they grew in complexity, making grids impractical in most cases, and Monte‐Carlo simulations became the norm, with early exercises typically supported by a version of the Longstaff‐Schwartz regression‐based algorithm [22]. Sophisticated models also had to be calibrated before they were used to value and risk manage exotics: their parameters were set to match the market prices of less complex, more liquid derivatives, typically European calls and puts.
Most of the steps involved—calibration, Monte‐Carlo path generation, backward induction through finite difference grids—were independent of the transactions being valued; therefore, it became best practice to implement models in terms of generic numerical algorithms, independently of products. Practitioners developed modular libraries, like the simulation library of our publication [27], where transactions were represented in separate code that interacted with models to produce values and risk sensitivities.
However, at that stage, dedicated code was still written for different families of transactions, and it was necessary in order to add a new product to the library, to hard code its payoff by hand, compile, test, debug, and release an updated software.
The modular logic could be pushed one step further with the introduction of scripting languages, where users create products dynamically at run time. The user describes the schedule of cash‐flows for a transaction with a dedicated language specifically designed for that purpose, for example:
STRIKE | 100 |
01Jun2021 | opt pays max( 0, spot() ‐ STRIKE) |
for a 1y European call with strike 100, or
STRIKE | 100 |
BARRIER | 120 |
01Jun2020 | vAlive = 1 |
Start: 01Jun2020 | |
End: 01Jun2021 | if spot() > BARRIER then vAlive = 0 endIf |
Freq: weekly | |
01Jun2021 | opt pays vAlive * max( 0, spot() ‐ STRIKE) |
for the same call with a 120 (weekly monitored) knock‐out barrier.1
The scripts are parsed into expression trees, and visited by an evaluator, a particular breed of visitor, who traverses the trees, while maintaining the internal state, to compute payoffs over the scenarios generated by a model: