This post is also available in: en, en and en

C++ Fundamentals and My First Option Class

Introduction and objectives

In this chapter we design and implement our first real working C++ code. Our goal is to model a European option by a C++ class. We know that a class has a member data and member functions in general and in this case we model the following option attributes:

  • Strike price
  • Volatility
  • Risk-free interest rate
  • Expiry date as member data. Furthermore, we are interested in designing call and put options as well as modelling some of their interesting properties, namely option price and option sensitivities, for example:
  • Option delta
  • Option gamma
  • Other option sensitivities (for more options, see Haug, 1998) We set up basic infraestructure by implementing the software in two files. First, we define the EuropeanOption class in a so-called header file. This means that we declare the option's member data and member functions in this file. It can be seen as a specification of the class. Second, we implement the functions that were declared in the header file and this is done in a so-called code file. Together, these two files describe the class. It is possible to use just one file but we prefer using two files because the code is easier to maintain in this case.

We take a well-known example, in this case a European Option. We implement it in C++ and in this way the reader will become familiar with C++ syntax and the object-oriented way of thinking as soon as possible. In later chapters we shall add more functionality to this class. This is the best way to learn, namely step-by-step.

The following topics will be discussed in this chapter:

  • Creating my first C++ class: separating class design issues from class implementation.
  • Member data and member functions in C++; the different categories of member functions.
  • Determining accessibility levels in a class.
  • Using the EuropeanOption class in test programs and applications.

After having studied this chapter you will have gained a good understanding of a basic C++ class. Having understood the topics in this chapter we then proceed to more advanced functionality in chapter four. In particular, we discuss a number of C++ features in more detail.

The C++ class that we introduce in this chapter implements the closed form solution for the Black-Scholes equation and it will be used in later chapters to test the accuracy of approximate methods such as the binomial method and finite difference schemes.

Class == member data + member functions

In general, programming any class involves -- grosso modo -- determining its member functions and member data. We are working in Financial Engineering and in order to reduce the scope here we examine European options.

C++ is an example of a class-based object-oriented language. A class is a description of a group of related attributes and operations. In C++ we use the synonyms member data for attributes and member functions* for operations. The member data and member functions are closely related. This feature is called encapsulation*. In short, the class's functions know which attributes to use. Let us take an example of a class implementing European options for stocks. The defining parameters for the European option will be designed in C++ as the following member data:

  • The risk-free interest rate: $r$.
  • The volatility of the relative price change: $\sigma$.
  • The strike price: $K$.
  • The time to expiration (in years): $T$.
  • The stock price: $S$ (or $U$ depending on the underlying).
  • The cost-of-carry: $b$. The cost-of-carry for the Black-Scholes model has the same value as $r$ but will have different values depending on the type of underlying asset (for example, $b=0$ for a future option), see Haug, 1998). We must define the data types of the member data. In this case we usually design them as double precision number although C++ allows us to design classes with so-called generic data types. This means that the member data can be customized with different specific data types depending on the current requirements. Having defined the member data we now must decide what to do with the data. To this end, we introduce the concept of object (or instance of a class). A class is abstract in the sense that is member data have not been instantiated (or instance of a class). A class is abstract in the sense that is member data have not been instantiated (they are just abstract descriptions of data) while an object is tangible and all its member data have been initialised. For example, the following assignments describe a European option on an index (Haug, 1998, p. 15):
  • Underlying value (stock price index) $U=500$.
  • Volatility $\sigma = 0.15$.
  • Strike Price $K=490$.
  • Time to expiry $T=0.25$ ($3$ months).
  • Risk-free interest rate $r=0.08$.
  • Cost-of-carry $b=0.03$. Having discussed member data we now describe the functionality of classes and objects. In general, a class has member functions that model the lifecycle of an object. The main categories in general are:
  • Member functions (constructors) for creation of objetcs.
  • Member functions that modify the member data (modifiers).
  • Member functions that perform calculations on the member data (selectors).
  • A member function (destructor) that deletes an object when no longer needed. There are various ways to create an object using constructors. For example, it is possible to create an instance of a European option class by initialising its member data. Two other constructors deserve mention: first, the default constructor creates an object with default member data while the copy constructor creates an object as a deep copy of some other object. The destructor is the other extreme; it removes the object from memory when the object is no longer needed. We note that the names of constructors and of the destructor are the same as the name of their corresponding class.

