Homework 0
Simple Binomial Option Pricing Model

Computational Finance

Copyright © Philip H. Dybvig 1996

Scenario Your boss wants to develop in-house the capability to use a binomial model to compute theoretical prices and hedges for various traditional and exotic options. This homework represents the first step in carrying out that assignment.

Action To start getting familiar with C++ programming, you will take the existing program discussed in the first class and work to get it running. Then, you will make some very minor changes as an initial step in the program development process. There are also some questions to encourage further understanding. Additional challenges are available for students with superior preparation or ambition.

Concept The finance application is the binomial model we reviewed in class. Many parts of the computer program may remain mysterious to you even after this week's explanation, but that is not a bad thing. In my experience, learning computer programming is more interesting and more rapid when we start with a fully functional (albeit simple) application than when building from the bottom up. The course book contains more of a detailed bottom-up perspective and will help to fill in the details.

Instructions In each of the following steps, provide a crisply written answer. For the program changes, write a short concise description of the changes you made and why. For thought questions, think about the question and answer in no more than two sentences of ordinary length. As in business, writing that is concise and to the point is appreciated. Unnecessarily long answers may be penalized.

  1. Put the program files (crrtest.cc, crr.cc, and crr.h ) in a directory on your machine where you want to work. Compile the program and run it, trying different values for the options's strike price and the underlying stock price. (Do not change any of the programs for this step.)
  2. Modify the test program file crrtest.cc to use a standard deviation of .5 instead of .3, leaving the other parameters unchanged. (Do not change crr.cc or crr.h.)
  3. Modify the test program file crrtest.cc to test the binary option feature of crr instead of the call option feature. This will require the input of three numbers, the stock price, the lower cutoff, and the upper cutoff. (Do not change crr.cc or crr.h.)
  4. Thought question Short of implementing a full mouse-driven interface (which is possible with the modules usually bundled with C++ compilers or the operating system), what additional features would you like to include in this program for the convenience of end users?
Extra for Experts
  1. Add a function to crr that will value a payoff that is polynomial in the stock price. If you like, fix the order of the polynomial (e.g. make it quadratic), but it is better if the user can specify the order of the polynomial when calling the function.
A Quick Tour of the Program Files

The program files are contained in Exhibits A, B, and C. The program files and critical pieces of the program contain "crr" in honor of Cox, Ross, and Rubinstein, who are the original developers of the binomial model now used widely in practice.

The header file Exhibit A contains the header file, crr.h, which gives type declarations for a number of variables. Type declarations help to protect us from common programming errors in a language like C++. At the level of machine language in the computer, there is no distinction between different types of number, representing integers, floating point numbers, characters, addresses, functions, or input-output ports, except for context. Type declaration forces us to define the context and use numbers consistently in different places. This discipline helps us to eliminate many common programming errors. The header file is included at the beginning of all files in which the variables are used to ensure consistent usage.

The particular header file crr.h contains a single large declaration for a class called "crr" which defines a new type of simulation object. An object in C++ is a collection of variables and associated functions that operate on the variables. This mode of organization (which makes C++ an object-oriented language) does not change the set of possible things we can do with the computer, but it does tend to minimize mistakes. It also makes the program much easier to maintain (for ourselves or for others), since it gathers in one place all the parts of the program that are likely to need to be changed at the same time. The header file is like an outline, it defines some of the program's properties but does not do any of the real work.

The test program file Exhibit B contains the file crrtest.cc which is used to test the program outlined in the header file. Different C++ compilers assume different suffixes for C++ filenames. You may have to rename your files with the suffix that your compiler recognizes for C++ programs, for example from crrtest.cc to crrtest.cpp and from crr.cc to crr.cpp. Note the statement

#include "crr.h"
near the top of the file. This is the command that includes the header information (as if it appeared here in the file). The program main is the program that is run once the program is compiled (converted into machine language that the computer can use directly) and started. Using an include file in this way avoids typing mistakes and is easy to understand and modify. The other include command
#include <iostream.h>
includes a system library for managing input-output data streams (e.g. from the keyboard, to the screen, or to-and-from files). The test program initializes an object called c1 ("see-one" not "see-el"-the computer is very literal) of type crr, whose function eurcall is applied to user-supplied arguments stock-price and strike-price. The output of this function is printed to the screen.

The implementation file While crr.h contains the organizational chart and crrtest.cc contains the boss's orders, crr.cc (shown in Exhibit C) is where the work is done. This contains the explicit details on how to compute the option prices and tells the computer step-by-step how to do the computations needed to work back through the tree. The member crr::crr is called a constructor and is used to initialize any object of type crr. (This constructor is called with default arguments in the line

