import java.util.*; import java.io.*; /** * Class representing the paths generated by the Monte Carlo engine. * * <p>To do list: * <ol> * <li><code>double[] pathDate</code> is not simulated.</li> * </ol> * * @author H W Yau * @version $Revision: 1.18 $ $Date: 1999/02/16 18:51:28 $ */ public class MonteCarloPath<region P> extends PathId<P> { //------------------------------------------------------------------------ // Class variables. //------------------------------------------------------------------------ /** * Class variable for determining whether to switch on debug output or * not. */ public static boolean DEBUG=true; /** * Class variable for defining the debug message prompt. */ protected static String prompt="MonteCarloPath> "; /** * Class variable for determining which field in the stock data should be * used. This is currently set to point to the 'closing price', as * defined in class RatePath. */ public static int DATUMFIELD=RatePath.DATUMFIELD; //------------------------------------------------------------------------ // Instance variables. //------------------------------------------------------------------------ /** * Random fluctuations generated as a series of random numbers with * given distribution. */ private double[]<P> fluctuations in P; /** * The path values from which the random fluctuations are used to update. */ private double[]<P> pathValue in P; /** * Integer flag for determining how the return was calculated, when * used to calculate the mean drift and volatility parameters. */ private int returnDefinition in P; /** * Value for the mean drift, for use in the generation of the random path. */ private double expectedReturnRate in P; /** * Value for the volatility, for use in the generation of the random path. */ private double volatility in P; /** * Number of time steps for which the simulation should act over. */ private int nTimeSteps in P; /** * The starting value for of the security. */ private double pathStartValue in P; //------------------------------------------------------------------------ // Constructors. //------------------------------------------------------------------------ /** * Default constructor. Needed by the HPT library to start create * new instances of this class. The instance variables for this should * then be initialised with the <code>setInitAllTasks()</code> method. */ public MonteCarloPath() { super(); // init moved here (5/18) returnDefinition = 0; expectedReturnRate = Double.NaN; volatility = Double.NaN; nTimeSteps = 0; pathStartValue = 0; set_prompt(prompt); set_DEBUG(DEBUG); } /** * Constructor, using the <code>ReturnPath</code> object to initialise * the necessary instance variables. * * @param returnPath Object used to define the instance variables in * this object. * @param nTimeSteps The number of time steps for which to generate the * random path. * @exception DemoException Thrown if there is a problem initialising the * object's instance variables. */ public MonteCarloPath(ReturnPath returnPath, int nTimeSteps) writes Root, P throws DemoException { /** * These instance variables are members of PathId class. */ // init moved here returnDefinition = 0; expectedReturnRate = Double.NaN; volatility = Double.NaN; nTimeSteps = 0; pathStartValue = 0; copyInstanceVariables(returnPath); this.nTimeSteps = nTimeSteps; this.pathValue = new double[nTimeSteps]<P>; this.fluctuations = new double[nTimeSteps]<P>; /** * Whether to debug, and how. */ set_prompt(prompt); set_DEBUG(DEBUG); } /** * Constructor, where the <code>PathId</code> objects is used to ease * the number of instance variables to pass in. * * @param pathId Object used to define the identity of this Path. * @param returnDefinition How the statistic variables were defined, * according to the definitions in * <code>ReturnPath</code>'s two class variables * <code>COMPOUNDED</code> and * <code>NONCOMPOUNDED</code>. * @param expectedReturnRate The measured expected return rate for which to generate. * @param volatility The measured volatility for which to generate. * @param nTimeSteps The number of time steps for which to generate. * @exception DemoException Thrown if there is a problem initialising the * object's instance variables. */ public MonteCarloPath(PathId<P> pathId, int returnDefinition, double expectedReturnRate, double volatility, int nTimeSteps) writes Root, P throws DemoException { /** * These instance variables are members of PathId class. * Invoking with this particular signature should point to the * definition in the PathId class. */ copyInstanceVariables(pathId); this.returnDefinition = returnDefinition; this.expectedReturnRate = expectedReturnRate; this.volatility = volatility; this.nTimeSteps = nTimeSteps; this.pathValue = new double[nTimeSteps]<P>; this.fluctuations = new double[nTimeSteps]<P>; /** * Whether to debug, and how. */ set_prompt(prompt); set_DEBUG(DEBUG); } /** * Constructor, for when the user wishes to define each of the instance * variables individually. * * @param name The name of the security which this Monte Carlo path * should represent. * @param startDate The date when the path starts, in 'YYYYMMDD' format. * @param endDate The date when the path ends, in 'YYYYMMDD' format. * @param dTime The interval in the data between successive data points * in the generated path. * @param returnDefinition How the statistic variables were defined, * according to the definitions in * <code>ReturnPath</code>'s two class variables * <code>COMPOUNDED</code> and * <code>NONCOMPOUNDED</code>. * @param expectedReturnRate The measured mean drift for which to generate. * @param volatility The measured volatility for which to generate. * @param nTimeSteps The number of time steps for which to generate. */ public MonteCarloPath(String name, int startDate, int endDate, double dTime, int returnDefinition, double expectedReturnRate, double volatility, int nTimeSteps) writes Root,P { /** * These instance variables are members of PathId class. */ set_name(name); set_startDate(startDate); set_endDate(endDate); set_dTime(dTime); this.returnDefinition = returnDefinition; this.expectedReturnRate = expectedReturnRate; this.volatility = volatility; this.nTimeSteps = nTimeSteps; this.pathValue = new double[nTimeSteps]<P>; this.fluctuations = new double[nTimeSteps]<P>; /** * Whether to debug, and how. */ set_prompt(prompt); set_DEBUG(DEBUG); } //------------------------------------------------------------------------ // Methods. //------------------------------------------------------------------------ //------------------------------------------------------------------------ // Accessor methods for class MonteCarloPath. // Generated by 'makeJavaAccessor.pl' script. HWY. 20th January 1999. //------------------------------------------------------------------------ /** * Accessor method for private instance variable <code>fluctuations</code>. * * @return Value of instance variable <code>fluctuations</code>. * @exception DemoException thrown if instance variable <code>fluctuations</code> * is undefined. */ public double[]<P> get_fluctuations() reads P throws DemoException { if( this.fluctuations == null ) throw new DemoException("Variable fluctuations is undefined!"); return(this.fluctuations); } /** * Set method for private instance variable <code>fluctuations</code>. * * @param fluctuations the value to set for the instance variable * <code>fluctuations</code>. */ public void set_fluctuations(double[]<P> fluctuations) writes P { this.fluctuations = fluctuations; } /** * Accessor method for private instance variable <code>pathValue</code>. * * @return Value of instance variable <code>pathValue</code>. * @exception DemoException thrown if instance variable <code>pathValue</code> * is undefined. */ public double[]<P> get_pathValue() reads P throws DemoException { if( this.pathValue == null ) throw new DemoException("Variable pathValue is undefined!"); return(this.pathValue); } /** * Set method for private instance variable <code>pathValue</code>. * * @param pathValue the value to set for the instance variable <code>pathValue</code>. */ public void set_pathValue(double[]<P> pathValue) writes P { this.pathValue = pathValue; } /** * Accessor method for private instance variable <code>returnDefinition</code>. * * @return Value of instance variable <code>returnDefinition</code>. * @exception DemoException thrown if instance variable <code>returnDefinition</code> * is undefined. */ public int get_returnDefinition() reads P throws DemoException { if( this.returnDefinition == 0 ) throw new DemoException("Variable returnDefinition is undefined!"); return(this.returnDefinition); } /** * Set method for private instance variable <code>returnDefinition</code>. * * @param returnDefinition the value to set for the instance variable * <code>returnDefinition</code>. */ public void set_returnDefinition(int returnDefinition) writes P { this.returnDefinition = returnDefinition; } /** * Accessor method for private instance variable <code>expectedReturnRate</code>. * * @return Value of instance variable <code>expectedReturnRate</code>. * @exception DemoException thrown if instance variable <code>expectedReturnRate</code> * is undefined. */ public double get_expectedReturnRate() reads P throws DemoException { if( this.expectedReturnRate == Double.NaN ) throw new DemoException("Variable expectedReturnRate is undefined!"); return(this.expectedReturnRate); } /** * Set method for private instance variable <code>expectedReturnRate</code>. * * @param expectedReturnRate the value to set for the instance variable * <code>expectedReturnRate</code>. */ public void set_expectedReturnRate(double expectedReturnRate) writes P { this.expectedReturnRate = expectedReturnRate; } /** * Accessor method for private instance variable <code>volatility</code>. * * @return Value of instance variable <code>volatility</code>. * @exception DemoException thrown if instance variable <code>volatility</code> * is undefined. */ public double get_volatility() reads P throws DemoException { if( this.volatility == Double.NaN ) throw new DemoException("Variable volatility is undefined!"); return(this.volatility); } /** * Set method for private instance variable <code>volatility</code>. * * @param volatility the value to set for the instance variable * <code>volatility</code>. */ public void set_volatility(double volatility) writes P { this.volatility = volatility; } /** * Accessor method for private instance variable <code>nTimeSteps</code>. * * @return Value of instance variable <code>nTimeSteps</code>. * @exception DemoException thrown if instance variable <code>nTimeSteps</code> * is undefined. */ public int get_nTimeSteps() reads P throws DemoException { if( this.nTimeSteps == 0 ) throw new DemoException("Variable nTimeSteps is undefined!"); return(this.nTimeSteps); } /** * Set method for private instance variable <code>nTimeSteps</code>. * * @param nTimeSteps the value to set for the instance variable * <code>nTimeSteps</code>. */ public void set_nTimeSteps(int nTimeSteps) writes P { this.nTimeSteps = nTimeSteps; } /** * Accessor method for private instance variable <code>pathStartValue</code>. * * @return Value of instance variable <code>pathStartValue</code>. * @exception DemoException thrown if instance variable <code>pathStartValue</code> * is undefined. */ public double get_pathStartValue() reads P throws DemoException { if( this.pathStartValue == Double.NaN ) throw new DemoException("Variable pathStartValue is undefined!"); return(this.pathStartValue); } /** * Set method for private instance variable <code>pathStartValue</code>. * * @param pathStartValue the value to set for the instance variable * <code>pathStartValue</code>. */ public void set_pathStartValue(double pathStartValue) writes P { this.pathStartValue = pathStartValue; } //------------------------------------------------------------------------ /** * Method for copying the suitable instance variable from a * <code>ReturnPath</code> object. * * @param obj Object used to define the instance variables which * should be carried over to this object. * @exception DemoException thrown if there is a problem accessing the * instance variables from the target objetct. */ private void copyInstanceVariables(ReturnPath obj) reads P writes Root,P throws DemoException { // // Instance variables defined in the PathId object. set_name(obj.get_name()); set_startDate(obj.get_startDate()); set_endDate(obj.get_endDate()); set_dTime(obj.get_dTime()); // // Instance variables defined in this object. this.returnDefinition = obj.get_returnDefinition(); this.expectedReturnRate = obj.get_expectedReturnRate(); this.volatility = obj.get_volatility(); } /** * Method for writing out the values from a Monte Carlo path into a * data file. This can then be fed back in as a test. * The data are written in the following format: <pre> 881003,0.0000,14.1944,13.9444,14.0832,2200050,0 881004,0.0000,14.1668,14.0556,14.1668,1490850,0 ... 990108,35.8125,36.7500,35.5625,35.8125,4381200,0 990111,35.8125,35.8750,34.8750,35.1250,3920800,0 990112,34.8750,34.8750,34.0000,34.0625,3577500,0 </pre> * <p>Where the fields represent, one believes, the following: * <ol> * <li>The date in 'YYMMDD' format</li> * <li>Open</li> * <li>High</li> * <li>Low</li> * <li>Last</li> * <li>Volume</li> * <li>Open Interest</li> * </ol> * One will probably make use of the closing price, but this can be * redefined via the class variable <code>DATUMFIELD</code>. Note that * since the read in data are then used to compute the return, this would * be a good place to trap for zero values in the data, which will cause * all sorts of problems. * * @param dirName the directory in which to write the data file. * @param filename the data filename itself. * @exception DemoException thrown if there was a problem with the data * file. */ public void writeFile(String dirName, String filename) throws DemoException { try{ java.io.File ratesFile = new File(dirName, filename); if( ratesFile.exists() && ! ratesFile.canWrite() ) throw new DemoException("Cannot write to specified filename!"); java.io.PrintWriter out = new PrintWriter(new BufferedWriter( new FileWriter(ratesFile))); for(int i=0; i < nTimeSteps; i++) { out.print("19990101,"); for(int j=1; j<DATUMFIELD; j++ ) { out.print("0.0000,"); } out.print(pathValue[i]+","); out.println("0.0000,0.0000"); } out.close(); } catch(java.io.IOException ioex) { throw new DemoException(ioex.toString()); } } /** * Method for returning a RatePath object from the Monte Carlo data * generated. * * @return a <code>RatePath</code> object representing the generated * data. * @exception DemoException thrown if there was a problem creating * the RatePath object. */ public RatePath<P> getRatePath() throws DemoException{ return(new RatePath<P>(this)); } /** * Method for calculating the sequence of fluctuations, based around * a Gaussian distribution of given mean and variance, as defined * in this class' instance variables. Mapping from Gaussian * distribution of (0,1) to (mean-drift,volatility) is done via * Ito's lemma on the log of the stock price. * * @param randomSeed The psuedo-random number seed value, to start off a * given sequence of Gaussian fluctuations. * @exception DemoException thrown if there are any problems with * the computation. */ // TODO main computation function. potential parallelism // MC computation with the random seed value public void computeFluctuationsGaussian(long randomSeed) writes P throws DemoException { if( nTimeSteps > fluctuations.length ) throw new DemoException("Number of timesteps requested is greater than the allocated array!"); // // First, make use of the passed in seed value. Random rnd; if( randomSeed == -1 ) { rnd = new Random(); } else { rnd = new Random(randomSeed); } // // Determine the mean and standard-deviation, from the mean-drift and volatility. double mean = (expectedReturnRate-0.5*volatility*volatility)*get_dTime(); double sd = volatility*Math.sqrt(get_dTime()); double gauss, meanGauss=0.0, variance=0.0; for( int i=0; i < nTimeSteps; i++ ) { gauss = rnd.nextGaussian(); // a method in Random class meanGauss+= gauss; variance+= (gauss*gauss); // // Now map this onto a general Gaussian of given mean and variance. fluctuations[i] = mean + sd*gauss; // dbgPrintln("gauss="+gauss+" fluctuations="+fluctuations[i]); } meanGauss/=(double)nTimeSteps; variance /=(double)nTimeSteps; // dbgPrintln("meanGauss="+meanGauss+" variance="+variance); } /** * Method for calculating the sequence of fluctuations, based around * a Gaussian distribution of given mean and variance, as defined * in this class' instance variables. Mapping from Gaussian * distribution of (0,1) to (mean-drift,volatility) is done via * Ito's lemma on the log of the stock price. This overloaded method * is for when the random seed should be decided by the system. * * @exception DemoException thrown if there are any problems with * the computation. */ public void computeFluctuationsGaussian() throws DemoException { computeFluctuationsGaussian((long)-1); } /** * Method for calculating the corresponding rate path, given the * fluctuations and starting rate value. * * @param startValue the starting value of the rate path, to be * updated with the precomputed fluctuations. * @exception DemoException thrown if there are any problems with * the computation. */ // TODO main computation method. public void computePathValue(double startValue) reads Root writes P throws DemoException { pathValue[0] = startValue; if( returnDefinition == ReturnPath.COMPOUNDED || returnDefinition == ReturnPath.NONCOMPOUNDED) { // may not be parallelized for(int i=1; i < nTimeSteps; i++ ) { pathValue[i] = pathValue[i-1] * Math.exp(fluctuations[i]); } } else { throw new DemoException("Unknown or undefined update method."); } } }