We now discuss the member functions that operate on an object after it has been constructed and before it is destructed. Again, we concentrate on the class for European options.

C++ is based on the message-passing paradigm. This means that client code sends a message to an object by calling its member functions. For example, here is a piece of code that calculates the price of the index put option that we introduced earlier (we assume that the member data have been initialised):

The header file (function prototypes)

In general, the code that is needed for a complete description of a class in C++ is contained in two files: first, the header file (this section) and this contains the formal descriptions of the member data and member functions in the class. Second, the code file contains the body of each declared member function. In other words, each member function declaration in the header file must have a corresponding entry in the code file.

We now discuss the details of the header file. First, there are two regions or parts called private and public, respectively. Both parts may contain member data and member functions. Members that are declared in the private part are not accessible from outside the class and may only be accessed by members in the class itself while public members may be accessed by any C++ code. In general, all data should be declared in the private part because this tends to change; however, in this chapter we place the data that represents the structure of an option in the public area. This is for convenience only.

The public member functions in the options class can be categorised as follows (see the code below):

  • Constructors: the different ways of creating instances of option class.
  • Destructors: deleting an object when it is no longer needed (automatically taken care of by the runtime system).
  • Assignment operator: the ability to assign one object to another object (this is a 'deepy' copy).
  • 'Core business' functions: these are the functions that calculate the price and the delta for the option, for example.
  • Other functions: for example, it is possible to switch a call option to a put option (and viceversa). Of course, the price and delta will be different!
In [4]:
!cat EuropeanOption.hpp
// EuropeanOption2.hpp
//
// Class that represents  solutions to European options. This is
// an implementation using basic C++ syntax only. It has been 
// written for pedagogical reasons
//
// (C) Datasim Component Technology BV 2003-2006
//

#ifndef EuropeanOption_hpp
#define EuropeanOption_hpp

#include <cmath>
#include <string>

class EuropeanOption
{
public:				// For TEST purposes only

	void init();	// Initialise all default values
	void copy(const EuropeanOption& o2);

	// 'Kernel' functions for option calculations
	double CallPrice() const;
	double PutPrice() const;
	double CallDelta() const;
	double PutDelta() const;
	double CallGamma() const;
	double PutGamma() const;
	double CallVega() const;
	double PutVega() const;
	
	// Gaussian functions
	double n(double x) const;
	double N(double x) const;


	double r;		// Interest rate
	double sig;	// Volatility
	double K;		// Strike price
	double T;		// Expiry date
	double U;		// Current underlying price (e.g. stock, forward)
	double b;		// Cost of carry

	std::string optType;	// Option name (call, put)
	std::string unam;	// Name of underlying asset


public:	// Public functions
	EuropeanOption();							// Default call option
	EuropeanOption(const EuropeanOption& option2);	// Copy constructor
	EuropeanOption (const std::string& optionType);	// Create option type
	virtual ~EuropeanOption();	

	EuropeanOption& operator = (const EuropeanOption& option2);

	// Functions that calculate option price and sensitivities
	double Price() const;
	double Delta() const;

	// Modifier functions
	void toggle();		// Change option type (C/P, P/C)


};

#endif

The class body (code file)

Having discussed the function prototypes for the option class, we need to describe how to fill in the body of the code for these functions. To this end, there are two major issues to be addresed. First, we must include the header file and other headers of libraries that are needed by the code. In this case, this leads to:

In [7]:
#include "EuropeanOption.hpp" //Declarations of functions
#include <cmath> // For mathematical functions, e.g. exp()
In [2]:
double EuropeanOption::PutPrice() const
{
    double tmp = sig * std::sqrt(T);
    
    double d1 = (std::log(U/K) + (b + (sig*sig)*0.5)*T)/tmp;
    double d2 = d1 - tmp;
    
    return (K * std::exp(-r*T)* N(-d2)) - (U*std::exp((b - r)*T)* N(-d1));
        
}
In [3]:
!cat EuropeanOption.cpp
// EurpeanOption.cpp
//
//	Author: Daniel Duffy
//
// (C) Datasim Component Technology BV 2003
//

#ifndef EuropeanOption_cpp
#define EuropeanOption_cpp


#include "EuropeanOption.hpp"

//////////// Gaussian functions /////////////////////////////////

