Annotated versions of FutOpStart.java, FutOp.java, and ValHedge.java

For Homework 3 of Computational Finance by P Dybvig

There are many new features in this application as well as many differences. My comments focus on the new parts. Please refer to earlier annotated versions for the parts that are similar to before.

Quick overview

Before going into details, here is a quick look at how the program is structured.

file FutOpStart.java:

public class FutOpStart {
  public static void main(String[] args) {
    ...}

--> This is where the standalone program program starts (with
    the main() method in FutOpStart).

class FutOpFrame extends Frame {
    ...}

--> This is the new window (or Frame) that is opened by
    FutOpStart.  This frame reads data about futures and futures
    options prices from over the net, and volatility and other
    parameters from user inputs in TextFields.  This information
    is sent to a computational engine of class FutOp to compute
    theoretical values.  All are displayed in a user-friendly
    format.

file FutOp.java:

public class FutOp {
   ...}

--> This is the computational engine the computes futures options
    prices.

file ValHedge.java:

public class ValHedge{
  ...}

--> This defines the type of object (which includes an option price
    and the delta for hedging) returned by method Eurcall of class
    FutOp.

FutOpStart.java

FutOpStart.java defines two classes, FutOpStart and FutOpFrame. FutOpStart is a very simple class that has the main() method that is the starting point in a standalone program. Its function is to create and activate a FutOpFrame, an object that has the user interface. This object also reads files on the internet (to get futures and futures option prices) and creates and invokes the computational engine, a FutOp, of a class defined in FutOp.java. The object passed back by FutOp, a ValHedge, is an object containing two doubles, the computed value and hedge ratio of the futures option.

//
// Binomial futures option pricing program
//
import java.awt.*;
import java.net.*;
import java.io.*;

--> The library java.net.* contains network interface classes,
    and the library java.io.* contains input-output classes.
    Together, the two open web files and read their contents as
    character streams.  Another use of the same libraries could
    read a continuous real-time data feed.

public class FutOpStart {
  public static void main(String[] args) {

--> Standard syntax for the required main() method in a
    standalone program.  This is analogous to the constructor
    in an applet.

    FutOpFrame f1 = new FutOpFrame();

--> This creates a frame (a new window; standalone programs do
    not automatically have windows) of type FutOpFrame defined
    below.

    f1.setTitle("Futures Option Pricing Program");

--> For the top line in the outside of the window.

    f1.pack();

--> Make everything its optimal size and fit together.

    f1.show();}}

--> Display the new window.

class FutOpFrame extends Frame {

--> As mentioned above, a Frame is similar to an applet but has
    its own window.  In a standalone program, it also has much
    less restricted access to files locally and on the Web than
    an applet running in a Web browser.

    int i,j,k;
    FutOp c1;
    ValHedge x;
    double futuresP,strikeP,optionP;
    String maturity, inputLine, futuresPs;
    URL optionsPage, futuresPage;
    BufferedReader futin, optin;
    TextField r, sigma, nper;
    Label[] tableBody;

--> An array of Labels so we will have names for all the cells
    in the table without having to make up separate names.

