Homework 4
Asset Allocation Simulation

Computational Finance

Copyright © Philip H. Dybvig 1996,1999

Scenario You are working in the treasury of a large corporation. One responsibility of your group is oversight of the company's pension fund, which is currently 50-50 in equities and fixed income. Your analysis will use a simulation to assess the asset mix and consider some alternative strategies.

Action You will be given an existing program that performs a simple simulation and plots the results. You will adapt the program to evaluate different candidate strategies.

Concept Simulation is a powerful tool for analyzing portfolio strategies. This Homework gives a realistic analysis of a serious practical problem faced in practice.

Instructions

  1. Put the program files (AssetAlloc.java, BasicLinePlot.java, and AssetAlloc.html ) in a directory on your machine where you want to work. Rename them as necessary. Compile the program and run it in appletviewer. Try out the different features of the program. Form a view of what would be a good asset mix.
  2. Adapt the program to show simulations of a constant-proportions-portfolio-insurance (CPPI) strategy. CPPI has an insured part with face value F at maturity that is invested in bonds, and a cushion, which is whatever wealth is left over, that is invested in fixed proportions in stocks and bonds. The value of the cushion at any time t is W(t)-F*exp(-r(T-t)), where W(t) is wealth at time t, F is the promised amount at the end, and exp(-r(T-t)) is the discount factor between t and maturity T given the interest rate r. Constant proportions portfolio insurance has a couple of other interesting strategies as special cases: the fixed proportions strategy (as is in the applet initially) has F=0, while buy-and-hold has the proportion of the cushion in the risky asset equal to one.
  3. Adapt the program to show the effect of infrequent rebalancing (to save on transaction costs). Assume the portfolio holdings are shifted between stocks and bonds only once every k periods. Debug and compile the program, and produce a new plot for this case, given the identical default parameter values but assuming that portfolio weights are rebalanced (i) monthly, (ii) quarterly, and (iii) annually. To identify when to rebalance, I suggest using the % and == operators. The operator == is a test for equality and the % operator gives the remainder; i % k == 0 is true when i is a multiple of k and false otherwise. (A common mistake is to use the assignment operator = in place of the equality test ==, since the equal sign is used both ways in mathematics.) Include a trading cost of 0.2% of the size of each trade.
  4. (thought question) What strategy would you like used for your retirement fund? Would you like this sort of simulation performed in real (inflation-adjusted) or nominal terms?
Extra for Experts

  1. Change the program to allow the user to change parameters without obtaining a new random draw. This will help the user to perform controlled experiments that look at the pure effect of changing strategies. To do this, store the random draws from Math.random(); entering the stock return computed in stockTotReturn for reuse in case the parameters are changed without a request for recalculation.
  2. Plotting the final portfolio value as a function of the final stock price is a good way to understand a portfolio strategy. Have the applet run 2000 simulations (without plotting their wealth but saving both the final stock price and wealth in arrays) and plot the final wealth as a function of stock price. This involves several steps. First modify fixProps (or your new CPPI method) to return the final stock price and final wealth. Next, create an array and a for loop to generate and store a bunch of these values. Then, modify BasicLinePlot to plot points (a scatterplot) instead of lines. Finally, send the final wealth and stock price arrays to this new scatterplot program.
  3. Create a histogram showing how probable it is for terminal wealth to be in different ranges.

Challengers

  1. Adapt the program to admit multiple assets with arbitrary means and covariances. Test it using reasonable parameters for domestic equities, international equities, small stocks, and the short bond.
  2. Assume that risk preferences are represented by maximization of the expected logarithm of terminal wealth. Compute (and/or approximate) the optimal trading strategy when facing transaction costs.
Exhibit A: HTML file AssetAlloc.html
<HTML>
<HEAD>
<TITLE>Asset Allocation Simulation</TITLE>
</HEAD>
<BODY>
<APPLET CODE=AssetAlloc.class WIDTH=300 HEIGHT=50>
</APPLET>
</BODY>
</HTML>
Exhibit B: Asset Allocation Applet file AssetAlloc.java
//
// Asset Allocation Applet
//
// This applet simulates asset allocation between risky and riskless
// assets.  The horizon is fixed at 10 years and initial wealth is
// normalized to be 100.  The interest rate is constant and stock
// returns are i.i.d. over time.
//

import java.applet.*;
import java.awt.*;