double EuropeanOption::n(double x) const
{ 

	double A = 1.0/std::sqrt(2.0 * 3.1415);
	return A * std::exp(-x*x*0.5);

}

double EuropeanOption::N(double x) const
{ // The approximation to the cumulative normal distribution


	double a1 = 0.4361836;
	double a2 = -0.1201676;
	double a3 = 0.9372980;

	double k = 1.0/(1.0 + (0.33267 * x));
	
	if (x >= 0.0)
	{
		return 1.0 - n(x)* (a1*k + (a2*k*k) + (a3*k*k*k));
	}
	else
	{
		return 1.0 - N(-x);
	}

}


// Kernel Functions (Haug)
double EuropeanOption::CallPrice() const
{

	double tmp = sig * std::sqrt(T);

	double d1 = ( std::log(U/K) + (b+ (sig*sig)*0.5 ) * T )/ tmp;
	double d2 = d1 - tmp;


	return (U * std::exp((b-r)*T) * N(d1)) - (K * std::exp(-r * T)* N(d2));

}

double EuropeanOption::PutPrice() const
{

	double tmp = sig * std::sqrt(T);

	double d1 = ( std::log(U/K) + (b+ (sig*sig)*0.5 ) * T )/ tmp;
	double d2 = d1 - tmp;

	return (K * std::exp(-r * T)* N(-d2)) - (U * std::exp((b-r)*T) * N(-d1));

}

double EuropeanOption::CallDelta() const
{
	double tmp = sig * sqrt(T);

	double d1 = ( std::log(U/K) + (b+ (sig*sig)*0.5 ) * T )/ tmp;


	return std::exp((b-r)*T) * N(d1);
}

double EuropeanOption::PutDelta() const
{
	double tmp = sig * std::sqrt(T);

	double d1 = ( std::log(U/K) + (b+ (sig*sig)*0.5 ) * T )/ tmp;

	return std::exp((b-r)*T) * (N(d1) - 1.0);
}



/////////////////////////////////////////////////////////////////////////////////////

void EuropeanOption::init()
{	// Initialise all default values

	// Default values
	r = 0.08;
	sig= 0.30;
	K = 65.0;
	T = 0.25;
	U = 60.0;		// U == stock in this case
	b = r;			// Black and Scholes stock option model (1973)

	optType = "C";		// European Call Option (this is the default type)



}

void EuropeanOption::copy(const EuropeanOption& o2)
{

	r	= o2.r;
	sig = o2.sig;	
	K	= o2.K;
	T	= o2.T;
	U	= o2.U;
	b	= o2.b;
	
	optType = o2.optType;


	
}

EuropeanOption::EuropeanOption() 
{ // Default call option

	init();
}

EuropeanOption::EuropeanOption(const EuropeanOption& o2)
{ // Copy constructor

	copy(o2);
}

EuropeanOption::EuropeanOption (const std::string& optionType)
{	// Create option type

	init();
	optType = optionType;

	if (optType == "c")
		optType = "C";

}



EuropeanOption::~EuropeanOption()
{

}


EuropeanOption& EuropeanOption::operator = (const EuropeanOption& option2)
{

	if (this == &option2) return *this;

	copy (option2);

	return *this;
}

// Functions that calculate option price and sensitivities
double EuropeanOption::Price() const 
{

	if (optType == "C")
	{
		return CallPrice();
	}
	else
		return PutPrice();

}

double EuropeanOption::Delta() const 
{
	if (optType == "C")
		return CallDelta();
	else
		return PutDelta();

}



// Modifier functions
void EuropeanOption::toggle()
{ // Change option type (C/P, P/C)

	if (optType == "C")
		optType = "P";
	else
		optType = "C";
}

#endif

Using the class

The code file is compiled and syntax errors should be resolved. We then need to write a program to test the class. The corresponding file is then compiled and linked with the other code to form an executable unit.

In this section we give an example of a test program. The object-oriented paradigm is based on the message-passing metaphor. Here we mean that client software sends messages to an object (by means of member function calls) by using the so-called dot notation. For example, to calculate the price of an existing option instance we code as follows:

double option_price = myOption.Price();
In [5]:
!cat TestEuropeanOption.cpp
// TestEuropeanOption.cpp
//
// Test program for the exact solutions of European options. 
// Check answers with Haug 1998
//
// (C) Datasim Component Technology BV 2003-2006
//