    Label north;
  public FutOpFrame() {

--> The constructor of a FutOpFrame.

    setLayout(new BorderLayout());
    setBackground(new Color(245,255,245));

--> Something new: a color constructed with 3 integer arguments,
    corresponding respectively to intensities of red, green, and
    blue, each on a scale from 0 to 255.  All 245's would be a
    white less bright than standard white (all 255's).  With the
    green slightly more intense than red and blue this gives a
    light pastel green.

    add("North",north = new Label(
      "Japanese Yen Futures Option Pricing Program: Call",
        Label.CENTER));
    north.setForeground(Color.blue);
      Panel centr = new Panel();
      centr.setLayout(new GridLayout(15,6));
      centr.add(new Label("maturity",Label.CENTER));
      centr.add(new Label("futuresP",Label.CENTER));
      centr.add(new Label("strikeP",Label.CENTER));  
      centr.add(new Label("call:mkt",Label.CENTER));
      centr.add(new Label("call:model",Label.CENTER));  
      centr.add(new Label("delta",Label.CENTER));
      tableBody = new Label[84];

--> There are 84 labels, one for each cell in the 6 columns x 14
    remaining rows.

      for(i=0,k=0;i<14;i++) {
        for(j=0;j<6;j++,k++) {
          centr.add(tableBody[k]=
            new Label("********",Label.CENTER));}}

--> Note that commas separate statements in a sequence that are
    treated as one in each for statement.  In the outer loop, we
    set both i and k equal to zero at the start, and in the inner
    loop, we increment both j and k at the end of each time through.
    In this case, i is the counter for the loop as in cases we have
    seen before, and k tells us which Label in tableBody we are
    going to place next.  We could eliminate reference to k and
    simply replace it in the centr.add statement by j + 6*i; doing
    the one or the other is a matter of taste.

    add("Center",centr);
      Panel south = new Panel();
      south.setLayout(new GridLayout(1,6));
      south.add(new Label("sigma (%) ="));
      south.add(sigma = new TextField("17",8));
      south.add(new Label("r (%) ="));
      south.add(r = new TextField("5",8));
      south.add(new Label("#periods ="));
      south.add(nper = new TextField("100",8));
    add("South",south);
    c1 = new FutOp();

--> creating the computational engine

    recalc();}
  void recalc() {

--> As in previous homeworks, the method recalc does the
    calculations.  In this case, we have it read in the futures and
    futures options data each time it recalculates.  With the
    current (static) Web pages we are reading from the course page,
    it might be more efficient to save that information.  However,
    in some (future) version of this that points directly at the
    CME site, we would probably want to read in the data each time
    to get the most current prices (or, perhaps, leave this at the
    user's option).

//
// Read in futures price for near contract
//
  try {

--> The try { ... } catch(.,.) { ... } catch(.,.) { ... } is for
    capturing and addressing input errors.  The first type of error
    that is caught is MalformedURLException which would be an error
    in the string argument to URL.  The second type of error is
    IOException, which would be an error reading from the URL.

    futuresPage = new URL(
"http://dybfin.wustl.edu/teaching/compufinj/homework/3/r_jy.html"); 

--> Sets up a URL.  It is not quite ready to read at this point.

/*    futuresPage = new URL(
"http://www.cme.com/cgi-bin/prices.cgi?prices/r_jy.html"); */

--> This commented-out URL is for the original CME web page with the
    prices.

    futin = new BufferedReader(new InputStreamReader(
      futuresPage.openStream()));

--> This defines futin as the input buffer/reader for the URL
    futuresPage.  Now the file can be read as a character stream
    coming into this buffer.

    while(!(futin.readLine().startsWith("STRIKE"))) {};

--> The method readLine in futin reads one line from the buffer and
    returns it as a String.  The method startWith compares the first
    characters with the String argument "STRIKE", which is the start
    of the line giving the table header in the .html file for the Web
    page.  The ! is a not operator; this says to keep executing the
    body of the while loop until we get to the header line.  The body
    of the loop is empty, since all the work (mainly reading another
    line) is done in the test part.  Note that we are not saving the
    character strings that are returned by these readLine()'s.
    futin.readLine();            // skip one line after table header
    inputLine = futin.readLine();     // read the near futures line

--> We read and discard one more line (this line in the r_jy.html
    file contains only a formatting command), and we save the
    following line in the string variable inputLine.

    /* System.out.println(inputLine); */

--> This commented-out print command was used in the debugging of
    the program.  Normally, I would comment this out, but I thought
    you might like to see what kind of diagnostics I used to make
    sure I was getting the right thing as I wrote this.  This is
    like the scaffolding used when building a building.  Leaving it
    there probably does no real damage but is aesthetically
    unpleasant.  In that case, as in this, leaving it up may give
    insight to the construction process.

    maturity = inputLine.substring(0,5); // maturity date string

--> The substring(0,5) gives the string starting with character 0
    (not 1, just like arrays) and ending ->just before<- character
    5. Therefore, this is a string of length 5 at the start of the
    line, which is the representation of the maturity (e.g. MAR99
    for March, 1999).
    /* System.out.println(maturity); */
    futuresPs = inputLine.substring(33,39);

--> this is the substring representing the futures price.

    futuresP = Double.valueOf(futuresPs).doubleValue();

--> and the corresponding number

    /* System.out.println(futuresP); */
  } catch(MalformedURLException e) {
  System.err.println("Error: bad URL");
  System.exit(0);
  } catch(IOException e) {
  System.err.println(
    "Error: Trouble opening or reading futuresPage");
  System.exit(0);}

--> The error handling code, completing the earlier try {.  In each
    case, we write a brief message to error output and exit.

//
// Set parameters for the option pricing engine.  Hardwiring days to
// maturity is a cheat!  See the Challenger for more information.
//
    c1.newPars((double) 28.0/365.25, (int) text2double(nper),
      (double)text2double(r)/100.0,(double)text2double(sigma)/100.0);

--> Most of these parameters are provided by the user.  Time to
    maturity is set (!) at 28 converted to an annual number.  This
    would not be acceptable if we were to use this for the CME site
    on different days.  The Challenger is to fix this and compute
    the number of days to maturity from information in the files we
    are reading.

//
// Read in corresponding futures options prices, compute theoretical
// value and delta, and print
//
  try {
      optionsPage = new URL(
"http://dybfin.wustl.edu/teaching/compufinj/homework/3/r_oj.html");
/*      optionsPage = new URL(
"http://www.cme.com/cgi-bin/prices.cgi?prices/r_oj.html"); */
      optin = new BufferedReader(
        new InputStreamReader(optionsPage.openStream()));

--> similar to the code for reading the futures Web page

    while(!(optin.readLine().startsWith("OJ "+maturity))) {};

--> find the subheading corresponding to this maturity (OJ means
    option Japan, I think, and is the symbol for the futures
    options)

    i=0;k=0;
    while( ((inputLine = optin.readLine()) != null) &&
      ((inputLine.length()>40) && (k<14)) ) {

--> a null input line would indicate end-of-file.  && indicates
    logical and, with the second argument executed only if the
    first is true (helps to avoid errors).  If the inputLine is
    shorter than 40, then we are done with the call options at this
    maturity.  If k is 14 or larger, we have no more lines to use in
    the table in the frame.  Passing these tests, we are still
    in the table of call prices at this maturity.

/* System.out.println(inputLine);
System.out.println("\"" + inputLine.substring(35,39) + "\"");
System.out.println("\"" + inputLine.substring(32,39) + "\"");
System.out.println("\"" + inputLine.substring(39,40) + "\""); */

--> yet more debugging print statements, commented out as a group.

      try {
      optionP = Double.valueOf(
        inputLine.substring(32,40)).doubleValue();
      strikeP = Double.valueOf(
        inputLine.substring(0,7)).doubleValue();

--> error-handling is doing part of our work here!  if this is a
    maturity that does not have proper option and strike prices,
    the catch(NumberFormatException e) below will skip over this
    line in the options file.  Note that its consequences are given
    by {} which means do nothing (as opposed to other errors above
    for which we print out an error message and abort the program.

      if(Math.abs(futuresP-strikeP)<futuresP/12.0) {

--> only include strikes that are not unreasonably far away from
    par (since those are probably not true trading prices)

        (tableBody[6*k]).setText(maturity);
        (tableBody[6*k+1]).setText(futuresPs);
        (tableBody[6*k+2]).setText(inputLine.substring(0,4));
        (tableBody[6*k+3]).setText(inputLine.substring(32,39));
        x = c1.eurcall(futuresP,strikeP);
/* System.out.println(futuresP);
System.out.println(strikeP);
System.out.println(x.value/100.0);
System.out.println(x.delta); */
        (tableBody[6*k+4]).setText(String.valueOf((float)
          Math.floor(1000.0 *(x.value/100.0) + 0.5)/1000.0));

--> rounding to three decimal places.  arguably we should use the
    formatting commands that include trailing zeros as well.  We
    divide by 100 because the file quotes futures in cents per 100
    yen but options in dollars per 100 yen.

        (tableBody[6*k+5]).setText(String.valueOf((float)
          Math.floor(1000.0 *(x.delta) + 0.5)/1000.0));
      (tableBody[6*k+3]).setForeground(Color.black);

--> some colors are pre-defined.  this doesn't change anything the
    first time through by may be important for recalculations.

      if(optionP > 1.05 *(x.value/100.0))
        (tableBody[6*k+3]).setForeground(Color.red);

--> label the quote with red if the market quote is more than 5
    percent above the theoretical value

      if(optionP < .95 * (x.value/100.0))
        (tableBody[6*k+3]).setForeground(Color.green);

--> label the quote with green if the market quote is more than 5
    percent below the theoretical value

        k++;}

--> move the pointer to the next line in the table

      } catch(NumberFormatException e) {}}
    optin.close();
    } catch(MalformedURLException e) {
    System.err.println("Error: bad URL");
    System.exit(0);
    } catch(IOException e) {
    System.err.println("Error: Trouble opening optionsPage");
    System.exit(0);}}
  public boolean handleEvent(Event event) {
    if(event.id == Event.WINDOW_DESTROY) {
      System.exit(0);}

--> kill the application if the user kills the window

    return super.handleEvent(event);}
  double text2double(TextField tf) {
    return Double.valueOf(tf.getText()).doubleValue();}
  public boolean action(Event ev, Object arg) {
    if(ev.target instanceof TextField) {
      recalc();
      return true;}
    return false;}}

FutOp.java

//
// Binomial futures option pricing model: computational engine 
//

public class FutOp {

  int nper;
  double tinc,disc,up,down,prcup,prcdn;
  double val[];

  public FutOp() {}

 
  public void newPars(double ttm,int npers,double r,double sigma) { 
    nper = npers;
    tinc = ttm/(double) nper;
    disc = Math.exp(-r * tinc);
    up = 1.0 + sigma * Math.sqrt(tinc);
    down = 1.0 - sigma * Math.sqrt(tinc);

--> This is the main difference between this computational engine
    and the equity option engine:  since futures require no initial
    investment there is no interest rate in the mean return under
    the risk-neutral probabilities.

    prcup = 0.5*disc;
    prcdn = 0.5*disc;
    val = new double[npers+1];}

  public ValHedge eurcall(double f0,double X) {
    int i,j;
    double futprice;
    ValHedge x1 = new ValHedge();
// initialize terminal payoffs
// i is the number of up moves over the whole life
    for(i=0;i<=nper;i++) {
      futprice = f0 * Math.pow(up,(double) i)
        * Math.pow(down,(double) (nper-i));
      val[i] = Math.max(futprice - X,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-1;j++) {
      for(i=0;i<nper-j;i++) {
        val[i] = prcdn * val[i] + prcup * val[i+1];}}
    x1.value = prcdn * val[0] + prcup * val[1];
    x1.delta = (val[1]-val[0]) / (f0*(up-down));

--> Here we compute the hedge ratio in the normal way as the
    ratio of value in up minus down for the hedged asset and the
    underlying

    return(x1);}}

ValHedge.java

This simple class just puts two named double numbers in an object. This just gives us the names. We could have ValHedge.Eurcall return a double[2] instead, but then the calling routine might look more obscure. It is a matter of taste whether this sort of thing is worth the effort.

public class ValHedge {
  public double value;
  public double delta;
  public ValHedge() {}}