© Carlos Oliveira 2016

CARLOS OLIVEIRA, Options and Derivatives Programming in C++, 10.1007/978-1-4842-1814-3_14

14. Using C++ Libraries for Finance

Carlos Oliveira

(1)Monmouth Junction, New Jersey, USA

Writing good financial code is a difficult task, one that cannot be done in isolation. As a software engineer, you frequently need to collaborate with others to achieve your development goals. You also need to use code that has been written by other groups. In particular, developers are constantly using libraries created by other companies or open source projects. Integrating these libraries into your own work is a major step to improve productivity.

In the world of quantitative finance, a number of C++ libraries have been used with great success. This chapter reviews some of these libraries and discusses how they can be integrated into your own applications. Some of the topics covered in this chapter include the following:

  • Boost introduction: The boost repository provides access to many C++ libraries that are based on templates for higher efficiency. You will learn how to install and use boost, as well as integrate particular libraries in the repository to your own applications.

  • Boost odeint: The odeint library is a well-tested and efficient set of algorithms for the solution of ordinary differential equations (ODEs). You will learn about the different algorithms contained in odeint and the different situations in which they can be employed.

  • QuantLib: The QuantLib library has been designed as a repository for quantitative algorithms and assorted utilities for financial applications. Many parts of this code can be used to simplify the process of analyzing options and derivatives. You will learn how to use this library and see a few of the most commonly used classes and algorithms that are available in the QuantLib repository.

Boost Libraries

In the last few years the boost project has become well known for providing high-quality libraries for C++ applications. As a result, the boost project is now the de facto repository for extensions to the STL. In fact, many of the libraries that started as part of the boost repository have been incorporated to the C++ standard, including, for example, std::shared_ptrand std::unique_ptr. A few of the developers working on boost libraries have also become part of the standard C++ committee.

The boost project focuses on using the modern features of the C++ language, including, but not exclusively, the employment of templates for high performance. Many of the libraries included in boost provide template-based interfaces that make the resulting system much more flexible. For example, different algorithms can be specialized at the template level, so that you can combine different algorithms through the use of templates, when deciding on the optimal techniques to solve a specific problem. This is a much more adaptable strategy, rather than relying on decisions made by library designers.

Note that boost is not a finance library. Instead, it provides a large number of features that are packaged in a few separate libraries. However, many of the components have direct use in the implementation of financial applications. Its components can be used to perform and simplify several tasks, such as:

  • Solving ODEs:Ordinary differential equations appear frequently in the solution of numerical problems in the area of finance. As you have seen, to solve some option analysis models, it is necessary to efficiently compute the value of ODEs. The odeint library gives you access to such functionality, as you see in the next section.

  • uBLAS: The Basic Linear Algebra System library provides a C++ interface to an advanced linear algebra library. uBLAS can be used to support more complex matrix-related code, as well as the solution of systems of equations.

  • Multi-array: Many applications require the use of multi-dimensional arrays when working in areas such as 3D animation, weather predictions, etc. The multi-array library provides an easy interface for the creation and manipulation of arrays that can be indexed using multiple indices.

  • Managing file and directories: The <filesystem> header file contains a set of templates that can be used to manage files and directories . It handles different operating systems, so that you don’t need to rely on system-specific libraries for common file-based operations.

Note

The filesystem library is scheduled to become part of the C++ standard library in the next few years. Meanwhile, boost can be used to gain access to this functionality.

The boost repository contains a large set of useful libraries for C++ development, including the ones listed previously. In its current version, there are 136 libraries that cover all types of tasks needed in modern programing. Table 14-1 shows a list of commonly used libraries contained in the boost project repository, including a quick explanation of their usage.

Table 14-1. List of Commonly Used Boost Libraries

Library

Description

odeint

Implements algorithms to solve ordinary differential equations (ODEs).

filesystem

A set of classes to manipulate files and directories in an OS-independent way.

Multi-array

Provides arrays with multiple dimensions; useful for scientific code.

MPI

Implements the Message Passing Interface, a standard for parallel processing.

