The content for this post is the fourth part of an ongoing series on the QuantLib finite-difference framework.
But first: this week the final version of Visual Studio 2015 was released and, whaddayaknow, QuantLib 1.6 was not quite prepared for it. We had tried to be forward-looking and had prepared our version-detecting code for VC13, but alas, Visual Studio 2015 turned out to be VC14 instead. The library compiles and links just fine, but has the wrong name and the auto-link pragmas get confused. This week I might be releasing a 1.6.1 version that will fix the issue, God willing and the creek don’t rise—since the other bit of news this week was that Sourceforge had a major outage (you might have noticed that the QuantLib web site and the mailing lists have been down for a few days). Now it’s mostly up again, but as of today it’s still not possible to make new releases. Keep your fingers crossed.
Oh, and my Quants Hub workshop is still a steal at £99, but from what I’m told this will only last for a few more days, until the end of July. Get it cheap while you can.
Follow me on Twitter if you want to be notified of new posts, or add me to your Google+ circles, or subscribe via RSS: the buttons for that are in the footer. Also, make sure to check my Training page.
At any step (or in the middle of a step; we’ll see later how we account for this) something might happen that changes the price of the asset; for instance, a right can be exercised or a coupon could be paid.
As opposed to boundary conditions, we called these step conditions. The name might not be the best; I can easily see the model as enforcing the “condition” that the asset price is the maximum between its continuation and the intrinsic value, but a coupon payment is harder to categorize in this way. In any case, the base class for all such conditions is shown in the listing below.
applyTo method, which modifies the array of asset values in
place, must also take care of checking that the condition applies at
the given time; so, for instance, an American exercise will change the
asset values regardless of the time, whereas a dividend payment will
first check the passed time and bail out if it doesn’t match the known
As you see, the base class is quite simple; but derived classes
over-generalized and went South. In the next listing, you can see one
such class, from which even simple conditions (like the one for
American exercise) are derived. We could have implemented a simple
applyTo method comparing the option values and the intrinsic
values. Instead, we started adding constructors over the years so that
instances could be built from either an existing array of intrinsic
values, or a payoff, or some data that could describe the payoff. Of
course these alternatives needed to be stored into different data
members, so we added type erasure to the mix, we defined an interface
to retrieve intrinsic values, and we gave it an array-based and a
Ironically, we only ever used half of this. Existing engines use the
array-based constructor and implementation, and the payoff-based inner
class is not used anywhere in the library, Which is just as well;
because, as I reviewed the code to write this chapter, I found out
that its implementation is wrong. So all in all, we could have written
a much simpler implementation of an American exercise condition that
would just take an array of intrinsic values and implement
accordingly. If you ever implement a step condition, I suggest you do
A final note; the step condition is not applied inside the
method of the evolution scheme, as we’ll see shortly. What this means
is that there’s no guarantee that the step condition won’t break the
boundary condition, or even the other way around. In practice, though,
applying a step condition for a model that makes any sense will
naturally enforce the chosen boundary condition.
Next time, with all the basic pieces in place, we’ll start to put them together.
Aside: look, Ma, no hands
The faulty implementation of
PayoffWrapper was added in February
2003, which probably makes this the longest-lived bug in the library
(apart from those we still haven’t found, of course). If I hadn’t
been looking at the code to write this chapter, the critter could have
got old enough to drive.
Now, bugs happen; nothing shocking about this. What irks me, though, is that the problem would have been caught easily by a couple of unit tests. I and others usually try and review what goes in the library, and the code that gets contributed has often been used in the field and purged of obvious errors; but still I’m somewhat worried about the lack of coverage of old code in the test suite. If you have a coverage tool and some time on your hands, please let me hear from you. I’d love to see some analysis on this.