Chapter 5, part 4 of 5: Models and calibration
Hello again.
This is the fourth in a series of five post (yes, I found out how many they are) covering chapter 5 of my book. The previous posts are here, here and here.
As I already mentioned (more than once, I seem to remember) during the first half of next week I’ll be in London to teach my Introduction to QuantLib Development course. Drop me a line if you want to meet over a pint; probably it won’t turn into a QuantLib user group, but it would be nice to meet some of you and chat about what you do with the library. I’ll try and tweet the location. And yes, there are still places available for the course; click on this link if you’re interested.
Follow me on Twitter if you want to be notified of new posts, or add me to your circles, or subscribe via RSS: the buttons for that are in the footer. Also, make sure to check my Training page.
Parameterized models and calibration
The CalibratedModel class
The implementation of the CalibratedModel
class is shown in listing
5.5. Its core is the calibrate
method, with most other features
being there in order to support its execution. (In fact, there’s a
couple of public methods there that should be used, directly or
indirectly, by calculate
alone and should belong to the protected
section. I’m not sure that, in true Ellery Queen tradition, you have
all the clues you need; but you can try looking at the code and
guessing which ones.)
Listing 5.5: Implementation of the CalibratedModel
class.
Instances of this class store a vector of Parameter
instances, which
for some reason are called arguments here; a constraint, to be applied
to the set of their underlying parameters; and a member of the
EndCriteria::Type
enumeration, which tells us how the latest
calibration ended (say, because it succeeded, or for reaching the
maximum number of evaluations) and whose name still shows the original
use of this class for short-rate models. As I mentioned, we gave this
class little attention for quite a while.
The constructor takes a single argument specifying the number of model
parameters and initializes the data members: the vector of parameters
is given the passed size, the constraint is set to an instance of an
inner PrivateConstraint
class that I’ll describe later, and the end
criterion is set to None
since the model is not yet calibrated.
Now, we have an interesting glitch here. This constructor is obviously
meant to be used by derived classes, but is declared as public
(probably an oversight). This, together with the fact that the class
doesn’t define any pure virtual function, makes it possible to create
instances of CalibratedModel
directly; however, such instances are
unusable since they don’t provide a way to set their parameters to
anything useful (the stored Parameter
instances are
default-constructed and thus lack any behavior). Technically, fixing
this glitch would break backward compatibility; but it might be argued
that programs using this feature were broken anyway. We’ll think about
it in one of the next versions.
When the model receives a notification, the update
method notifies
the model’s own observers after performing any needed
calculation. These will be implemented by overriding the virtual
generateArguments
method. The name might be misleading, since it
seems to suggest that parameter instances should be created here; but
this can’t be, since we don’t want to override parameters that we
might have already calibrated. (We don’t want to recalibrate at each
notification, either.) Instead, this method is used either to create
parameters that don’t need calibration (e.g., the term-structure
parameter in some short-rate models, which follows the risk-free rate)
or to perform some housekeeping, as we’ll see in the continuation of
the Heston model example.
The params
and setParams
methods are used to read and write the
underlying parameters. To return them, the params
method asks each
of the stored Parameter
instances for the number of underlying
parameters it provides, creates an Array
instance that can hold all
of them, and collects their values (it can’t add them to the array in
a single loop because Array
doesn’t provide a push_back
operation). In a similar way, the setParams
method reads from the
passed array and writes the required number of values in the stored
Parameter
instances.
Now, it you guessed that params
and setParams
are the methods that
I’d rather have in the protected section, you can go and pour yourself
the alcoholic beverage of your choice. (Drink responsibly. Also, don’t
drink and code.) These two methods should only be called from inside
the calibrate
method; client code isn’t even able to know the number
of the underlying parameters or which ones belong to each Parameter
instance (unless its programmer reads the source code of the
particular model used. That’s cheating, though) so it shouldn’t be
able to modify them, and it has very little use for reading them, too.
As I said, the calibrate
method is the focus of the class; and in
true managerial fashion, it delegates most of the work to other
objects. Simply put, it sets up a minimization problem so that solving
it gives the calibrated set of parameters. The ingredients of the
problem are an instance of a class derived from OptimizationMethod
(for instance, it might implement the simplex method or
Levenberg-Marquardt. More details on those are in appendix A) which is
passed to the method by the calling code; a function to minimize, or
rather a function object, which is an instance of its inner
CalibrationFunction
class and that returns a measure of the
calibration error (more on that shortly); and a constraint on the
parameter values, which defaults to the instance of
PrivateConstraint
stored at construction and can optionally be
combined with an additional constraint passed as an argument.
The calibrate
method collects all of the above, instantiates the
problem, and starts the minimization. When that is done, it saves the
end criterion, sets the parameter values to those that minimize the
error (that is, those returned by problem.currentValue()
) and
notifies any observers that something has changed. The end criterion
(which might be that the minimization succeeded, or that it failed for
a number of different reasons) can be retrieved by means of the
endCriteria
method. If I were to write this class now, I’d probably
return it from calibrate
instead; but I’m ambivalent about it. It
might make sense to store it in the model.
As it is now, the calibrate
method provide little exception safety;
if an exception were thrown at some point during the calibration, the
model would be left with the last parameter values tried by the
minimizer (the very same that probably caused the exception to be
thrown). We might provide the strong guarantee by storing the
parameter values before starting the minimization, catching any
exceptions, and restoring the old parameter values before re-throwing;
but it’s probably best to set an appropriate end criterion, which is
what happens if the calibration fails for other reasons.
The last pieces of functionality are implemented in the
PrivateConstraint
and CalibrationFunction
inner classes, shown in
listing 5.6.
Listing 5.6: Inner classes of the CalibratedModel
class.
The PrivateConstraint
class works by collecting the constraints set
to the stored Parameter
instances. The logic is similar to that of
params
or setParams
; it loops over the stored parameters,
determines the subset of underlying parameters that belong to each
one, and asks the Parameter
instance to check them by calling its
testParams
method. The composite constraint is satisfied if and only
if all the inner constraints are.
Finally, the CalibrationFunction
class provides an estimate of the
calibration error for a given set of parameters. Its constructor takes
and stores a pointer to the model being calibrated, the set of quoted
instruments being used for the calibration, and a set of weights. For
some reason, the pointer to the model is stored in a shared_ptr
instance, taking care that it’s not deleted with the calibration
function. Storing the raw pointer would have been enough.
The class inherits from CostFunction
, which requires derived classes
to implement both a values
method returning a set of errors (in this
case, one per quoted instrument) and a value
method returning a
single error estimate; a given optimization method might use the one
or the other. The two work in a similar way, so I’m showing the
implementation of just the first in the listing: they set the given
parameters to the model, and then ask the stored helpers for the
calibration error. For this to work, the helpers need to be set a
pricing engine that uses the model being calibrated. The setup of the
entire thing would be something like this:
That is, the helpers use the engine to calculate their model prices,
and in turn the engine uses the model. Thus, after the call to
setParams
inside the values
method the model prices change and so
do the corresponding calibration errors. The values
method returns
the set of distinct errors, while the value
method returns the sum
of their squares.
A final note: currently, the CalibrationFunction
class is declared
as a friend of CalibratedModel
. This is actually not necessary,
since it only accesses the public setParams
method; and if we were
using C++11, it wouldn’t be necessary even if setParams
was
protected. According to the new standard, inner classes have access to
all member of their enclosing class, public or not.
Next post: an example of model.