Math

A set of mathematical functions not included in the standard library.

Graph

A library that extends the STL and provides containers and algorithms to handle graphs.

Functional

Provides templates that simplify functional programming techniques.

Algorithm

A set of generic algorithms that extends the algorithm header in the STL.

uBLAS

A modern C++ implementation of BLAS (Basic Linear Algebra Subprograms).

Variant

A container that safely stores a union container, capable of storing different data types.

Sort

Implements several sorting strategies using templates for high performance.

Regex

Provides support for regular expressions in C++.

Python

A set of templates and classes that allows interaction between Python and C++ code.

Installing Boost

The first step in using the boost libraries is to install them on your machine. Being an open source repository, boost packages are made available through the web and mirrored in several web sites. The canonical web site for the repository is www.boost.org , where you can find instructions for installing boost in several architectures and operating systems.

The most common way to install boost is to download the compressed file containing the headers and source files. Once the files are uncompressed, you can use the main installation script that is provided, bootstrap.sh, to build and install the software on the desired path in the local disk.

Another way to install boost libraries is to use third-party installers or package managers. For example, if you use Linux, it is possible to install boost as a package using the local package manager, such as dpkg on Debian systems. On Windows systems, you can also install cygwin, which contains a package manager with several common C++ programming packages, including the boost libraries.

Installing from source is also easy. You just need to unzip the source files into a location and use that directory as the include path for the compilation process. An advantage of boost is that most of the libraries are implemented as header files (this is also true for most of the STL). Therefore, there is no need for any compilation. A few libraries, however, require a compilation step that can be performed using the bootstrap script. You will need the build step if you need to use one of the following libraries:

Boost libraries are built using a C++ build system called bjam. The build script will try to find bjam in your machine or build it. You can also download bjam from its binary distribution located in boost.org/build.

In the next few sections, you will see how to use a few libraries available from boost. First, you will see how to solve ordinary differential equations with the odeint library.

Solving ODEs with Boost

In the previous chapter, you saw how ordinary differential equations (ODEs) can be implemented directly using C++ code. Due to how options are defined and represented, ODEs models arise naturally in the design of financial algorithms. As a result, being able to quickly implement such methods is a great advantage for the quantitative software developer. Moreover, it is much easier to reuse an ODE implementation that has already been reviewed and thoroughly tested, especially considering that numerical errors are hard to catch in many cases.

One of the components of the boost repository, the odeint library, deals specifically with ODEs. With odeint, you can more easily create code to integrate ODEs, choosing from a number of different algorithmic strategies. Figure 14-1 shows a screenshot of the current web page for the odeint web site, where its repository is maintained.

A371837_1_En_14_Fig1_HTML.jpg
Figure 14-1. Web site of the odeint library, where you can download its latest version

Table 14-2 presents a quick list of the integration techniques available when using odeint. Some of these techniques have been discussed in the previous chapter. Others are variations of the best-known algorithms and can provide performance advantages for use in particular applications.

Table 14-2. List of Integration Techniques Available When Using odeint

Class Name

Description

euler

Original Euler’s algorithm to solve ODEs

runge_kutta4

Uses the Runge-Kutta method, with fourth-order approximation

runge_kutta_cash_karp54

Runge-Kutta method

runge_kutta_fehlberg78

Variation of Runge-Kutta that uses the Fehlberg algorithm

adams_moulton

A multi-step algorithm for solving ODEs

dense_output_runge_kutta

An implementation of Runge-Kutta that uses dense output

bulirsch_stoer

Based on the Bulirsch-Stoer algorithm, provides higher accuracy in the solution of complex ODEs

implicit_euler

A variation of Euler’s algorithm in which the equation is given in implicit form and requires the use of the associated Jacobian

The algorithms made available in the odeint library are implemented as separate template classes. Each class corresponds to an algorithm or algorithmic concept. The odeint library contains a set of integration methods that can be parameterized using the provided templates. These templates make it possible to use different strategies through the combination of the given algorithms and concepts.

