For Homework 1 of Computational Finance by P Dybvig
The file CrrA.html is our program's interface to the "outside world." It is written in "hyper text markup language" (hence html), the default language of Web documents. In html, most items are labeled by matched tags. For example, <HTML> and </HTML> around the whole document indicate it is html. <HEAD> and </HEAD> indicate the head of the document, which contains only the title (marked by <TITLE> and </TITLE>) that shows in the top line of the browser. In the body of the document (between <BODY> and </BODY>) is the pair of tags (<APPLET CODE=CrrA.class WIDTH=500 HEIGHT=350> and </APPLET>) instructing the browser to include our applet. Our applet tag has three arguments, CODE which gives the name of the class file, WIDTH which gives the width in pixels, and HEIGHT which gives the height in pixels. (Pixels, short for "picture elements," are the dots used to make up a picture.) Many other arguments can be used in an Applet tag, including user-defined arguments. Here CrrA.class is the name of the class file containing the class CrrA defining the applet. It is important that the two names agree (here they are both CrrA), including capitalization.
<HTML> <HEAD> <TITLE>Binomial Option Program: Prototype</TITLE> </HEAD> <BODY> <APPLET CODE=CrrA.class WIDTH=500 HEIGHT=350> </APPLET> </BODY> </HTML>
CrrA.java is the program file that contains the actual java program. The compiler converts this program to "bytecodes" that are closer to machine language. Actual conversion to machine language would vary from machine to machine this is run on and is not done at time of compilation.
Two classes are defined in CrrA.java: CrrA and Crr. These could be defined instead in separate files (bearing their names exactly including capitalization plus the suffix .java), which would be preferable for classes that will be reused by classes not already defined in this file. Each would then have to be made "public" so they can be used outside of this file. As it is, only CrrA is public, since Crr is only referenced by CrrA which is located in the same source file.
Each class gives a description or template for a type of object. The class CrrA is the overall applet which includes a label, an input area, a results area, and a computational engine. Each of these smaller objects making up the applet could be defined as a separate class; as it is, I chose to define only the computational engine crr in a separate class called Crr. Each time the applet starts, one object each of classes CrrA and Crr is created. In a different application, we might want to have two or more Crr objects to allow comparisons for various parameter values, in which case having the single class definition as a template for each pair would save us some time! Furthermore, having a single class definition would make the program file easier to read and would minimize programming errors.
Each class has a number of methods (functions) that perform operations in the class and variables that keep track of important data or states of the class. This is one of the features of object-oriented programming, characteristic of languages like C++ and java: the data and the functions used to manipulate the data are associated in a combined object. One important method in each class is a Constructor, which is a method with the same name as the class that is used to set up the object (construct it) the first time it is created.
This is the java 1.0 version of the applets. The exact details of the user interface (e.g. the action method and resize method) seem to be in a state of flux and are different in version 1.1. I do not suggest spending too much effort learning these features of the language.
Detailed comments are in the lines marked --> in the code below.
import java.applet.*; import java.awt.*; --> These two statements allow us to use the shortcut of omitting the prefix in some java classes below. For example, we can write Applet instead of java.applet.Applet in defining CrrA. public class CrrA extends Applet { --> This signals the class definition of the new class CrrA which extends the class Applet. Extension means that it inherits a lot of the general features of Applets as well as the specific features defined here. The qualifier "public" says that CrrA should be a global name that can be referred to from outside the file. TextField Strike, S0, sigma, r, ttm, nper; Button row6; Label optval; Crr crr; /* option pricing engine */ --> These statements define variables used in an object of class CrrA. Strike, S0, sigma, r, ttm, and nper are the names of TextFields (little input boxes), row6 is the name of a Button, optval is the name of a Label, and crr is the name of an object of type Crr. For now the objects do not exist and if we referred to these names before they were assigned to objects, we would probably get a warning or error like "crr used before set." --> The text between /* and */ is a comment that is ignored by the compiler. Including comments is important because it is likely that someone will have to use or modify the code besides the original programmer. Even the original programmer will appreciate comments on code written six months earlier. On the other hand, code that is well-organized and written in a straightforward way should require reasonably sparse comments. public CrrA() { --> This method, which has the same name as the class, does all the initial work that is required when a new object of this type is created, in this case (for an applet) in response to a call from a .html file (in this case CrrA.html). This is called a Constructor. setLayout(new BorderLayout()); --> A layout object of class BorderLayout is arranged in a rectangle with a rectangle in the center ("Center"), rectangles on top and bottom ("North" and "South"), and rectangles on the sides ("East" and "West"). The setLayout method (by default of the current object, an applet of class CrrA we are constructing) says to make the new BorderLayout object the layout of the current object. add("North",new Label("Binomial Option Pricing Applet",Label.CENTER)); --> Add a new Label "Binomial Option Pricing Applet" at the top of the applet. The second argument Label.CENTER to Label indicates this should be centered. Panel centr = new Panel(); centr.setLayout(new FlowLayout()); --> The center of the new applet should be a new panel named centr. The new panel should have a layout of type FlowLayout, which means put objects added to it in a row horizontally until space is gone and then start again below. In this case, we expect all parts of the panel to fit on one line and therefore we do not plan to start again. Panel inputs = new Panel(); inputs.setLayout(new GridLayout(7,1)); --> The panel called inputs is the first panel we will put in centr. Its layout is of a type called GridLayout, which in this case means 7 equally-sized cells arranged in 7 rows and one column. Panel row0 = new Panel(); --> "Panel" declares the type of the variable row0, which is the name assigned to a newly created panel object. row0.setLayout(new FlowLayout(FlowLayout.LEFT)); --> row0 is given a new layout of type FlowLayout, left-justified row0.add(Strike = new TextField("50",8)); row0.add(new Label("Option Strike Price")); --> To row0, we add a textfield 8 characters wide initially containing the input 50, and a label "Option Strike Price". Strike is the name of the TextField in row0. inputs.add(row0); --> row0 is added to the new object of type CrrControls (the input panel) whose Constructor this is. --> rows 1-5 work the same way: Panel row1 = new Panel(); row1.setLayout(new FlowLayout(FlowLayout.LEFT)); row1.add(S0 = new TextField("50",8)); row1.add(new Label("Underlying Stock Price")); inputs.add(row1); Panel row2 = new Panel(); row2.setLayout(new FlowLayout(FlowLayout.LEFT)); row2.add(sigma = new TextField("40",8)); row2.add(new Label("Annual Standard Deviation %")); inputs.add(row2); Panel row3 = new Panel(); row3.setLayout(new FlowLayout(FlowLayout.LEFT)); row3.add(r = new TextField("5",8)); row3.add(new Label("Annual Interest Rate %")); inputs.add(row3); Panel row4 = new Panel(); row4.setLayout(new FlowLayout(FlowLayout.LEFT)); row4.add(ttm = new TextField("0.25",8)); row4.add(new Label("Time to Maturity (yrs)")); inputs.add(row4); Panel row5 = new Panel(); row5.setLayout(new FlowLayout(FlowLayout.LEFT)); row5.add(nper = new TextField("10",8)); row5.add(new Label("Number of Subperiods (whole number)")); inputs.add(row5); row6 = new Button("Recompute"); inputs.add(row6); --> row6 is a Button with the word Recompute on it. row6 is added to our input panel object. centr.add(inputs); --> and the entire input panel is added to the center panel of the applet. Panel results = new Panel(); results.setLayout(new GridLayout(6,1)); --> The panel called results is the second panel we will put in centr. Like inputs, it has a Layout of type GridLayout, which in this case means 6 equally-sized cells arranged in 6 rows and one column. results.add(new Label("")); results.add(new Label("")); --> The first two cells in results are blank labels. results.add(new Label("Call Option Value:")); optval = new Label("",Label.LEFT); optval.resize(180,optval.size().height); results.add(optval); --> The third cell is a Label describing the result in the fourth cell, which is a left-justified Label optval, resized to have a width of 180 pixels. results.add(new Label("")); results.add(new Label("")); --> and the final two cells in results are two more blank Labels. centr.add(results); --> the entire results panel is added to the center panel of the applet. add("Center",centr); --> and the center panel is added where it belongs. Caution: using add(centr); instead of add("Center",centr); will cause problems in a BorderLayout. In particular, javac and appletviewer will work fine, but mysteriously browsers may not. I think this is because the location defaults to center if not given in version 1.1 but many of the browsers still support only 1.0. crr = new Crr(5001); --> Create a new object crr of type Crr. The argument 5001 is the argument to the constructor, which is the method Crr(int) in Crr. Specifically, 5001 gives the maximum number of terminal stock prices (which equals the maximum number of periods plus one). recalc();} --> The last step in constructing the applet is to perform the option pricing calculation the first time. The } indicates the end of the definition of the constructor CrrA(). public boolean action(Event ev, Object arg) { if(ev.target instanceof TextField) { recalc(); return true;} if(ev.target instanceof Button) { recalc(); return true;} return false;} --> This function says what to do when something happens: recalculate if it is a button pressed or a TextField input. This is part of the language that is changing in later versions of Java. double text2double(TextField tf) { --> This method returns a double precision real number represented by the text in the TextField. return Double.valueOf(tf.getText()).doubleValue();} --> Starting with the TextField tf, ".getText()" uses the method that is part of every TextField to extract just the string that has been typed there. Then, "Double.valueOf" converts the string to a Double object, which is an object containing a double precision number. Finally, ".doubleValue()" extracts the number itself. A better version of this function might include context-specific help to guide the user who types inappropriate input (not a number or a number that is too large or too small). void recalc() { --> This function defines what it means to recalculate. The void says no value is returned by the method (in contrast to, for example, a mathematical function which may return a double). row6.setLabel("Computing...Please Wait"); --> In case recomputing takes a while, change the label on the "Recompute" button to clue the user in about what is happening. This will not even be noticeable except when there are many periods (or the computer is very slow). crr.newPars(text2double(ttm),(int) text2double(nper), text2double(r)/100.0,text2double(sigma)/100.0); --> The crr.newPars function is used to change the variables to the parameter values currently in the input boxes. The text2double method (defined just above this method) extracts the string from the box and converts it to type double. For the interest rate r and standard deviation sigma, division by 100.0 converts the percentage to a number. For the number of periods, (int) forces a change to type integer before passing it on to crr.newPars. optval.setText(String.valueOf( (float)crr.Eurcall(text2double(S0),text2double(Strike)))); --> These two lines are a single program statement. The function crr.Eurcall(double,double) is called to compute the call value as a double precision real number, which is cast (converted) to a float (single precision real number), and then to a character string. The label optval's text is then set to this string. row6.setLabel("Recompute");}} --> Finally, the label is set back to "Recompute" since the computation is done. The first } tells the compiler this is the end of the method recalc; the second } tells the compiler this is the end of the class CrrA. class Crr { --> Crr is the class in the file that is not immediately visible to the user. It defines a template for the object that does the actual calculations of option prices in the binomial tree. double ttm=.25,r=.05,sigma=.3; int nper=4,maxternodes; double tinc,r1per,disc,up,down,priceup,pricedn,Sprice; double[] val; --> setting up names for various constants for the binomial option pricing tree. the following are inputs ttm -- time to maturity r -- interest rate sigma -- standard deviation of stock returns nper -- number of periods to maturity maxternodes -- largest permissible number of terminal nodes while the following are computed tinc -- time increment r1per -- 1 + interest rate over tinc disc -- discount factor over tinc up -- new stock price over previous at an up node down -- new stock price over previous at a down node priceup -- state price of consuming in the up state pricedn -- state price of consuming in the down state Sprice -- stock price at the node we are considering now val[] -- vector of option values at different stock prices on the date we are currently working on public Crr(int maxternodes) { val = new double[maxternodes];} --> The class constructor's only input is the maximum number of terminal nodes, and the only task is to create the vector in which we place the values at a given date void newPars(double ttm,int nper,double r,double sigma) { this.nper = nper; tinc = ttm/(double) nper; r1per = 1.0 + r * tinc; disc = 1.0/r1per; up = r1per + sigma * Math.sqrt(tinc); down = r1per - sigma * Math.sqrt(tinc); priceup = disc * 0.5; pricedn = disc * 0.5;} --> The method newPars changes the underlying parameters of the stock price process and computes the derived parameters. The initial stock price could be set here too (instead of being inputs to the individual pricing functions). The derived parameters are the quantities that will be used again and again through the tree. It saves time to compute them once here instead of computing them at each node in the tree. public double Eurcall(double S0,double X) { --> The method Eurcall prices a European call option with strike X when the stock price is S0. int i,j; --> these two integer variables are counters for the loops below and indicate which node in the binomial tree we are considering // initialize terminal payoffs // i is the number of up moves over the whole life for(i=0;i<=nper;i++) { Sprice = S0*Math.pow(up,(double) i)*Math.pow(down,(double) (nper-i)); val[i] = Math.max(Sprice - X,(double) 0.0);} --> First, we must set all the values of the option at nodes at the terminal date and store these values in the array val. The for command repeats the statements following between curly brackets a number of times. The first argument of for is executed once in preparation for the repetition. In this case, we set the counter i (which can be interpreted as the number of up moves taken to get to the terminal node) equal to 0. The second argument of for is the criterion for continuing to repeat the statements in the loop. In this case, we repeat so long as i is less than or equal to the number of periods. The final argument is what is done at the end of each repetition, in this case, increasing i by one. --> The calculation for the stock price Sprice at a node uses the power function Math.pow(double, double) which takes the first argument to the power of the second. Calculating the option value val[i] at node i uses the function Math.max(double,double) which is the max of the arguments. In each case, casting with (double) converts the number to the right type for the function. // 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] = pricedn * val[i] + priceup * val[i+1];}} --> The previous for statment computed the values at the end; this pair of for statements computes the value back through the entire tree. These are called nested for loops; for each time through the outer loop (with index j), we go through the inner loop a number of times. At each node (characterized by i and j) we compute the option value at a new node. The vector val is used to store both next period's values (previously computed) and this period's values (computed now). This is possible because the time of computing this node's value is the last time we need to use the next period's value previously stored there. return(val[0]);} --> At the end, the value corresponding to no ups is the option value we are returning. public double binRight(double S0,double lower) { --> The binRight method gives the value of a European "binary option" that pays off 1 when the stock price is higher than ("to the right of") some minimum value lower. 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*Math.pow(up,(double) i)*Math.pow(down,(double) (nper-i)); val[i] = ((Sprice>=lower) ? 1.0 : 0.0);} --> This line, used to compute the terminal payoff, is the only real difference between binRight and Eurcall. The construction (a ? b : c) is equal to b if a is true and is equal to c if a is false. // 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] = pricedn * val[i] + priceup * val[i+1];}} return(val[0]);} public double binLeft(double S0,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*Math.pow(up,(double) i)*Math.pow(down,(double) (nper-i)); val[i] = ((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] = pricedn * val[i] + priceup * val[i+1];}} return(val[0]);}} --> The function binLeft gives the value of a binary option that pays of when the stock price is left of a critical value upper. Note that the criterion of the (a ? b : c) has been changed from binRight to reflect the difference.