#include "EuropeanOption.hpp"
#include <iostream>

int main()
{ // All options are European

	// Call option on a stock
	EuropeanOption callOption;
	std::cout << "Call option on a stock: " << callOption.Price() << std::endl;
	
	// Put option on a stock index
	EuropeanOption indexOption;
	indexOption.optType = "P";
	indexOption.U = 100.0;
	indexOption.K = 95.0;
	indexOption.T = 0.5;
	indexOption.r = 0.10;
	indexOption.sig = 0.20;

	double q = 0.05;		// Dividend yield
	indexOption.b = indexOption.r - q;

	std::cout << "Put option on an index: " << indexOption.Price() << std::endl;

	// Call and put options on a future
	EuropeanOption futureOption;
	futureOption.optType = "P";
	futureOption.U = 19.0;
	futureOption.K = 19.0;
	futureOption.T = 0.75;
	futureOption.r = 0.10;
	futureOption.sig = 0.28;

	futureOption.b = 0.0;

	std::cout << "Put option on a future: " << futureOption.Price() << std::endl;

	// Now change over to a call on the option
	futureOption.toggle();
	std::cout << "Call option on a future: " << futureOption.Price() << std::endl;


	// Call option on currency
	EuropeanOption currencyOption;
	currencyOption.optType = "C";
	currencyOption.U = 1.56;
	currencyOption.K = 1.60;
	currencyOption.T = 0.5;
	currencyOption.r = 0.06;
	currencyOption.sig = 0.12;

	double rf = 0.08;		// risk-free rate of foreign currency
	currencyOption.b = currencyOption.r - rf;

	std::cout << std::endl << "** Other pricing examples **" << std::endl << std::endl;

	std::cout << "Call option on a currency: " << currencyOption.Price() << std::endl;

	////////   NOW CALCULATIONS OF SENSITIVITIES //////////////////////////////////

	// Call and put options on a future: Delta and Elasticity
	EuropeanOption futureOption2;
	futureOption2.optType = "P";
	futureOption2.U = 105.0;
	futureOption2.K = 100.0;
	futureOption2.T = 0.5;
	futureOption2.r = 0.10;
	futureOption2.sig = 0.36;

	futureOption2.b = 0.0;

	std::cout << "Delta on a put future: " << futureOption2.Delta() << std::endl;

	// Now change over to a call on the option
	futureOption2.toggle();
	std::cout << "Delta on a call future: " << futureOption2.Delta() << std::endl;

	
	// Stock Option: Gamma
	EuropeanOption stockOption;
	stockOption.optType = "C";
	stockOption.U = 55.0;
	stockOption.K = 60.0;
	stockOption.T = 0.75;
	stockOption.r = 0.10;
	stockOption.sig = 0.30;

	stockOption.b = stockOption.r;


	stockOption.toggle();

	// Calculating theta of a European stock index
	EuropeanOption indexOption2;
	indexOption2.optType = "P";
	indexOption2.U = 430.0;
	indexOption2.K = 405.0;
	indexOption2.T = 0.0833;	// One month expiration
	indexOption2.r = 0.07;
	indexOption2.sig = 0.20;

	double divYield = 0.05;		// Dividend yield, 5% per annum
	indexOption2.b = indexOption2.r - divYield;


	// Stock Option: Rho
	EuropeanOption stockOption2;
	stockOption2.optType = "C";
	stockOption2.U = 72.0;
	stockOption2.K = 75.0;
	stockOption2.T = 1.0;
	stockOption2.r = 0.09;
	stockOption2.sig = 0.19;

	stockOption2.b = stockOption2.r;

	// Calculating Cost of Carry of a European stock index
	EuropeanOption indexOption3;
	indexOption3.optType = "P";
	indexOption3.U = 500.0;
	indexOption3.K = 490.0;
	indexOption3.T = 0.222225;
	indexOption3.r = 0.08;
	indexOption3.sig = 0.15;

	double divYield3 = 0.05;		// Dividend yield, 5% per annum
	indexOption3.b = indexOption3.r - divYield3 ;

	return 0;
}
In [1]:
#include <iostream>
#include "EuropeanOption.cpp"
{
    EuropeanOption callOption;
    std::cout << "Call option on a stock: " << callOption.Price() << std::endl;
    
    // Put option on a stock index
    EuropeanOption indexOption;
    indexOption.optType = "P";
    indexOption.U = 100.0;
    indexOption.K = 95.0;
    indexOption.T = 0.5;
    indexOption.r = 0.10;
    indexOption.sig = 0.20;
    
    double q = 0.05; // Dividend yield
    indexOption.b = indexOption.r - q;
    
    std::cout << "Put option on an index: " << indexOption.Price() << std::endl;

    // Call and put options on a future
	EuropeanOption futureOption;
	futureOption.optType = "P";
	futureOption.U = 19.0;
	futureOption.K = 19.0;
	futureOption.T = 0.75;
	futureOption.r = 0.10;
	futureOption.sig = 0.28;

	futureOption.b = 0.0;

	std::cout << "Put option on a future: " << futureOption.Price() << std::endl;

	// Now change over to a call on the option
	futureOption.toggle();
	std::cout << "Call option on a future: " << futureOption.Price() << std::endl;


	// Call option on currency
	EuropeanOption currencyOption;
	currencyOption.optType = "C";
	currencyOption.U = 1.56;
	currencyOption.K = 1.60;
	currencyOption.T = 0.5;
	currencyOption.r = 0.06;
	currencyOption.sig = 0.12;

	double rf = 0.08;		// risk-free rate of foreign currency
	currencyOption.b = currencyOption.r - rf;

	std::cout << std::endl << "** Other pricing examples **" << std::endl << std::endl;

	std::cout << "Call option on a currency: " << currencyOption.Price() << std::endl;

	////////   NOW CALCULATIONS OF SENSITIVITIES //////////////////////////////////

	// Call and put options on a future: Delta and Elasticity
	EuropeanOption futureOption2;
	futureOption2.optType = "P";
	futureOption2.U = 105.0;
	futureOption2.K = 100.0;
	futureOption2.T = 0.5;
	futureOption2.r = 0.10;
	futureOption2.sig = 0.36;

	futureOption2.b = 0.0;

	std::cout << "Delta on a put future: " << futureOption2.Delta() << std::endl;

	// Now change over to a call on the option
	futureOption2.toggle();
	std::cout << "Delta on a call future: " << futureOption2.Delta() << std::endl;

	
	// Stock Option: Gamma
	EuropeanOption stockOption;
	stockOption.optType = "C";
	stockOption.U = 55.0;
	stockOption.K = 60.0;
	stockOption.T = 0.75;
	stockOption.r = 0.10;
	stockOption.sig = 0.30;

	stockOption.b = stockOption.r;


	stockOption.toggle();

	// Calculating theta of a European stock index
	EuropeanOption indexOption2;
	indexOption2.optType = "P";
	indexOption2.U = 430.0;
	indexOption2.K = 405.0;
	indexOption2.T = 0.0833;	// One month expiration
	indexOption2.r = 0.07;
	indexOption2.sig = 0.20;

	double divYield = 0.05;		// Dividend yield, 5% per annum
	indexOption2.b = indexOption2.r - divYield;


	// Stock Option: Rho
	EuropeanOption stockOption2;
	stockOption2.optType = "C";
	stockOption2.U = 72.0;
	stockOption2.K = 75.0;
	stockOption2.T = 1.0;
	stockOption2.r = 0.09;
	stockOption2.sig = 0.19;

	stockOption2.b = stockOption2.r;

	// Calculating Cost of Carry of a European stock index
	EuropeanOption indexOption3;
	indexOption3.optType = "P";
	indexOption3.U = 500.0;
	indexOption3.K = 490.0;
	indexOption3.T = 0.222225;
	indexOption3.r = 0.08;
	indexOption3.sig = 0.15;

	double divYield3 = 0.05;		// Dividend yield, 5% per annum
	indexOption3.b = indexOption3.r - divYield3 ;
    
}
Call option on a stock: 2.13293
Put option on an index: 2.4648
Put option on a future: 1.70118
Call option on a future: 1.70118