public class AssetAlloc extends Applet {
  ValuePlotFrame valuePlotFrame;
  Button startASimu;
    public AssetAlloc() {
      setLayout(new GridLayout(1,1));
      add(startASimu = new Button("Start a Simulation"));
      valuePlotFrame = new ValuePlotFrame();
      valuePlotFrame.setTitle("Asset Allocation Simulation");
      valuePlotFrame.pack();
      valuePlotFrame.resize(500,400);}
    public boolean action(Event e, Object arg) {
      if(e.target == startASimu) {
        valuePlotFrame.reset();
        return true;}
      return false;}}

class ValuePlotFrame extends Frame {
  BasicLinePlot blp;
  TextField r,mu,sigma,inrisky;
  Button newRandomDraws,resetInputs;
  double ttm = 10.0,ir;
  double[] times,values;
  int nper = 1200;
  int i;
  AssetAllocEngine vroom;
  double[] xgrid,ygrid;
  public ValuePlotFrame() {
    setLayout(new BorderLayout());
    blp = new BasicLinePlot();
    add("Center",blp);
    Panel inputs = new Panel();
    inputs.setLayout(new GridLayout(6,2));
      inputs.add(new Label("interest rate (%/yr)"));
      inputs.add(r = new TextField("5",10));
      inputs.add(new Label("mean stock return (%/yr)"));
      inputs.add(mu = new TextField("15",10));
      inputs.add(new Label("std dev of stock return (%/yr)"));
      inputs.add(sigma = new TextField("30",10));
      inputs.add(new Label("allocation to risky asset (%)"));
      inputs.add(inrisky = new TextField("70",10));
      inputs.add(newRandomDraws = new Button("Simulate again"));
      inputs.add(new Label(""));
      inputs.add(resetInputs = new Button("Reset and simulate again"));
    add("South",inputs);
    vroom = new AssetAllocEngine(nper);
    times = new double[nper + 1];
    for(i=0;i<=nper;i++) times[i] = ((double) i) * ttm / ((double) nper);
    xgrid = new double[6];
    for(i=0;i<6;i++) xgrid[i] = ((double) i) * 2.0;
    ygrid = new double[6];
    for(i=0;i<6;i++) ygrid[i] = ((double) i) * 100.0;}
  public void startSimu() {
    vroom.newPars(text2double(r)/100.0,
        text2double(mu)/100.0,text2double(sigma)/100.0,ttm);
    ir = text2double(inrisky)/100.0;
    values = vroom.fixProps(ir,ir * 100.0,(1.0-ir)*100.0);
    blp.newXY(times,values,xgrid,ygrid,
      "Simulated Wealth, Fixed Proportions Startegy: 0-10 years out");
    show();}
  public void reset() {
    r.setText("5");
    mu.setText("15");
    sigma.setText("30");
    inrisky.setText("70");
    startSimu();}
  public boolean action(Event e, Object arg) {
    if(e.target == newRandomDraws) {
      startSimu();
      return true;}
    if(e.target == resetInputs) {
      reset();
      return true;}
    return false;}
  public boolean handleEvent(Event event) {
    if(event.id == Event.WINDOW_DESTROY) {
      dispose();}
    return super.handleEvent(event);}
  double text2double(TextField tf) {
    return Double.valueOf(tf.getText()).doubleValue();}}

class AssetAllocEngine {
  int nper;
  double tinc,r1per,mean1per,std1persqrt12;
  double[] values;
  public AssetAllocEngine(int nper) {
    values = new double[nper+1];
    this.nper = nper;}
  public void newPars(double r,double mu,double sigma,double ttm) {
    tinc = ttm/((double) nper);
    r1per = 1.0 + r * tinc;
    mean1per = 1.0 + mu * tinc;
    std1persqrt12 = sigma * Math.sqrt(12.0 * tinc);}
  public double[] fixProps(double inrisky,double initstock,
      double initcash) {
    double stock,cash,wealth,stockret;
    int i;
    stock = initstock;
    cash = initcash;
    for(i=1,values[0]=stock + cash;i<=nper;i++) {
      wealth = stock + cash;
      stock = wealth * inrisky;
      cash = wealth - stock;
      stockret = stockTotRet();
      stock *= stockret;
      cash *= r1per;
      values[i] = cash + stock;}
    return values;}
  double stockTotRet() {
    return mean1per + std1persqrt12 * (Math.random()-0.5);}}
Exhibit C: Line Plot program file BasicLinePlot.java
import java.awt.*;
      
