Homework 3
Binomial Futures Option Pricing Model

Computational Finance

Copyright © Philip H. Dybvig 1996, 1999

Scenario You are working for a corporation that uses fx futures to hedge currency risk. There is a current debate about whether you should be using futures options as well. You are charged with evaluating the pricing of futures options calls and puts. Your program will be useful for getting an understanding of the market and may also be a useful tool for trading.

Action You will be given an existing program that computes prices and hedges for futures options. This program reads futures and futures options prices off the Web and compares them with theoretical values, and is set up as a standalone program avoid security restrictions of Web browsers that give their applets limited access to files on the Web. (See Sun's Java security FAQ page http://java.sun.com/sfaq/ for an excellent discussion of these security restrictions.) The program is set up to price European calls and compare the theoretical price with the last trade; you will modify it to price American calls and compare the theoretical price with the opening price.

Concept Corporate hedging strategies represent one of the most important uses (and in some cases abuses) of option pricing theory. Hedging practices and expertise once found only in the most quantitative investment banks are now found in many corporations.

Instructions

  1. Put the program files, FutOpStart.java, FutOp.java, and ValHedge.java, in a directory on your machine where you want to work. Compile the program and run it. Since this is a standalone program, the commands you need are slightly different from what you have used before for applets. Here are the commands:
    javac FutOpStart.java FutOp.java ValHedge.java
    java FutOpStart
    
    The first command is the normal command for compiling any applet or standalone Java application with multiple source files. The second command uses the Java run-time environment that comes with the Java Development Kit to run the application. The futures and options prices in the applet are downloaded from two files ( r_jy.html and r_oj.html) on my Web page that are (except for acknowledgement of the source) from corresponding files ( r_jy.html and r_oj.html) with delayed live price quotes that were posted on the CME web page. We could use that page in our analysis; because it is changing all the time some additional programming would be needed (for example, see the Challenger below).
  2. Experiment with the program. At the initial choice of volatility, the options that are misvalued (in red or green) have extreme strike prices. Why might this be?
  3. The futures options traded on the CME are actually American options while the program assumes European options. Modify the program to evaluate the correct American options. (Note: for futures, we do not have the usual equality of American and European call prices in the absence of dividends. To compute the American call value we compute both the value of continuing and the value of exercising now, and the actual value is the higher of the two.)
  4. The opening price is arguably more reliable than the last price (if only because of the timing question considered in the thought question). Modify the program to use the opening price instead of the price of the last trade.
  5. (thought question) The prices in the two files are not necessarily synchronous. In fact, the futures file is updated periodically with a 10-minute delay and the options file is updated periodically with a 20-minute delay. Also, the last price may be for a trade that took place some time before. How do these observations affect our interpretation of the program's output?
Extra for Experts
  1. Modify the program to list put options as well as call options. This will require addition of an American put method in the pricing engine and an examination of the file r_oj to figure out how to step through and find the put prices.
Challenger
  1. Modify the program to compute the correct number of days to maturity. This is to remedy a great deficiency of the program, namely that it assumes the number of days to maturity is 28. This is true for the particular pages I have posted on the Web, but a program to be used in general should extract the dates from the file and compute the number of days to maturity! The relevant option maturity is the second Friday before the third Wednesday of the month. You can work out the dates yourself, or you can use a Julian day routine written by someone else. For example, there is one in the book Numerical Recipes in C by Press et al, Cambridge University Press, ISBN 0521431085. Also, a Web search revealed a number of useful-looking sites with information on Julian days. See, for example, http://www.magnet.ch/serendipity/hermetic/cal_stud/jdn.htm.

Exhibit A: FutOpStart.java

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

public class FutOpStart {
  public static void main(String[] args) {
    FutOpFrame f1 = new FutOpFrame();
    f1.setTitle("Futures Option Pricing Program");
    f1.pack();
    f1.show();}}

class FutOpFrame extends Frame {
    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;
    Label north;
  public FutOpFrame() {
    setLayout(new BorderLayout());
    setBackground(new Color(245,255,245));
    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];
      for(i=0,k=0;i<14;i++) {
        for(j=0;j<6;j++,k++) {
          centr.add(tableBody[k]=new Label("********",Label.CENTER));}}
    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();
    recalc();}
  void recalc() {
//
// Read in futures price for near contract
//
  try {
    futuresPage = new URL("http://dybfin.wustl.edu/teaching/compufinj/homework/3/r_jy.html"); 
/*    futuresPage = new URL("http://www.cme.com/cgi-bin/prices.cgi?prices/r_jy.html"); */
    futin = new BufferedReader(new InputStreamReader(futuresPage.openStream()));
    while(!(futin.readLine().startsWith("STRIKE"))) {};   // remove up to the table header
    futin.readLine();                                     // skip one line
    inputLine = futin.readLine();                         // read the near futures line
    /* System.out.println(inputLine); */
    maturity = inputLine.substring(0,5);                  // extract maturity date as string
    /* System.out.println(maturity); */
    futuresPs = inputLine.substring(33,39);
    futuresP = Double.valueOf(futuresPs).doubleValue();   // extract futures price
    /* System.out.println(futuresP); */
    futin.close();
  } 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);}
//
// 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);
//
// 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()));
    while(!(optin.readLine().startsWith("OJ "+maturity))) {}; // remove up to the right maturity
    i=0;k=0;
    while( ((inputLine = optin.readLine()) != null) && ((inputLine.length()>40) && (k<14)) ) {
/* 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) + "\""); */
      try {
      optionP = Double.valueOf(inputLine.substring(32,40)).doubleValue();
      strikeP = Double.valueOf(inputLine.substring(0,7)).doubleValue();
      if(Math.abs(futuresP-strikeP)<futuresP/12.0) {
        (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));
        (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);
      if(optionP > 1.05 *(x.value/100.0)) (tableBody[6*k+3]).setForeground(Color.red);
      if(optionP < .95 * (x.value/100.0)) (tableBody[6*k+3]).setForeground(Color.green);
        k++;}
      } 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);}
    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;}}

Exhibit B: 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);
    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));
    return(x1);}}

Exhibit C: ValHedge.java

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