crr c1;
in the test file.) The other definition in the file is for the public function eurcall that is made available to users.

The power of the computer comes from being able to perform very simple steps rapidly; the power of our program comes from telling the computer the general rule of what steps to perform rather than telling the computer each step individually. This is performed in the for-loops in the program (and in the while loop in the test file). The for-loop that varies j corresponds to moving earlier in time date-by-date to infer values, and the for-loop that varies i corresponds to looking at different stock prices on a given date.

There are a number of additional details in the program, probably more than any novice programmer can absorb at once. Let's turn instead to the practical mechanics of running the program we are given.

Compiling and Running the Program

You will want to compile your programs (convert them to machine language that the computer can run) and then run them. The exact details for compiling and running the program will differ from system to system. On my SUN SPARCstation, the compilation command is

CC -o crrtest crrtest.cc crr.cc
where CC is the C++ compiler command, -o crrtest is a ``compiler flag'' inicating that the executable file (runnable program) is to be called crrtest, and of course we have the names of the two C++ files to be compiled. (We do not have the name of the include file crr.h, which is called from within the C++ program files.) To run the compiled program (when I am fortunate enough to have a successful compilation), I simply use the command
crrtest
to run the compiled program.

More information on how to use various C++ compilers will be made available separately. This information will include instructions for using the compilers in the computer lab and pointers on how to handle some common problems you may encounter.

Exhibit A: the header file crr.h

// crr.h
//
// Simple binomial option pricing model: declarations
//
#define MAXTERNODES 400
class crr {
public:
  crr(double ttm=.25,int npers=4,double r=.05,double sigma=.3);
  double eurcall(double S0,double X);
  double binopt(double S0,double lower,double upper);

private:
  int nper;
  double tinc,r1per,disc,up,down,prup,prdn,Sprice;
  double val[MAXTERNODES];};
Exhibit B: the test file crrtest.cc
// crrtest.cc
//
// Binomial option pricing model: test
//
#include <iostream.h>
#include "crr.h"
main() {
  crr c1;
  double stockP,strikeP;
  cout << "\nType the stock price, a space, the strike"
    << " price, and then ENTER." << "\n"
    << "Make the stock price negative to terminate." << "\n\n";
  while(1) {
    cout << "stock-price strike-price: ";
    cin >> stockP >> strikeP;
    if(stockP < 0.0){
      cout << "\nBye!\n" << endl;
      return(0);}
    if(!cin){
      cout << "\nError: enter stock-price strike-price\n"
        << "Terminating\n" << endl;
      return(1);}
    cout << "call option value = " << c1.eurcall(stockP,strikeP)
      << "\n\n";}}
Exhibit C: the implementation file crr.cc
// crr.cc
//
// Simple binomial option pricing model: implementation
// (following Cox, Ross, and Rubinstein)
//
#include <math.h>
#include <iostream.h>
#include "crr.h"
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
crr::crr(double ttm,int npers,double r,double sigma) {
  nper = npers;
  tinc = ttm/(double) nper;
  r1per = 1.0 + r * tinc;
  disc = 1.0/r1per;
  up = r1per + sigma * sqrt(tinc);
  down = r1per - sigma * sqrt(tinc);
  prup = disc * 0.5;
  prdn = disc * 0.5;}

double crr::eurcall(double S0,double X) {
  int i,j;
// initialize terminal payoffs
// i is the number of up moves over the whole life
  for(i=0;i<=nper;i++) {
    Sprice = S0*pow(up,(double) i)*pow(down,(double) (nper-i));
    val[i] = MAX(Sprice - X,0);}
// compute prices back through the tree
// j+1 is the number of periods from the end
// i is the number of up moves from the start
  for(j=0;j<nper;j++) {
    for(i=0;i<nper-j;i++) {
      val[i] = prdn * val[i] + prup * val[i+1];}}
  return(val[0]);}

double crr::binopt(double S0,double lower,double upper) {
  int i,j;
// initialize terminal payoffs
// i is the number of up moves over the whole life
  for(i=0;i<=nper;i++) {
    Sprice = S0*pow(up,(double) i)*pow(down,(double) (nper-i));
    val[i] = (((Sprice>=lower) && (Sprice<=upper)) ? 1.0 : 0.0);}
// compute prices back through the tree
// j+1 is the number of periods from the end
// i is the number of up moves from the start
  for(j=0;j<nper;j++) {
    for(i=0;i<nper-j;i++) {
      val[i] = prdn * val[i] + prup * val[i+1];}}
  return(val[0]);}