A Simple Futures Option Pricing Program

Philip H. Dybvig

Washington University

Saint Louis, Missouri

- One-way arb
- Can go long physical commodity
- cannot go short

- Adjust return by:
- storage cost
- use value

- Futures price = risk-adjusted expected spot rate
- Can jump down as maturity increases
- Agriculturals: at expected harvest
- Oil: at anticipated easing of supply
- Silver and gold: rare, since stock is large
- Natural gas: storage expensive, can jump either way
- Paper: strange; futures but no spot

A Futures Contract gives the holder a daily claim to the variation in the market-determined Futures Price day by day. At maturity, the futures price is given by the underlying commodity price (with cash or physical settlement). If the interest rate is nonrandom and there is no arbitrage, then the futures price equals the forward price. This is usually a good approximation even when interest rates are random.

One futures contract gives ``more bang for the buck'' than one forward contract, since the change in value is received immediately rather than at the end. Holding one futures contract is equivalent to holding Q forward contracts, where Q is one over the discount factor to maturity of the contract.

- Less margin or credit verification is required, since only one day's worth of information arrival needs to be covered.
- The contract is the same every day.

|- F(1 + delta) F -| |- F(1 - delta)this means that an investment of 0 paying the change (called variation) is a fair trade:

|- + F * delta 0 -| |- - F * deltawhich is to say that the expected change is zero in the risk-neutral probabilities. For many commodities, this is a good model with delta = sigma * sqrt(Delta t) constant and risk-neutral probabilities of 1/2 and 1/2. (We could take the spacing to be unequal to have volatility fall as the price falls, with the necessary adjustment in the probabilities.)

The simple assumption about risk-neutral probabilities is the one described in the previous slide, although it may be more natural to usual approach for the underlying asset for bond futures options or stock index futures options.

The number of futures to hold is the number needed to give the same difference in value across the two states tomorrow as holding the futures would.

// fut.h // // Binomial futures option pricing model: declarations // #define MAXTERNODES 40 struct valhedge { double value; double delta;}; class fut { public: fut(double ttm=.25,int npers=4,double r=.05,double sigma=.3); valhedge eurcall(double f0,double X); private: int nper; double tinc,r1per,disc,disctm,up,down,pratio,prcup,prcdn; double val[MAXTERNODES];};

// futtest.cc // // Binomial futures option pricing model: test // #include <iostream.h> #include "fut.h" main() { fut c1; valhedge x; double futprice,strikeP; cout << "\nType the futures price, a space, the strike" << " price, and then ENTER.\n" << "Make the futures price negative to terminate." << "\n\n"; while(1) { cout << "futures-price strike-price: "; cin >> futprice >> strikeP; if(futprice < 0.0) { cout << endl; return(0);} if(!cin) { cout << "invalid input" << endl; return(1);} x = c1.eurcall(futprice,strikeP); cout << "call option value = " << x.value << "\n" << "hedge (number of contracts) = " << x.delta << "\n\n";}}

// fut.cc // // Binomial futures option pricing model: implementation // #include <math.h> #include "fut.h" #define MAX(a,b) (((a) > (b)) ? (a) : (b))

fut::fut(double ttm,int npers,double r,double sigma) { nper = npers; tinc = ttm/(double) nper; r1per = exp(r * tinc); disc = 1.0/r1per; disctm = exp(-r * ttm); up = 1.0 + sigma * sqrt(tinc); down = 1.0 - sigma * sqrt(tinc); prcup = 0.5*disc; prcdn = 0.5*disc;}

valhedge fut::eurcall(double f0,double X) { int i,j; double futprice; valhedge x1; // initialize terminal payoffs // i is the number of up moves over the whole life for(i=0;i<=nper;i++) { futprice = f0 * pow(up,(double) i) * pow(down,(double) (nper-i)); val[i] = MAX(futprice - 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-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);}