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 * *

*

*
payoff * = max(0, bar(S)T - K)
*

*

* where K is the strike price, and bar(S)T is the arithmetic average * *

*

*
bar(S)T = $\displaystyle
 * {\frac{1}{n}}$i=1nS(ti) *
*

*

* 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) * = $ \tt s0$ 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"; } }