package ift6561examples; // package umontreal.ssj.finance; import umontreal.ssj.stat.Tally; import umontreal.ssj.stochprocess.*; import umontreal.ssj.rng.*; import umontreal.ssj.mcqmctools.*; /** * This class represents an Asian average price call * option with European exercise type. The payoff of this option at the time of * expiration is given by the formula * *
*
* **
* where K is the strike price, and bar(S)T is the arithmetic average * **
**
* of the option's underlying asset price at the observation times ti ( i = * 1,…, n), with tn = * T, the time of expiration of the option. * *
* Note that the initial value S(t0)
* = of the price process is not included in the
* calculation of the average. However it will be included if the user sets the
* first observation time t1 to be
* the same as the initial time t0.
*
*/
public class AsianOption implements MonteCarloModelDouble {
StochasticProcess priceProcess; // Underlying process for the price.
int d; // Number of observation times.
double[] obsTimes; // obsTimes[0..d] must contain obsTimes[0]=0.0,
// plus the d positive observation times.
double[] path; // Sample path of the process.
double strike; // Strike price.
double discount; // Discount factor exp(-r * obsTimes[t]).
/**
* Array obsTimes[0..d+1] must contain obsTimes[0] = 0,
* plus the d observation times.
*
*/
public AsianOption(double r, int d, double[] obsTimes, double strike) {
this.d = d;
this.obsTimes = new double[d + 1];
for (int j = 0; j <= d; j++)
this.obsTimes[j] = obsTimes[j];
this.strike = strike;
discount = Math.exp(-r * obsTimes[d]);
}
// This constructor also specifies the underlying process.
public AsianOption(StochasticProcess sp, double r, int d,
double[] obsTimes, double strike) {
this(r, d, obsTimes, strike);
setProcess(sp);
}
/**
* Here the d observation times are equally spaced, from T1 to T.
*/
public AsianOption(double r, int d, double T1, double T, double strike) {
this.d = d;
obsTimes = new double[d + 1];
obsTimes[0] = 0.0;
for (int j = 1; j <= d; j++)
obsTimes[j] = T1 + (double) (j - 1) * (T - T1) / (double) (d - 1);
this.strike = strike;
discount = Math.exp(-r * obsTimes[d]);
}
/**
* Reset the process to sp. Assumes that obsTimes have
* been set.
*/
public void setProcess(StochasticProcess sp) {
// Reset the process to sp. Assumes that obsTimes have been set.
priceProcess = sp;
sp.setObservationTimes(obsTimes, d);
}
/**
* Computes and returns discounted payoff. Assumes path has been generated.
*/
public double getPerformance() {
double average = 0.0; // Average over sample path.
for (int j = 1; j <= d; j++)
average += path[j];
average /= d;
if (average > strike)
return discount * (average - strike);
else
return 0.0;
}
/**
* Returns the number of observation times d.
*
*/
public int getNumObsTimes() {
return d;
}
/**
* Generate a sample path of the process using stream
*/
public void simulate(RandomStream stream) {
path = priceProcess.generatePath(stream);
// Note: We cannot pre-generate RQMC points here and call
// generatePath(points), because not defined for all process types.
}
/**
* Performs n independent runs using
* stream and collects statistics in statValue.
* The collector statValue collects only the positive payoffs.
*/
public void simulateRuns(int n, RandomStream stream, Tally statValue,
Tally statValuePos) {
statValue.init();
statValuePos.init();
double x;
for (int i = 0; i < n; i++) {
simulate(stream);
x = getPerformance();
statValue.add(x);
if (x > 0.0000000001)
statValuePos.add(x);
stream.resetNextSubstream();
}
}
public String toString() {
return "Asian option model with " + d + " observation times";
}
}