** Other pricing examples **

Call option on a currency: 0.0290937
Delta on a put future: -0.356609
Delta on a call future: 0.59462

Examining the class in detail

The code implements the class for a plain one-factor option has been discussed in some detail in the previous section. We have not done justice to all the detaills but our objective was to create working code as soon as possible in the book. Furthermore, we shall discuss the syntax in greater detail in later chapters, especially Chapter 4.

Nonetheless, it is advisable at this stage to say something about the syntax that we use here. In this sense we avoid forward references.

Accessibility issues

A class contains of members in general. A member is either a member data or a member function. All members in a class are accessible from any other members of the class. However, a class can decide to expose certain members to outside clients just as it can decide to keep some members hidden from the outside world. To this end, we can define private and public member areas:

  • Public member: any client can access it.
  • Private member: not accessible to clients, only to member of the class.

In general, data and functions are tightly coupled and this principle is called encapsulation. In general, it is advisable to define data to be private because this feature seems to be the most volatile part of a class interface. In this chapter the member data are public but this is for convenience only.

Using standard libraries

In later chapters we shall introduce the Standard Template Library (STL), a library of template classes or containers, algorithms that operate on those containers and so-called iterators that allow us to navigate in the containers.

Some important data containers are:

  • Vectors.
  • Lists.
  • Maps (or dictionaries).

