For Homework 2 of Computational Finance by P Dybvig
Many of the features of this application are very similar to previous ones. My comments focus on the new parts. Please refer to earlier annotated versions for the parts that are similar to before.
Caplet.html instructs the Web browser to load Caplet.class. This works exactly the same as the previous .html files.
<HTML> <HEAD> <TITLE>Binomial Cap Pricing Program</TITLE> </HEAD> <BODY> <APPLET CODE=Caplet.class WIDTH=400 HEIGHT=100> </APPLET> </BODY> </HTML>
// // Fixed income binomial cap pricing applet // import java.applet.*; import java.awt.*; public class Caplet extends Applet { F_I_bin c2; --> This is the computational engine (F_I stands for fixed income). double caprate,rzero; Label capval; TextField interest_rate, capped_level; public Caplet() { setLayout(new GridLayout(3,2)); --> This applet has a very simple interface, a grid of 3 rows by 2 columns. This is not very suitable for distribution for use by others, but would good for your own use or for debugging. add(new Label("Interest rate (%) =")); add(interest_rate = new TextField("5",10)); add(new Label("Capped level (%) =")); add(capped_level = new TextField("5.5",10)); add(new Label("Cap value (per $100 face) =")); add(capval = new Label("**********")); c2 = new F_I_bin((double) 2.0, (int) 24, (double) 0.01, (double) 0.05, (double) 0.125, (int) 5001); recalc();} public boolean action(Event ev, Object arg) { if(ev.target instanceof TextField) { recalc(); return true;} return false;} double text2double(TextField tf) { return Double.valueOf(tf.getText()).doubleValue();} void recalc() { capval.setText(String.valueOf((float) (100 * c2.cap(text2double(capped_level)/100.0, text2double(interest_rate)/100.0))));}} // // Fixed-income binomial option pricing engine // class F_I_bin { int nper; double tinc,up,down,sigma,rbar,kappa,prfact; double [] r,val; public F_I_bin(double ttm,int nper,double sigma,double rbar,double kappa, int maxternodes) { this.nper=nper; tinc = ttm/(double) nper; this.sigma = sigma; up = sigma*Math.sqrt(tinc); this.rbar = rbar; this.kappa = kappa; prfact = kappa*Math.sqrt(tinc)/(2.0*sigma); val = new double[maxternodes]; r = new double[maxternodes];} --> The parameters are somewhat different than before because the model is different. In particular, the prices of up and down states depends on the node in the tree (both because the interest rate is changing and because of the mean reversion). Computing prfact here is about as much work as we can do that is not specific to a node. double bprice(double r0) { --> This computes a bond price. The assumption is that the bond is a zero-coupon bond that pays 1.0 nper periods from now. int i,j; double prup; //initialize terminal payoffs //i is the number of up moves for(i=0;i<=nper;i++) { // r[i] = r0 + up * (double)(2*i-nper); not needed for this claim val[i] = 1.0;} --> This is the final payoff, which is always 1.0. //compute prices back through the tree //j is the number of periods from the end //i is the number of up moves from the start for(j=1;j<=nper;j++) {for(i=0;i<=nper-j;i++) { --> The outer loop (over j) goes from maturity-1 back to the start, and the inner loop goes over different interest rate nodes at a point in time. r[i] = r0 + up * (double) (2*i-nper + j); --> This computes the interest rate at the node (needed for discounting). This formula uses that fact that down = -up. The number of downs to this node is the number of periods so far (nper - j) less the number of ups (i). So, we have that the total change in interest rates so far is equal to the formula up * i + down * (nper - j - i) = up * i + (-up) * (nper - j - i) = up * (2*i - nper + j), which implies the line in the program. prup = 0.5 + prfact*(rbar-r[i]); --> We compute prup (the risk-neutral probability of an up move) at each node, using the formula with mean reversion from class. prup = Math.min((double) 1.0,Math.max((double) 0.0,prup)); --> Since that formula can make the risk-neutral probability of an up-move or down-move negative when the interest rate is really huge or really small, we increase any negative value to 0.0 (that is the Math.max) and we reduce any value over 1.0 to 1.0 (that is the Math.min). val[i] = (prup*val[i+1]+(1.0-prup)*val[i])*Math.exp(-r[i]*tinc);}} --> Here is the valuation step, which is the risk-neutral valuation times the discount factor Math.exp(-r[i]*tinc). The formula for the discount factor assumes continuous compounding. return(val[0]);} double cap(double level,double r0) { --> This is the method that evaluates a cap. It is identical to the method for evaluating the bond price except for the terminal payment and the addition of the cash flow from the cap in the valuation step. int i,j; double prup; //initialize terminal payoffs //i is the number of up moves for(i=0;i<=nper;i++) { // r[i] = r0 + up * (double)(2*i-nper); not needed for this claim val[i] = 0.0;} --> The terminal payment is 0.0 since the cap is worthless at maturity. //compute prices back through the tree //j is the number of periods from the end //i is the number of up moves from the start for(j=1;j<=nper;j++) {for(i=0;i<=nper-j;i++) { r[i] = r0 + up * (double) (2*i-nper + j); prup = 0.5 + prfact*(rbar-r[i]); prup = Math.min((double) 1.0,Math.max((double) 0.0,prup)); val[i] = (prup*val[i+1]+(1.0-prup)*val[i])*Math.exp(-r[i]*tinc) + Math.max((double) 0.0,(r[i]-level)*tinc);}} --> At each node, we add the value of the cap payoff max((r-level)*tinc,0). return(val[0]);}}