public class BasicLinePlot extends Canvas {
  double[] x,y,xgrid,ygrid;
  int i,nper;
  int ixleft,ixright,iytop,iybottom,ih,iw,ihalftic,iRise,fmHeight;
  double xleft,xright,ytop,ybottom;
  double lmarg = 0.10,rmarg = 0.05,tmarg = 0.10,bmarg = 0.10,halftic = 0.0035;
  double ixintercept,ixslope,iyintercept,iyslope;
  String thingy;
  public BasicLinePlot() {}
  String mainTitle;
  public void newXY(double[] x,double[] y,double[] xgrid,double[] ygrid,
    String mainTitle) {
    if(x.length != y.length) {
      System.err.println("Error: x and y must have the same length");
      System.exit(-1);}
    this.x = new double[x.length];
    this.y = new double[x.length];
    for(i=0;i<x.length;i++) {
      this.x[i] = x[i];
      this.y[i] = y[i];}
    this.xgrid = new double[xgrid.length];
    this.ygrid = new double[ygrid.length];
    for(i=0;i<xgrid.length;i++)
      this.xgrid[i] = xgrid[i];
    for(i=0;i<ygrid.length;i++)
      this.ygrid[i] = ygrid[i];
    this.mainTitle = mainTitle;
    repaint();}
  public void paint(Graphics g) {
    if(xgrid != null) {
      xleft = xgrid[0];
      xright = xgrid[xgrid.length - 1];
      ybottom = ygrid[0];
      ytop = ygrid[ygrid.length - 1];
  
      Rectangle r = bounds();
      ih = r.height;
      iw = r.width;
      iytop = (int) (tmarg * ((double) ih));
      iybottom = (int) ((1.0-bmarg) * ((double) ih));
      ixleft = (int) (lmarg * ((double) iw));
      ixright = (int) ((1.0-rmarg) * ((double) iw));
      ihalftic = (int) (halftic * ((double) iw));
  
      ixslope = ((double) (ixright - ixleft))/(xright - xleft);
      ixintercept = 0.5 + (((double) ixright) * xleft - ((double) ixleft) *
        xright)
        /(xleft - xright);
      iyslope = ((double) (iybottom - iytop))/(ybottom - ytop);
      iyintercept = 0.5 + (((double) iybottom) * ytop - ((double) iytop) *
        ybottom)/(ytop - ybottom);
  
//
//  white background
//
      g.setColor(Color.white);
      g.fillRect(0,0,iw,ih);
  
//
//  draw the axes
//
      g.setColor(Color.black);
      g.drawLine(ixleft,iytop,ixleft,iybottom);
      g.drawLine(ixleft,iybottom,ixright,iybottom);
  
//
//  add tick marks
//
      g.setColor(Color.black);
      for(i=0;i<ygrid.length;i++)
        g.drawLine(ixleft-ihalftic,y2iy(ygrid[i]),
          ixleft+ihalftic,y2iy(ygrid[i]));
      for(i=0;i<xgrid.length;i++)
        g.drawLine(x2ix(xgrid[i]),iybottom-ihalftic,
          x2ix(xgrid[i]),iybottom+ihalftic);
  
//
//  add axis numbers
//
      g.setColor(Color.black);
      FontMetrics fm = g.getFontMetrics();
      iRise = fm.getAscent()/2;
      fmHeight = fm.getHeight();
      for(i=0;i<ygrid.length;i++) {
        thingy = Double.toString(ygrid[i]);
        g.drawString(thingy,ixleft - ihalftic -fm.stringWidth(thingy),
          y2iy(ygrid[i]) + iRise);}
      for(i=0;i<xgrid.length;i++) {
        thingy = Double.toString(xgrid[i]);
        g.drawString(thingy,x2ix(xgrid[i]) - fm.stringWidth(thingy)/2,
          iybottom + ihalftic + fmHeight);}
  
//
//  plot lines
//
      g.setColor(Color.blue);
      for(i=1;i<x.length;i++)
        g.drawLine(x2ix(x[i-1]),y2iy(y[i-1]),
          x2ix(x[i]),y2iy(y[i]));
  
//
//  add the mainTitle
//
      g.drawString(mainTitle,(ixright + ixleft)/2 -
        fm.stringWidth(mainTitle)/2,fmHeight);}}
  int x2ix(double x) {return (int) Math.floor(ixintercept + ixslope * x);}
  int y2iy(double y) {return (int) Math.floor(iyintercept + iyslope * y);}}