It is important to note at this stage that it is not necessary to create your own data containers and corresponding algorithms.

The scope resolution ::

Contrary to C and other procedural languages, C++ allows us to define member functions as elements of a class. To make this relationship explicit we use the so-called scope resolution operator ::, for example:

double EuropeanOption::Price() const
{
    if (optType == "C")
    {
        return CallPrice();
    }
    else
        return PutPrice();
}

In this case the pricing function belongs to the given option class.

Virtual destructor: better safe than sorry

We start with a conclusion:

Declare all destructors to be virtual.

The reason why this is so will discussed in a later chapter. Failing to declare a destructor to be virtual may result in memory problems, so we play safe.

Other paradigms

The first example in this chapter was a C++ class that models plain one-factor options. This is a good application of the object-oriented paradigm: we encapsulate tightly-coupled data representing an option's parameter and we then create member functions that act on that data. Before we go overboad by thinking that everything in sight must be a class or object we mention that there are other paradigms that are just as effective and that can be used in conjunction with, or as a competitor to, the object-oriented paradigm. To this end, we show how modular programming techniques can be used in Quantitative Finance by taking some simple examples of interest rate calculations (see Fabozzi 1993; Hull, 2006). The examples are not difficult but we use them because they elaborate on a number of coding issues that will be needed in this book.

We have created a number of functions for the following kinds of calculations:

  • Calculating the future value of a sum of money (paid once per year, $m$ times a year and continous compounding).
  • Future value of an ordinary annuity.
  • Simple present value calculations.
  • Present value of a series of future values.
  • Present value of an ordinary annuity. As usual, we create two files, one (the header) containing function declarations and the other one containing code. The header file is given by:
In [3]:
!cat SimpleBondPricing.hpp
// SimpleBondPricing.hpp
//
// Simple functions for interest rate calcuations.
//
// (C) Datasim Education BV 2006
//

#ifndef SimpleBondPricing_HPP
#define SimpleBondPricing_HPP

#include <vector>
#include <cmath>
#include <cassert>

namespace Chapter3CPPBook // Logical grouping of functions and others
{

	// Handy shorthand synonyms
	typedef std::vector<double> Vector;

	// Recursive function to calculate power of a number. This 
	// function calls itself, either directly or indirectly
	double power(double d, long n);

	// Future value of a sum of money invested today
	double FutureValue(double P0, long nPeriods, double r);

	// Future value of a sum of money invested today, m periods 
	// per year. r is annual interest rate
	double FutureValue(double P0, long nPeriods, double r, long m);

	// Continuous compounding, i.e. limit as m -> INFINITY
	double FutureValueContinuous(double P0, long nPeriods, double r);

	// Future value of an ordinary annuity
	double OrdinaryAnnuity(double A, long nPeriods, double r);

	// Present Value
	double PresentValue(double Pn, long nPeriods, double r);

	// Present Value of a series of future values
	double PresentValue(const Vector& prices, long nPeriods, double r);

	// Present Value of an ordinary annuity
	double PresentValueOrdinaryAnnuity(double A, long nPeriods, double r);

}

#endif
In [4]:
!cat SimpleBondPricing.cpp
// SimpleBondPricing.cpp
//
// Simple functions for interest rate calcuations.
//
// Last Modfication dates:
// 
// 2006-2-21 DD Kick-off
// 2006-2-22 DD Small bug removed
//
// (C) Datasim Education BV 2006
//

