import java.io.*;
import java.util.*;
/**
* Class for recording the values in the time-dependent path of a security.
*
* <p>To Do list:
* <ol>
* <li><i>None!</i>
* </ol>
*
* @author H W Yau
* @version $Revision: 1.28 $ $Date: 1999/02/16 18:52:29 $
*/
public class RatePath<region P> extends PathId<P> {
//------------------------------------------------------------------------
// Class variables.
//------------------------------------------------------------------------
/**
* Class variable, for setting whether to print debug messages.
*/
public static boolean DEBUG=true;
/**
* The prompt to write before any debug messages.
*/
protected static String prompt="RatePath> ";
/**
* Class variable for determining which field in the stock data should be
* used. This is currently set to point to the 'closing price'.
*/
public static int DATUMFIELD=4;
/**
* Class variable to represent the minimal date, whence the stock prices
* appear. Used to trap any potential problems with the data.
*/
public static final int MINIMUMDATE = 19000101;
/**
* Class variable for defining what is meant by a small number, small enough
* to cause an arithmetic overflow when dividing. According to the
* Java Nutshell book, the actual range is +/-4.9406564841246544E-324
*/
public static final double EPSILON= 10.0 * Double.MIN_VALUE;
//------------------------------------------------------------------------
// Instance variables.
//------------------------------------------------------------------------
/**
* An instance variable, for storing the rate's path values itself.
*/
private double[]<P> pathValue in P;
/**
* An instance variable, for storing the corresponding date of the datum,
* in 'YYYYMMDD' format.
*/
private int[] pathDate in P;
/**
* The number of accepted values in the rate path.
*/
private int nAcceptedPathValue in P =0;
//------------------------------------------------------------------------
// Constructors.
//------------------------------------------------------------------------
/**
* Constructor, where the user specifies the filename in from which the
* data should be read.
*
* @param String filename
* @exception DemoException thrown if there is a problem reading in
* the data file.
*/
public RatePath(String filename) writes Root, P throws DemoException {
set_prompt(prompt);
set_DEBUG(DEBUG);
readRatesFile(null,filename);
}
/**
* Constructor, where the user specifies the directory and filename in
* from which the data should be read.
*
* @param String dirName
* @param String filename
* @exception DemoException thrown if there is a problem reading in
* the data file.
*/
public RatePath(String dirName, String filename) reads Root, P writes Root,P throws DemoException {
set_prompt(prompt);
set_DEBUG(DEBUG);
readRatesFile(dirName,filename);
}
/**
* Constructor, for when the user specifies simply an array of values
* for the path. User must also include information for specifying
* the other characteristics of the path.
*
* @param pathValue the array containing the values for the path.
* @param name the name to attach to the path.
* @param startDate date from which the path is supposed to start, in
* 'YYYYMMDD' format.
* @param startDate date from which the path is supposed to end, in
* 'YYYYMMDD' format.
* @param dTime the time interval between successive path values, in
* fractions of a year.
*/
public RatePath(double[]<P> pathValue, String name, int startDate, int endDate, double dTime) reads Root writes P {
set_name(name);
set_startDate(startDate);
set_endDate(endDate);
set_dTime(dTime);
set_prompt(prompt);
set_DEBUG(DEBUG);
this.pathValue = pathValue;
this.nAcceptedPathValue = pathValue.length;
}
/**
* Constructor, for use by the Monte Carlo generator, when it wishes
* to represent its findings as a RatePath object.
*
* @param mc the Monte Carlo generator object, whose data are to
* be copied over.
* @exception DemoException thrown if there is an attempt to access
* an undefined variable.
*/
public RatePath(MonteCarloPath<P> mc) reads Root writes P throws DemoException {
//
// Fields pertaining to the parent PathId object:
set_name(mc.get_name());
set_startDate(mc.get_startDate());
set_endDate(mc.get_endDate());
set_dTime(mc.get_dTime());
//
// Fields pertaining to RatePath object itself.
pathValue=mc.get_pathValue();
nAcceptedPathValue=mc.get_nTimeSteps();
//
// Note that currently the pathDate is neither declared, defined,
// nor used in the MonteCarloPath object.
pathDate=new int[nAcceptedPathValue];
}
/**
* Constructor, for when there is no actual pathValue with which to
* initialise.
*
* @param pathValueLegth the length of the array containing the values
* for the path.
* @param name the name to attach to the path.
* @param startDate date from which the path is supposed to start, in
* 'YYYYMMDD' format.
* @param startDate date from which the path is supposed to end, in
* 'YYYYMMDD' format.
* @param dTime the time interval between successive path values, in
* fractions of a year.
*/
public RatePath(int pathValueLength, String name, int startDate, int endDate, double dTime) reads Root writes P {
set_name(name);
set_startDate(startDate);
set_endDate(endDate);
set_dTime(dTime);
set_prompt(prompt);
set_DEBUG(DEBUG);
this.pathValue = new double[pathValueLength]<P>;
this.nAcceptedPathValue = pathValue.length;
}
//------------------------------------------------------------------------
// Methods.
//------------------------------------------------------------------------
/**
* Routine to update this rate path with the values from another rate
* path, via its pathValue array.
*
* @param operandPath the path value array to use for the update.
* @exception DemoException thrown if there is a mismatch between the
* lengths of the operand and target arrays.
*/
public <region R>void inc_pathValue(double[]<R> operandPath) reads R writes P /*throws DemoException*/ {
/*
if( pathValue.length != operandPath.length )
throw new DemoException("The path to update has a different size to the path to update with!");
*/
// foreach (int i in 0, pathValue.length) {
for(int i=0; i<pathValue.length; i++ ) {
pathValue[i] += operandPath[i];
}
}
public <region R>void inc_pathValue2(double[]<R> operandPath)
reads R writes P {
for (int i=0;i<pathValue.length;i++) {
pathValue[i] += operandPath[i];
}
}
/**
* Routine to scale this rate path by a constant.
*
* @param scale the constant with which to multiply to all the path
* values.
* @exception DemoException thrown if there is a mismatch between the
* lengths of the operand and target arrays.
*/
public void inc_pathValue(double scale) writes P, Root throws DemoException {
if( pathValue==null )
throw new DemoException("Variable pathValue is undefined!");
for(int i=0; i<pathValue.length; i++ ) {
// foreach (int i in 0, pathValue.length) {
pathValue[i] *= scale;
//pathVal *= scale;
}
}
//------------------------------------------------------------------------
// Accessor methods for class RatePath.
// Generated by 'makeJavaAccessor.pl' script. HWY. 20th January 1999.
//------------------------------------------------------------------------
/**
* 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>pathDate</code>.
*
* @return Value of instance variable <code>pathDate</code>.
* @exception DemoException thrown if instance variable <code>pathDate</code> is undefined.
*/
public int[] get_pathDate() reads P throws DemoException {
if( this.pathDate == null )
throw new DemoException("Variable pathDate is undefined!");
return(this.pathDate);
}
/**
* Set method for private instance variable <code>pathDate</code>.
*
* @param pathDate the value to set for the instance variable <code>pathDate</code>.
*/
public void set_pathDate(int[] pathDate) writes P {
this.pathDate = pathDate;
}
//------------------------------------------------------------------------
/**
* Method to return the terminal value for a given rate path, as used
* in derivative calculations.
*
* @return The last value in the rate path.
*/
public double getEndPathValue() reads Root writes P {
return( getPathValue(pathValue.length-1) );
}
/**
* Method to return the value for a given rate path, at a given index.
* <i>One may want to index this in a more user friendly manner!</i>
*
* @param index the index on which to return the path value.
* @return The value of the path at the designated index.
*/
public double getPathValue(int index) reads Root,P {
return(pathValue[index]);
}
/**
* Method for calculating the returns on a given rate path, via the
* definition for the instantaneous compounded return.
* u_i = \ln{\frac{S_i}{S_{i-1}}}
*
* @return the return, as defined.
* @exception DemoException thrown if there is a problem with the
* calculation.
*/
// TODO main computation method. potential parallelism around for loops.
public ReturnPath<P> getReturnCompounded() reads Root writes P throws DemoException {
if( pathValue == null || nAcceptedPathValue == 0 ) {
throw new DemoException("The Rate Path has not been defined!");
}
// returnPathValue
//*******************************************************************
// array of double type with size of # of accepted path value
//*******************************************************************
double[]<P> returnPathValue = new double[nAcceptedPathValue]<P>;
returnPathValue[0] = 0.0;
try{
// can this be a parallel loop?
// TODO maybe no...
for(int i=1; i< nAcceptedPathValue; i++ ) {
//foreach (int i in 1, nAcceptedPathValue) {
returnPathValue[i] = Math.log(pathValue[i] / pathValue[i-1]);
}
} catch( ArithmeticException aex ) {
throw new DemoException("Error in getReturnLogarithm:"+aex.toString());
}
// initialize return path
ReturnPath<P> rPath = new ReturnPath<P>(returnPathValue, nAcceptedPathValue,ReturnPath.COMPOUNDED);
//
// Copy the PathId information to the ReturnPath object.
rPath.copyInstanceVariables(this);
rPath.estimatePath();
return(rPath);
}
/**
* Method for calculating the returns on a given rate path, via the
* definition for the instantaneous non-compounded return.
* u_i = \frac{S_i - S_{i-1}}{S_i}
*
* @return the return, as defined.
* @exception DemoException thrown if there is a problem with the
* calculation.
*/
public ReturnPath<P> getReturnNonCompounded() reads Root,P writes P throws DemoException {
if( pathValue == null || nAcceptedPathValue == 0 ) {
throw new DemoException("The Rate Path has not been defined!");
}
double[]<P> returnPathValue = new double[nAcceptedPathValue]<P>;
returnPathValue[0] = 0.0;
try{
// TODO parallelizable?
for(int i=1; i< nAcceptedPathValue; i++ ) {
returnPathValue[i] = (pathValue[i] - pathValue[i-1])/pathValue[i];
}
} catch( ArithmeticException aex ) {
throw new DemoException("Error in getReturnPercentage:"+aex.toString());
}
ReturnPath<P> rPath = new ReturnPath<P>(returnPathValue, nAcceptedPathValue,
ReturnPath.NONCOMPOUNDED);
//
// Copy the PathId information to the ReturnPath object. (name, date...)
rPath.copyInstanceVariables(this);
// ********************************************************************
// computation in ReturnPath class
rPath.estimatePath();
// ********************************************************************
return(rPath);
}
//------------------------------------------------------------------------
// Private methods.
//------------------------------------------------------------------------
/**
* Method for reading in data file, in a given format.
* Namely:
<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 search for the data file.
* @param filename the data filename itself.
* @exception DemoException thrown if there was a problem with the data
* file.
*/
// TODO cannot serialize; just copy the body
private void readRatesFile(String dirName, String filename) reads Root,P writes Root,P throws DemoException {
java.io.File ratesFile = new File(dirName, filename);
java.io.BufferedReader in;
if( ! ratesFile.canRead() ) {
throw new DemoException("Cannot read the file "+ratesFile.toString());
}
try{
in = new BufferedReader(new FileReader(ratesFile));
} catch( FileNotFoundException fnfex ) {
throw new DemoException(fnfex.toString());
}
//
// Proceed to read all the lines of data into a Vector object.
int iLine=0, initNlines=100, nLines=0;
String aLine;
java.util.Vector allLines = new Vector(initNlines);
try{
while( (aLine = in.readLine()) != null ) {
iLine++;
//
// Note, I'm not entirely sure whether the object passed in is copied
// by value, or just its reference.
allLines.addElement(aLine);
}
} catch( IOException ioex ) {
throw new DemoException("Problem reading data from the file "+ioex.toString());
}
nLines = iLine;
//
// Now create an array to store the rates data.
// two arrays of double type and int type
// **********************************************************************
this.pathValue = new double[nLines]<P>;
this.pathDate = new int[nLines];
// **********************************************************************
nAcceptedPathValue=0;
iLine=0;
for( java.util.Enumeration enum_ = allLines.elements(); enum_.hasMoreElements(); ) {
aLine = (String) enum_.nextElement();
String[] field = Utilities.splitString(",",aLine);
int aDate = Integer.parseInt("19"+field[0]);
//
// static double Double.parseDouble() method is a feature of JDK1.2!
double aPathValue = Double.valueOf(field[DATUMFIELD]).doubleValue();
if( (aDate <= MINIMUMDATE) || (Math.abs(aPathValue) < EPSILON) ) {
//dbgPrintln("Skipped erroneous data in "+filename+" indexed by date="+field[0]+".");
}
else {
pathDate[iLine] = aDate;
pathValue[iLine] = aPathValue;
iLine++;
}
}
//
// Record the actual number of accepted data points.
nAcceptedPathValue = iLine;
//
// Now to fill in the structures from the 'PathId' class.
set_name(ratesFile.getName());
set_startDate(pathDate[0]);
set_endDate(pathDate[nAcceptedPathValue-1]);
set_dTime((double)(1.0/365.0));
}
}