One of the basic types of strategies classes available in odeint is a stepper . A stepper is used to navigate through the solution space of the given ODE. This is an important concept because ODEs are solved interactively, and the step size and direction determine how a particular solution strategy will behave. Depending on the type of stepping strategy used, the resulting algorithm can perform a calculation that is faster or more accurate. Here are the known stepper types provided by odeint:

  • runge_kutta4

  • euler

  • runge_kutta_cash_karp54

  • runge_kutta_dopri5

  • runge_kutta_fehlberg78

  • modified_midpoint

  • rosenbrock4

Solving a Simple ODE

In this section, you will see how to use the concepts described previously to solve a simple ODE in the standard form given by:

y' = f(x,y)

Here, y is a function of x, y' is the first derivative of y, and f(x, y) is a general equation that may depend both on x and y.

To use odeint, the first step is to include the main header file containing this library, with:

#include <boost/numeric/odeint.hpp>

To solve any ODE, you need first to determine the f(x, y) part of the system, that is, the right side of the ODE equation. In this example, you will solve for the simple equation
$$ yhbox{'}=frac{3}{2.5{x}^2}+frac{y}{3/2x} $$

This is done in the following code fragment:

#include "boosttest.hpp"

#include <iostream>
#include <boost/array.hpp>


#include <boost/numeric/odeint.hpp>

//
// This is the equation at the right side of the ODE   y' = f(x,y)
// It is evaluated in the inner steps of the algorithm.
//
void right_side_equation(double y, double &dydx, double x)
{
   dydx = 3.0/(2.5*x*x) + y/(1.5*x);
}

An optional feature of odeint algorithm is the use of an observer. The observer is a function that can be used to inspect each step of the algorithm. Using this information, you can record the progression of the solution, or you can perform more complex analysis if necessary. In this example, the observer simply prints the output, which will later be used to plot the convergence of the solution.

// this function simply prints the current value of the interactive
// solution steps.
void write_cout( const double &x , const double t )
{
   cout << t << ' ' << x << endl;
}

Next, you need to define the stepper algorithm. In this case, the runge_kutta_dopri5, a basic stepper based on the Runge-Kutta method , was selected. This can be done with a simple typedef to define the stepper_type.

// A stepper based on Runge-Kutta algorithm.
// the state_type use is 'double'
typedef runge_kutta_dopri5<double> stepper_type;

Finally, the main function is used to integrate the ODE under the given initial conditions. The task is performed by the integrate_adaptive function, which takes as parameters the stepper, the ODE defining equation, state and step parameters, and a function that prints the intermediate results.

// This solves the ODE described above with initial condition x(1) = 0.
//
int main()
{
   double x = 0.0;
   auto n = integrate_adaptive(
         make_controlled(1E-12, 1E-12, stepper_type()),  // instantiate the stepper
         right_side_equation,            // equation
         x,                              // initial state
         1.0 , 10.0 , 0.1 ,              // start x, end x, and step size
         write_cout );
   cout << " process completed after "  << n << " steps ";
   return 0;
}

I ran this code and used the output of the observer function to plot the convergence of the results found by the ODE solver. The plot, displayed in Figure 14-2, shows how solution values change as you move from 1.0 to 10.0 in the solution space.

A371837_1_En_14_Fig2_HTML.jpg
Figure 14-2. Results of the integrate_adaptive function from the odeint library

The QuantLib Library

The second example of a library that is used in quantitative finance and options analysis is the QuantLib library. QuantLib is a well-established repository of quantitative code for C++. The library has been tested and used by many developers, which means that you can take advantage of the hard work that went into creating and testing the algorithms.

Being an open source project, QuantLib is free and can be used by anyone by just downloading and building the source code. The project also accepts contributed code, which means that many people can fix bugs and participate in the improvement of the library.

The QuantLib contains a wide assortment of classes that simplify certain tasks that are necessary in quantitative algorithms for finance. A few areas covered by QuantLib are the following:

  • Date handling: Many algorithms for options and derivative analysis are based on dates. Therefore, accurate information about trading dates, holidays, and other calendar-specific events are very important for the correct results of such algorithms. QuantLib provides a number of classes that encapsulates the concepts needed for data handling in financial applications.

  • Design patterns: The QuantLib library puts a lot of effort in following well-established design patterns . Most algorithms use design patterns that make them easier to understand and to maintain. For this reason, QuantLib has a rich implementation of common design patterns, including Singleton, Observer, Singleton, Composite, and others.

  • Monte Carlo methods: A few of the classes provided by QuantLib are used to simplify the implementation of Monte Carlo methods. These classes make it easier to create, for example, random paths for financial instruments, as well as similar models based on Brownian motion.

  • Pricing engines: Another area that is covered by QuantLib is the implementation of efficient pricing engines for options and derivatives. The library provides several techniques for options pricing, which are carefully packaged into C++ classes. These pricing engines include barrier option engines, Asian option engines, basket option engines, and vanilla option engines.

  • Optimizers: Another utility that is frequently employed in financial applications is an optimization engine. The QuantLib library contains a few classes dedicated to some common optimization strategies. Using such optimization algorithms, it is possible to quickly solve complex problems where the objective is to find the minimum or the maximum of a given function.

In the remaining of this section, you will see a few examples using classes from QuantLib. You will learn how to use some of the main classes available in the library and integrate them to your applications.

Handling Dates

One of the most common tasks in financial algorithms is handling dates correctly. You saw in Chapter 3 that there are several ways to store and transform values stored as dates. The QuantLib library tries to simplify some of these tasks with the introduction of carefully designed date and time classes.

Managing holidays is one of the most difficult problems when using dates in financial applications. Since the number of trading days constitute part of the calculation, when computing the price of an option, it becomes very important to have precise representations of date intervals, considering which of those days are trading days.

First, lets consider how to use the Date class provided by QuantLib, along with some of the basic operations defined on that class. The basic way to construct an object of type Date is to pass the desired date in the day-month-year format. Here is an example:

   Date date1(10, Month::April, 2010);

This would create a date representing the tenth day of April, 2010. Now, using a date created in this way, it is possible to perform operations such as addition or subtraction using the operators that have been overloaded by QuantLib.

void testDates()
{
   Date date(10, Month::April, 2010);
   cout << "original date: " << date << endl;


   date += 2 * Days;
   cout << "after 2 days: " << date << endl;


   date += 3 * Months;
   cout << "after 3 months: " << date << endl;
}

In this code, the operators are used to add a period of two days and three months, respectively, to the original date. The Days and Month identifiers are simple data types that concisely represent a time period and can be used to simplify the handling of intervals.

Another simple operation on dates is incrementing and decrementing. This allows you to quickly find the next or the previous day in a sequence, without needing to check if these dates occur in different months or years. The following code shows an example of how this works:

void nextAndPreviousDay()
{
   Date date(28, Month::February, 2010);
   cout << "original date: " << date << endl;


   date++;
   cout << "next day: " << date << endl;


   date--;
   cout << "previous day: " << date << endl;
}

Additional tools are provided to answer common questions related to dates. For example, member functions of the Date class are used to determine if a particular date occurs in a leap year, if it occurs at the end of the month, or if the date is a weekday. These are exemplified by the code in the following section.

Working with Calendars

Another aspect of dates that causes a lot of confusion is handling local holidays. Each country has non-trading days that are determined by holidays, which also change according to the year in which they occur. To handle these issues, QuantLib provides a set of Calendar objects . These calendars are localized and can be used to determine if a particular date is a holiday.

The following example shows how to use the Calendar class in a typical C++ application:

void useCalendar()
{
   Calendar cal = UnitedStates(UnitedStates::NYSE);


   cout << " list of holidays " << endl;
   for (auto date : Calendar::holidayList(cal, Date(1, Month::Jan, 2010),
                                               Date(1, Month::Jan, 2012)))
   {
      cout << " " << date;
   }


   cout << " is Jan 1 2010 a business day?  "
        << cal.isBusinessDay(Date(1, Month::Jan, 2010)) << endl;
   cout << " is Jan 1 2010 a holiday?  "
        << cal.isHoliday(Date(1, Month::Jan, 2010))     << endl;
   cout << " is Jan 1 2010 end of month?  "
        << cal.isEndOfMonth(Date(1, Month::Jan, 2010))  << endl;
}

The first line of the useCalendar function shows how to create a new calendar for a particular region. In this case, the calendar corresponds to the United States, and in particular to the New York Stock Exchange.

With this calendar loaded, it is possible to answer a number of questions about dates in the United States. For example, the next few lines show how to list all holidays with the holidayList function. The function receives as arguments the calendar and the desired start and end date. The result is a container with all the holidays for the given period.

The next few lines show how to use QuantLib Calendar object to answer a few common questions related to the day of the week and the month. The first call is to isBusinessDay, and it returns true if the given date occurs in a business day (usually Monday to Friday in most markets). The second member function is isHoliday, which returns true only if the given date is a holiday.

Finally, you can see the member function isEndOfMonth example. This function returns true if the given date occurs at the end of a month, which may be an important date in some kinds of financial contracts.

Another interesting feature of the Calendar class is that you can create and manage your own calendars. This is necessary when creating code for countries that are not already covered by the library, or when you’re working on particular institutions or markets that use a distinct calendar.

The main functions to manage calendar holidays are addHoliday and removeHoliday. With these functions, you can create calendars that are specific to your needs. The following example code shows how to use them:

Calendar createNewCalendar()
{
   Calendar newCal = UnitedStates(UnitedStates::NYSE);


   // Remove winter holiday
   newCal.removeHoliday(Date(25, Month::December, 2016));


   // Add international workers' day
   newCal.addHoliday   (Date(1,  Month::May, 2016));


   cout << " list of holidays " << endl;
   for (auto date : Calendar::holidayList(newCa
l, Date(1,  Month::Jan, 2016),
                                                  Date(31, Month::Dec, 2016)))
   {
      cout << " " << date;
   }


   return newCal;
}

This function starts with the creation of a new calendar object based on the U.S. calendar, more specifically using the NYSE list of holidays. The function then proceeds to modify the original calendar, adding a common holiday and adding another so the number of holidays remains the same. The code also prints the list of holidays for the year 2016 to the standard output. Finally, the createNewCalendar function returns the newly created calendar as the result.

Another important feature of the Calendar class provided by QuantLib is the ability to determine the number of trading days between two dates. This is done using the businessDaysBetween member function, which returns the number of business days in a particular interval given to the function. A simple example can demonstrate how this function works:

int getNumberOfDays(Date d1, Date d2)
{
   Calendar usCal = UnitedStates(UnitedStates::NYSE);


   int nDays = usCal.businessDaysBetween(d1, d2);

   cout << " the interval size is "  << nDays << endl;

   return nDays;
}

In the beginning, the getNumberOfDays function creates a calendar using the U.S. locale. The next step is to determine the number of business days between two given dates. Then, the function prints the value of this difference and returns that value as the final result.

Computing Solutions for Black-Scholes Equations

The next example of QuantLib is directly related to the problem of pricing options. The main formula for pricing options is derived from the Black-Scholes differential equations. This makes it really important to have a library that can quickly solve Black-Scholes models , at least as an initial step for further analysis.

The QuantLib provides classes that are specifically designed to solve Black-Scholes models. Unlike other ODE and PDE packages that can be used to solve general differential equations (as seen in the previous section on boost), the QuantLib classes target efficient techniques to solve a single model in particular. This results in a very specialized algorithm that can be relied on for the efficient solution of Black-Scholes models.

To benefit from options models used by the QuantLib, you need to instantiate two classes:

  • A class representing the option and the associated payoff: QuantLib provides a set of classes for this purpose. An example of such a class is PlainVanillaPayoff, which represents a common (vanilla) option and its associated payoff.

  • A class representing the pricing method: This class encapsulates the algorithm that is used to compute the option price. This example is interested in the class representing the Black-Scholes algorithm, which is named the BlackScholes calculator.

These classes are exemplified in the following sample code, which includes a function that performs the computation and an associated test function.

First, you need to create a simple storage area, where the necessary information for the algorithm is stored. The BlackScholesParameters structure is used for this purpose. The structure contains the following fields:

  • The spot price for the underlying instrument

  • The strike price for the desired option

  • The current interest rate

  • The forward interest rate

  • The volatility of the underlying instrument

The structure can be represented in the sample C++ code as:

struct BlackScholesParameters {
   double S0;
   double K;
   double rd;
   double rf;
   double tau;
   double vol;
};

Based on this information, it is possible to describe the use of Black-Scholes pricing method using a C++ function. The function, called callBlackScholes, receives as a parameter a single reference to a structure of type BlackScholesParameters.

void callBlackScholes(BlackScholesParameters  &bp)
{
   // create a vanilla option (standard option type)
   boost::shared_ptr<PlainVanillaPayoff>
      vanillaPut(new QuantLib::PlainVanillaPayoff(Option::Put,bp.K));


   // compute discount rates
   double cur_disc = std::exp(-bp.rd  * bp.tau);  // current discount rate
   double for_disc = std::exp(-bp.rf  * bp.tau);  // forward  discount rate
   double stdev    = bp.vol * std::sqrt(bp.tau);  // standard deviation


   BlackScholesCalculator putPricer(vanillaPut, bp.S0, for_disc, stdev, cur_disc);

   // Print options greeks
   cout << "value:" << putPricer.value() << endl;
   cout << "delta:" << putPricer.delta() << endl;
   cout << "gamma:" << putPricer.gamma() << endl;
   cout << "vega:"  << putPricer.vega(bp.tau)  << endl;
   cout << "theta:" << putPricer.theta(bp.tau) << endl;
   cout << "delta Fwd:" << putPricer.deltaForward() << endl;
   cout << "gamma Fwd:" << putPricer.gammaForward() << endl;


}

This code works in the following way. The first instruction is necessary to create a new object describing the required option. This is done with the instantiation of an object of class PlainVanilllaPayoff, which indicates that the new option is of plain vanilla type (i.e., it is a standard option). The arguments passed are the type of option (either a call or a put) and the strike. These two parameters determine the type of option that you’re handling, independent of the current characteristics of the market. The object of type PlainVanillaPayoff is stored in a shared_ptr, which automatically manages the lifetime of the object, cleaning up the pointer at the end of the scope of the local variable.

The next part of the callBlackScholes function initializes some of the parameters necessary to use the options pricer. The parameters include the current and forward discount rate, which are computed from the given interest rate using an exponential transformation. Another important parameter is the standard deviation, which measures the volatility of the underlying instrument.

Once the parameters for the options pricing model are available, you can instantiate the BlackScholesCalculator class, passing as parameters the object that describes the option, the current price, and the other parameters discussed previously.

Using the object of type BlackScholesCalculator, you can retrieve important information about the option price. The most important information is clearly the value of option at a particular date, returned by the member function value. The option Greeks also provide key information that can be used to make decisions about the option. The Greeks calculated by the BlackScholesCalculator include the following:

  • The delta: Represents the marginal change in value with respect to the price of the underlying.

  • The gamma: Represents the marginal change in delta with respect to the price of the underlying.

  • The vega: Represents the marginal change in value with respect to the change in volatility.

  • The theta: Represents the marginal change in value with respect to the change in remaining time.

You can test this code using a function that uses a few common values for each of the parameters and calls the callBlackScholes function . Here is an example of how this can be done:

void testBlackScholes()
{
   BlackScholesParameters bp;


   bp.S0 = 95.0;     // current price
   bp.K  = 100.0;    // strike
   bp.rd = 0.026;    // current rate of return
   bp.rf = 0.017;    // forward rate of return
   bp.tau= 0.62;     // tau (time greek)
   bp.vol= 0.193;    // volatility


   callBlackScholes(bp);
}

Creating a C++ Interface

Based on the previous functions, it is easy to create a generic class that encapsulates a vanilla Black-Scholes pricing strategy. I called this class BlackScholesPricer, and it presents a simple interface that can be called without external references to QuantLib.

The class declaration contains a set of parameters that will be used in the constructor, as shown in the next code listing.

class BlackScholesPricer {
public:
   BlackScholesPricer(bool call, double price, double strike, double tau, double r, double fr, double vol);
   BlackScholesPricer(const BlackScholesPricer &p);
   ∼BlackScholesPricer();
   BlackScholesPricer &operator=(const BlackScholesPricer &p);


   double value();

   double delta();
   double gamma();
   double theta();
   double vega();
private:
   double m_price;
   double m_strike;
   double m_tau;
   double m_rate;
   double m_frate;
   double m_vol;
   double m_isCall;


   boost::shared_ptr<QuantLib::BlackScholesCalculator> m_calc;
};

The constructor for BlackScholesPricer is responsible for initializing all the parameters with the passed arguments. Inside the constructor, you can see the code that initializes the payoff class. The option payoff can be a put or a call, depending on the value of the first parameter.

Later, you will see these parameters being used to create a new BlackScholesCalculator object. This object is stored in a shared pointer so that it can be used to answer questions about the model.

BlackScholesPricer::BlackScholesPricer(bool call, double price, double strike, double tau, double r, double fr, double vol)
:m_price(price),
m_strike(strike),
m_tau(tau),
m_rate(r),
m_frate(fr),
m_vol(vol),
m_isCall(call)
{
   boost::shared_ptr<QuantLib::PlainVanillaPayoff>
      m_option (new QuantLib::PlainVanillaPayoff(
                   call ? QuantLib::Option::Call : QuantLib::Option::Put, strike));


   // compute discount rates
   double cur_disc = std::exp(-m_rate  * m_tau);  // current discount rate
   double for_disc = std::exp(-m_frate * m_tau);  // forward  discount rate
   double stdev    = m_vol * std::sqrt(m_tau);    // standard deviation


   m_calc.reset(new QuantLib::BlackScholesCalculator(m_option, m_price, for_disc, stdev, cur_disc));
}


BlackScholesPricer::BlackScholesPricer(const BlackScholesPricer &p)
:m_price(p.m_price),
m_strike(p.m_strike),
m_tau(p.m_tau),
m_rate(p.m_rate),
m_frate(p.m_frate),
m_vol(p.m_vol),
m_isCall(p.m_isCall),
m_calc(p.m_calc)
{}


BlackScholesPricer::∼BlackScholesPricer() {}

BlackScholesPricer &BlackScholesPricer::operator=(const BlackScholesPricer &p)
{
   if (this != &p)
   {
      m_price = p.m_price;
      m_strike = p.m_strike;
      m_tau = p.m_tau;
      m_rate = p.m_rate;
      m_frate = p.m_frate;
      m_vol = p.m_vol;
      m_isCall = p.m_isCall;
      m_calc = p.m_calc;
   }
   return *this;
}

Using these definitions, the following member functions can be used to provide access to the results of the pricing algorithm. They rely on the m_calc member variable, which already contains this stored information.

double BlackScholesPricer::value() { return m_calc->value(); }

double BlackScholesPricer::delta() { return m_calc->delta(); }

double BlackScholesPricer::gamma() { return m_calc->gamma(); }

double BlackScholesPricer::theta() { return m_calc->theta(m_tau); }

double BlackScholesPricer::vega()  { return m_calc->vega(m_tau);  }

Complete Code

Listing 14-1 shows the BlackScholesPrices class. It shows an examples of how create an interface for the Black-Scholes component in QuantLib.

Listing 14-1. Implementation File BlackScholesPrices.cpp
#include <ql/quantlib.hpp>

#include <ql/pricingengines/blackcalculator.hpp>

//
// The BlackScholesPricer class provides an interface to the QuantLib
// pricer component
//
class BlackScholesPricer {
public:
   BlackScholesPricer(bool call, double price, double strike, double tau, double r, double fr, double vol);
   BlackScholesPricer(const BlackScholesPricer &p);
   ∼BlackScholesPricer();
   BlackScholesPricer &operator=(const BlackScholesPricer &p);


   double value();

   double delta();
   double gamma();
   double theta();
   double vega();
private:
   double m_price;
   double m_strike;
   double m_tau;
   double m_rate;
   double m_frate;
   double m_vol;
   double m_isCall;


   boost::shared_ptr<QuantLib::BlackScholesCalculator> m_calc;
};


BlackScholesPricer::BlackScholesPricer(bool call, double price, double strike, double tau, double r, double fr, double vol)
:m_price(price),
m_strike(strike),
m_tau(tau),
m_rate(r),
m_frate(fr),
m_vol(vol),
m_isCall(call)
{
   boost::shared_ptr<QuantLib::PlainVanillaPayoff>
      m_option (new QuantLib::PlainVanillaPayoff(call ? QuantLib::Option::Call : QuantLib::Option::Put, strike));


   // compute discount rates
   double cur_disc = std::exp(-m_rate  * m_tau);  // current discount rate
   double for_disc = std::exp(-m_frate * m_tau);  // forward discount rate
   double stdev    = m_vol * std::sqrt(m_tau);    // standard deviation


   m_calc.reset(new QuantLib::BlackScholesCalculator(m_option, m_price, for_disc, stdev, cur_disc));
}


BlackScholesPricer::BlackScholesPricer(const BlackScholesPricer &p)
:m_price(p.m_price),
m_strike(p.m_strike),
m_tau(p.m_tau),
m_rate(p.m_rate),
m_frate(p.m_frate),
m_vol(p.m_vol),
m_isCall(p.m_isCall),
m_calc(p.m_calc)
{}


BlackScholesPricer::∼BlackScholesPricer() {}

BlackScholesPricer &BlackScholesPricer::operator=(const BlackScholesPricer &p)
{
   if (this != &p)
   {
      m_price = p.m_price;
      m_strike = p.m_strike;
      m_tau = p.m_tau;
      m_rate = p.m_rate;
      m_frate = p.m_frate;
      m_vol = p.m_vol;
      m_isCall = p.m_isCall;
      m_calc = p.m_calc;
   }
   return *this;
}


double BlackScholesPricer::value()
{
   return m_calc->value();
}


double BlackScholesPricer::delta()
{
   return m_calc->delta();
}


double BlackScholesPricer::gamma()
{
   return m_calc->gamma();
}


double BlackScholesPricer::theta()
{
   return m_calc->theta(m_tau);
}


double BlackScholesPricer::vega()
{
   return m_calc->vega(m_tau);
}

To compile this code, you need to install the QuantLib library for your platform and add that library to the project. For example, using the gcc compiler, you need to use the –lQuantLib option.

Conclusion

Using good libraries is an important aspect of effective software development. Financial code, especially when options and derivatives are involved, requires the use of efficient and well-tested algorithms. For this reason, it is important that developers be acquainted with high-quality libraries that can be used to simplify the development process.

In this chapter, you learned about some libraries, such as boost and QuantLib, which have been successfully used to create financial applications handling options and other derivatives. The first example was from the boost repository, which contains several special-purpose libraries that use modern C++ features. The odeint library in particular, which is contained in the boost repository, can be used to simplify the computation of solutions to ODEs.

Another important library used in the financial software community is QuantLib. This open source financial library provides many useful algorithms implemented in modern, efficient C++. You saw examples of common utilities provided by QuantLib. The most common classes are for date handling. These utility classes can handle business calendars, date intervals, and sequences in a way that makes it possible to handle financial applications.

You also saw how to use QuantLib to quickly create options and derivative models. The BlackScholesCalculator class encapsulates the solution to the Black-Scholes model. This model is the basis for most techniques that can be used to analyze prices and variations of values for financial derivatives.

The next chapter will cover additional algorithms that can be used to process more complex derivatives, with special attention to credit derivatives. These algorithms with be compared and implemented in C++.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.229.143