#ifndef SimpleBondPricing_CPP
#define SimpleBondPricing_CPP

#include "SimpleBondPricing.hpp"

namespace Chapter3CPPBook 
{

	// Recursive function to calculate power of a number. This 
	// function calls itself, either directly or indirectly
	double power(double d, long n)
	{
		if (n == 0) return 1.0;
		if (n == 1) return d;

		double result = d;
		for (long j = 1; j < n; j++)
		{
			result *= d;
		}

		return result;

	}

	// Future value of a sum of money invested today
	double FutureValue(double P0, long nPeriods, double r)
	{

		double factor = 1.0 + r;
		return P0 * power(factor, nPeriods);
	}

	// Future value of a sum of money invested today, m periods 
	// per year. r is annual interest rate
	double FutureValue(double P0, long nPeriods, double r, long m)
	{
		double R = r / double(m);
		long newPeriods = m * nPeriods;

		return FutureValue(P0, newPeriods, R);
	}

	// Continuous compounding
	double FutureValueContinuous(double P0, long nPeriods, double r)
	{
					
		double growthFactor = std::exp(r * double(nPeriods) );
		
		return P0 * growthFactor;
	}

	// Future value of an ordinary annuity
	double OrdinaryAnnuity(double A, long nPeriods, double r)
	{

		double factor = 1.0 + r;
		return A * ((power(factor, nPeriods) - 1.0)/r);
	}

	// Present Value
	double PresentValue(double Pn, long nPeriods, double r)
	{
		
		double factor = 1.0 + r;
		return Pn * (1.0 / power(factor, nPeriods));
	}

	// Present Value of a series of future values
	double PresentValue(const Vector& prices, long nPeriods, double r)
	{
		// Number of periods MUST == size of the vector
		assert (nPeriods == prices.size());

		double factor = 1.0 + r;

		double PV = 0.0;

		for (long t = 0; t < nPeriods; t++)
		{
			PV += prices[t] / power(factor, t+1);
		}

		return PV;

	}


	// Present Value of an ordinary annuity
	double PresentValueOrdinaryAnnuity(double A, long nPeriods, double r)
	{

		double factor = 1.0 + r;
		double numerator = 1.0 - (1.0 / power(factor, nPeriods));
		return (A * numerator ) / r;
	}

}

#endif
In [6]:
!cat TestSimpleBondPricing.cpp
// TestSimpleBondPricing.cpp
//
// (C) Datasim Education BV 2006
//

#include "SimpleBondPricing.hpp"
#include <iostream>

