Previously we have explored how to implement a simple, vanilla European option pricer in C++ by using QuantLib’s pre-made tools. While these tools are very nice, we will explore in this post how to create our very own objects in C++, QuantLib-style.
We will encounter new things like creating classes, namespaces (so we don’t interfere with QuantLib’s names), public and private variables within classes, and even look at implementing a subclass that inherits the properties of QuantLib’s pricing engine results.
Other technical aspects of this post will include using pointers once again, but also accessing pointer properties using the arrow operator. We’ll discuss constant variables and mutable variables and why we would use one or the other.
Setup
Open Visual Studio 2017 (VS) and create a new C++ project. I’ve called mine “TestInstrument” because that is also the name of the C++ source file containing the main
program that will test our instrument
class.
When it opens create two new files: 1) a new Source File called “Instrument.cpp
” and a new Header File called “Instrument.h
“. These will go in the Source and Header subfolders respectively. Before we even start though we must turn off precompiled headers, because this will interfere with our own headers and namespace declarations! To do this, right-click on your TestInstrument solution and go to Configuration Properties > C/C++ > Precompiled Headers and change the Precompiled Header to “Not Using Precompiled Headers”.
The Instrument Header File
Open up the Instrument.h
header file. We begin by wrapping the entire code block in an #ifndef
statement. It looks like this:
#ifndef conundrum_instrument_H #define conundrum_instrument_H #endif
This #define
code block connects our source C++ file with our header file. The names have to be the same, and it’s ideal to have it like [namespace name]_[class name]_H
(the H
at the end stands for “Header”).
We will attempt to code up as much of the class header as possible without including any files, so to begin with we have no include files.
So that we can use our instrument class in conjunction with QuantLib’s instrument class we will have to wrap our C++ code in a namespace
like so:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { } #endif
Inside the namespace we create the base class Instrument
like so:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { }; } #endif
It is a base class because it is not inheriting anything, for example, a class that inherits a base class would be declared like this: class Instrument : InheritedBaseClass {}
. We will use this a little later on.
For now we will just give it the default constructor:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { // Default Constructor Instrument(); }; } #endif
So now, when we create this Instrument object in our main
program we would type something like this:
#include "Instrument.h" #include <iostream> int main(int, char*[]) { Conundrum::Instrument option(); }
Try it out. Even with nothing written in the source file and only the header declared, the intellisense should pick up the object when you begin to type Conundrum::
.
The NPV Member Function
In our main program, we would like to be able to type something like this: option.NPV()
to return the present value of the instrument using the so-called dot operator. NPV
is what is called a Member Function of the class, and it would need to be public so that our main
program can access it. Furthermore, it would be ideal that it be of type double
(like a real number), and be a const
function so that we are assured that the member function won’t change the instrument object’s (client-visible) state. So we write in the class header:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { // Default Constructor Instrument(); // Member Functions double NPV() const; }; } #endif
And now, jumping back to the test main program, we are able to type the following with no errors:
#include "Instrument.h" #include <iostream> int main(int, char*[]) { Conundrum::Instrument option(); std::cout << "Value of option is = " << option.NPV() << std::endl; }
Now let's provide some actual source code to our instrument class. As it stands, the constructor and the member function NPV()
do absolutely nothing. In fact, you should have little green lines under those functions telling you that no definitions could be found.
To give them definitions we code them in. Now we have two choices, to provide the source code in the .cpp
file, or we can provide the definitions as inline
definitions in the header file. We will do the latter because this is a very simple class.
Go back to the instrument header file and scroll down to a region of the code after the class but before the end of the namespace. We will declare our inline definitions here:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { // Default Constructor Instrument(); // Member Functions double NPV() const; }; // inline definitions // Default Constructor inline Instrument::Instrument() {} // Member Functions inline double Instrument::NPV() const {} } #endif
These two inline functions still don’t do anything (at least they’re now defined though!). To make them do something we would need to put some code in between the {
}
. We will leave the constructor empty for now and just provide some code for the NPV()
member function.
The easiest code would be to provide the member function with some sort of void
function (recall, a void
function is a type of function which does not return any values – it just performs some sort of operation) like calculate()
which does the actual calculation and then return NPV_
where it would return a double temp variable called NPV_
that was calculated inside the calculate()
void function. Writing this in straight will give more undefined errors, but set us off in the right path:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { // Default Constructor Instrument(); // Member Functions double NPV() const; }; // inline definitions // Default Constructor inline Instrument::Instrument() {} // Member Functions inline double Instrument::NPV() const { calculate(); return NPV_; } } #endif
So now we just have to define what calculate()
is.
The Calculate Function
The void
member function calculate()
should not be accessible from outside the object, only from within. So we go back to the header file and declare it as a private void
function and give it an inline definition like so:
#ifndef conundrum_instrument_H #define conundrum_instrument_H namespace Conundrum { class Instrument { public: // Default Constructor Instrument(); // Member Functions double NPV() const; private: void calculate() const; }; // inline definitions // Default Constructor inline Instrument::Instrument() {} // Member Functions inline double Instrument::NPV() const { calculate(); return NPV_; } inline void Instrument::calculate() const {} } #endif
Include QuantLib for a Pricing Engine
Now, we’re going to cheat a little bit because I do not want to have to code up an entire pricing engine just for this example of an instrument class. So we are going to have to include the QuantLib include directories and library files. If you are unsure how to do this, read a previous post on the topic here.
After you have added QuantLib to the C++ directories, go to the top of instrument.h
and add the following line in: #include
.
The Pricing Engine
We want the class to be able to use a Pricing Engine object that the user specifies. So where should we put it? First, it should not be accessible from public; once it is declared it should stay private, so it’s definition should be as a private variable in the instrument class. Second, the engine’s type
will be QuantLib’s PricingEngine
type. Not only that, but this type should be a smart pointer to the PricingEngine
(we covered why this should be so in our previous post). So we need to also include Boost’s shared ptr header file with #include
. While we are at it, we also need to declare what type the temp variable NPV_
is back in the instrument class declarations.
Now we add the engine_
and NPV_
temporary variables in to the private part of the instrument class:
#ifndef conundrum_instrument_H #define conundrum_instrument_H #include #include namespace Conundrum { class Instrument { public: // Default Constructor Instrument(); // Member Functions double NPV() const; private: void calculate() const; double NPV_; boost::shared_ptr engine_; }; // inline definitions // Default Constructor inline Instrument::Instrument() {} // Member Functions inline double Instrument::NPV() const { calculate(); return NPV_; } inline void Instrument::calculate() const {} } #endif
Finishing off the Calculate Function
and the Arrow operator
The first thing that will happen in the calculate
function is that we reset()
the engine. This is achieved by writing engine_->reset()
(not engine_.reset()
! Why? because engine_
is a pointer, so member functions are accessed using the ->
operator).
Alternatively, we could have de-referenced the pointer for regular member access with the dot operator like so:
(*engine_).reset()
Next, we use the member function getArguments()
to set the arguments of the engine. Then the member function calculate()
to calculate the price, and finally we will get the results and assign the value to the NPV_
variable using the member function getResults()
.
#ifndef conundrum_instrument_H #define conundrum_instrument_H #include <ql/quantlib.hpp> #include <boost/shared_ptr.hpp> namespace Conundrum { class Instrument { public: // Default Constructor Instrument(); // Member Functions double NPV() const; private: void calculate() const; double NPV_; boost::shared_ptr engine_; }; // inline Defintions: // Default Constructor: inline Instrument::Instrument() {} // Member Functions: inline double Instrument::NPV() const { calculate(); return NPV_; } inline void Instrument::calculate() const { engine_->reset(); engine_->getArguments(); engine_->calculate(); engine_->getResults(); NPV_ = 0.0; } } #endif
We have just set NPV_
equal to 0.0
for now because we are unsure how to get the results out of the Pricing Engine. However, this has instructional value because you should get an error here when we try to assign a value to the variable. The error states: expression must be a modifiable value
. To fix this, go back up to where NPV_
was first declared as a double
and prefix it with the keyword mutable
. This allows the variable to be changed within the class depending on the outcome of the Pricing Engine’s calculation, which is exactly what we want to do.
The Results Class
The annoying thing here is that we need access to the Pricing Engine’s getResults()
member function and assign one if its values to the NPV_
variable, but it’s not immediately accessible – at least in the way we want. So to get at it we need to build another class that inherits the Pricing Engine’s result
class, then instantiate it as a new object and access the value via the dot operator.
So under the class declaration for instrument, but above the inline definitions, we add a new inherited class called “Instrument::results
“:
class Instrument::results : public virtual QuantLib::PricingEngine::results { public: void reset() { } double value; double errorEstimate; QuantLib::Date valuationDate; };
This class won’t work yet because we have not declared what Instrument::results
is in the parent class yet. Furthermore, we have left the inherited member function reset()
empty for now, but we will have to fill it in later. Also, you will notice that we are using the default constructor. So let’s define the result
object in the parent instrument class (note: the declaration of the child class Instrument::results
goes before the default constructor!):
#ifndef conundrum_instrument_H #define conundrum_instrument_H #include <ql/quantlib.hpp> #include <boost/shared_ptr.hpp> namespace Conundrum { class Instrument { public: // Member Classes class results; // Default Constructor Instrument(); // Member Functions double NPV() const; private: void calculate() const; mutable double NPV_; boost::shared_ptr engine_; }; class Instrument::results : public virtual QuantLib::PricingEngine::results { public: void reset() { } double value; double errorEstimate; QuantLib::Date valuationDate; }; // inline Defintions: // Default Constructor: inline Instrument::Instrument() {} // Member Functions: inline double Instrument::NPV() const { calculate(); return NPV_; } inline void Instrument::calculate() const { engine_->reset(); engine_->getArguments(); engine_->calculate(); engine_->getResults(); NPV_ = 0; } } #endif
Now, hopefully, we can just go down to our calculate()
definition and fix up the NPV code with:
NPV_ = results->value;
But no, this will be an error. Why? Because Instrument::calculate()
doesn’t know what the results
object is, at least, it won’t recognise which instance it is – unless we pass it in!
To do that we need to pass it in as an argument to the calculate()
member function, and also fix up its declaration in the instrument class so that it will know to expect an argument:
void calculate(const QuantLib::PricingEngine::results*) const;
So what should we pass in? Well, since we are assigning the NPV_
variable to a pointer, the argument should also be a pointer. QuantLib’s Pricing Engine has a subclass called results
so we will pass in a pointer to that object and call it simply r
with the following code:
inline void Instrument::calculate(const QuantLib::PricingEngine::results* r) const
Inside the calculate
member function we will define a new variable ourResults
of type Instrument::results*
and dynamically cast QuantLib’s Pricing Engine results to it with the following code:
const Instrument::results* ourResults = dynamic_cast(r);
Note how we are dynamically casting QuantLib’s result
object in to our own result
object! See here for more information on what it does. Admittedly, it’s a little advanced for this post, and I might cover more on it in a later post. But for now, we just accept that it is a nice shortcut way to move around objects of similar types.
Our calculate()
member function looks like this:
inline void Instrument::calculate(const QuantLib::PricingEngine::results* r) const { const Instrument::results* ourResults = dynamic_cast(r); engine_->reset(); engine_->getArguments(); engine_->calculate(); engine_->getResults(); NPV_ = ourResults->value; }
Full Listing of TestInstrument.cpp
Going back to our main
we can now access the instrument’s NPV function with the following code and it should compile but NOT run (as we have not coded instructions for the instrument class to handle actual pricing engines or payoff objects):
#include "Instrument.h" #include <iostream> int main(int, char*[]) { Conundrum::Instrument option; std::cout << "Value of option is = " << option.NPV() << std::endl; return 0; }
Summary
We have created our own Instrument class by creating a base class (inherits nothing) and a child class called Results to interpret QuantLib’s Pricing Engine results.
We have covered C++ topics such as Namespaces (to avoid confusion with QuantLib’s instrument class), inheriting QuantLib classes to get at particular member functions and return results and inline member function definitions.
In addition to the above, we have also looked at accessing member functions of pointers (using the ->
operator), we’ve looked at passing in pointers as arguments, and talked about making certain variables either const
so that they do not get changed or mutable
because they can get changed.
We have implemented the instrument class by utilising Boost shared pointers and QuantLib’s Pricing Engine to define an NPV member function that returns the value of the instrument.
Full Listing of Instrument.h
Please note that while this code compiles, it will not work fully as we have not created the reset()
member function for the subclass Instrument::results
nor have we given it a constructor that can take in a Pricing Engine and a Payoff type. These will be covered in the next posts! This header is still a good representation of a skeleton class though and shows the basic ingredients required to get one working.
#ifndef conundrum_instrument_H #define conundrum_instrument_H #include <ql/quantlib.hpp> #include <boost/shared_ptr.hpp> namespace Conundrum { class Instrument { public: // Member Classes class results; // Default Constructor Instrument(); // Member Functions double NPV() const; private: void calculate(const QuantLib::PricingEngine::results*) const; mutable double NPV_; boost::shared_ptr engine_; }; class Instrument::results : public virtual QuantLib::PricingEngine::results { public: void reset() { //value = errorEstimate = Null(); //valuationDate = QuantLib::Date(); //additionalResults.clear() } double value; double errorEstimate; QuantLib::Date valuationDate; }; // inline Defintions: // Default Constructor: inline Instrument::Instrument() {} // Member Functions: inline double Instrument::NPV() const { calculate(engine_->getResults()); return NPV_; } inline void Instrument::calculate(const QuantLib::PricingEngine::results* r) const { const Instrument::results* ourResults = dynamic_cast(r); engine_->reset(); engine_->getArguments(); engine_->calculate(); engine_->getResults(); NPV_ = ourResults->value; } } #endif
In the following posts we will be adding more functionality to this class.