int main()
{

	// Future value of a sum of money invested today
	long nPeriods = 6;				// 6 years
	double P = 10000000;	// Amount invested now
	double r = 0.092;		// 9.2% interest

	double fv = Chapter3CPPBook::FutureValue(P, nPeriods, r);

	std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::cout << "Future Value: " << fv << std::endl;

	long frequency = 2;
	double fv2 = Chapter3CPPBook::FutureValue(P, nPeriods, r, frequency);
//	cout.setf(0, ios_base::floatfield);

	std::cout << "Future Value, 2 periods: " << fv2 << std::endl;

	// Future value of a sum of money invested today, m periods 
	// per year. r is annual interest rate

	// Using: means that we search in NS for the functions
	using namespace Chapter3CPPBook;

	double P0 = 10000000; // 10 million
	r = 0.092;
	long m = 2;	// Twice per year
	nPeriods = 6;
	std::cout << "**Future with " << m << " periods: " << FutureValue(P0, nPeriods, r, m) << std::endl;

	// Future value of an ordinary annuity
	double A = 2000000;
	r = 0.08;
	nPeriods = 15;	// 15 years
	std::cout << "**Ordinary Annuity; " << OrdinaryAnnuity(A, nPeriods, r)  << std::endl;

	// Present Value
	double Pn = 5000000;
	r = 0.10;
	nPeriods = 7;
	std::cout << "**Present value: " << PresentValue(Pn, nPeriods, r) << std::endl;

	// Present Value of a series of future values
	Vector futureValues(5); // For five years
	for (long j = 0; j < 4; j++)
	{ // The first 4 years
		futureValues[j] = 100.0;
	}
	futureValues[4] = 1100.0;

	nPeriods = 5; // Redundant in a sense since this is in the vector
	r = 0.0625;
	std::cout << "**Present value, series: " << PresentValue(futureValues, nPeriods, r) << std::endl;

	// Present Value of an ordinary annuity
	A = 100.0;
	r = 0.09;
	nPeriods = 8;
	std::cout << "**PV, ordinary annuity: " << PresentValueOrdinaryAnnuity(A, nPeriods, r) << std::endl;

	// Now test periodic testing with continuous compounding
	P0 = 10000000;
	r = 0.092;
	nPeriods = 6;
	for (long mm = 1; mm <= 10000000; mm *=12)
	{
		std::cout << "Periodic: " << mm << ", " << FutureValue(P0, nPeriods, r, mm) << std::endl;

	}

	std::cout << "Continuous Compounding: " << FutureValueContinuous(P0, nPeriods, r);

	return 0;
}
In [9]:
#include "SimpleBondPricing.cpp"
#include <iostream>
In [10]:
{
    // Future value of a sum of money invested today
	long nPeriods = 6;				// 6 years
	double P = 10000000;	// Amount invested now
	double r = 0.092;		// 9.2% interest

	double fv = Chapter3CPPBook::FutureValue(P, nPeriods, r);

	std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::cout << "Future Value: " << fv << std::endl;

	long frequency = 2;
	double fv2 = Chapter3CPPBook::FutureValue(P, nPeriods, r, frequency);
    //	cout.setf(0, ios_base::floatfield);

	std::cout << "Future Value, 2 periods: " << fv2 << std::endl;

	// Future value of a sum of money invested today, m periods 
	// per year. r is annual interest rate

	// Using: means that we search in NS for the functions
	using namespace Chapter3CPPBook;

	double P0 = 10000000; // 10 million
	r = 0.092;
	long m = 2;	// Twice per year
	nPeriods = 6;
	std::cout << "**Future with " << m << " periods: " << FutureValue(P0, nPeriods, r, m) << std::endl;

	// Future value of an ordinary annuity
	double A = 2000000;
	r = 0.08;
	nPeriods = 15;	// 15 years
	std::cout << "**Ordinary Annuity; " << OrdinaryAnnuity(A, nPeriods, r)  << std::endl;

	// Present Value
	double Pn = 5000000;
	r = 0.10;
	nPeriods = 7;
	std::cout << "**Present value: " << PresentValue(Pn, nPeriods, r) << std::endl;

	// Present Value of a series of future values
	Vector futureValues(5); // For five years
	for (long j = 0; j < 4; j++)
	{ // The first 4 years
		futureValues[j] = 100.0;
	}
	futureValues[4] = 1100.0;

	nPeriods = 5; // Redundant in a sense since this is in the vector
	r = 0.0625;
	std::cout << "**Present value, series: " << PresentValue(futureValues, nPeriods, r) << std::endl;

	// Present Value of an ordinary annuity
	A = 100.0;
	r = 0.09;
	nPeriods = 8;
	std::cout << "**PV, ordinary annuity: " << PresentValueOrdinaryAnnuity(A, nPeriods, r) << std::endl;

	// Now test periodic testing with continuous compounding
	P0 = 10000000;
	r = 0.092;
	nPeriods = 6;
	for (long mm = 1; mm <= 10000000; mm *=12)
	{
		std::cout << "Periodic: " << mm << ", " << FutureValue(P0, nPeriods, r, mm) << std::endl;

	}

	std::cout << "Continuous Compounding: " << FutureValueContinuous(P0, nPeriods, r);
}
Future Value: 16956485.006864
Future Value, 2 periods: 17154584.929442
**Future with 2 periods: 17154584.929442
**Ordinary Annuity; 54304227.854957
**Present value: 2565790.591154
**Present value, series: 1156.895096
**PV, ordinary annuity: 553.481911
Periodic: 1, 16956485.006864
Periodic: 12, 17330706.083117
Periodic: 144, 17364169.079167
Periodic: 1728, 17366974.736354
Periodic: 20736, 17367208.660596
Periodic: 248832, 17367228.155581
Periodic: 2985984, 17367229.774378
Continuous Compounding: 17367229.927213

Published

Last Updated

Category

c++

Tags

Contact