AbstractTreeProduct.java

package net.finmath.tree;

import net.finmath.stochastic.RandomVariable;

/**
 * Base class for products that can be priced on a (recombining) with TreeModel.
 * This abstraction provides a small template:
 * <ul>
 * 	<li>getValue(TreeModel) returns the scalar time–0 price.</li>
 * 	<li>getValue(double, TreeModel) returns the value as a RandomVariable at a given evaluation time.</li>
 * 	<li>getValues(double, TreeModel) must be implemented by subclasses and should return the full vector of values
 * 		(per state) at each time level, produced by a backward induction. By convention the element at index 0
 * 		corresponds to time 0.</li>
 * </ul>
 * Subclasses (e.g. European, American, Asian) implement their payoff logic and early–exercise features within
 * getValues(double, TreeModel).
 *
 * @author Carlo Andrea Tramentozzi
 * @author Alessandro Gnoatto
 * @author Andrea Mazzon
 */
public abstract class AbstractTreeProduct implements TreeProduct {

	/** Contract maturity (in model time units). */
	private final double maturity;

	/**
	 * Creates a tree-priced product with the given maturity.
	 *
	 * @param maturity The contract maturity must be compatible with the model time grid.
	 */
	public AbstractTreeProduct(final double maturity) {
		this.maturity = maturity;
	}

	/**
	 * Returns the time–0 present value under the given model.
	 * This is a convenience method delegating to getValue(double, TreeModel)
	 * with evaluationTime = 0.0 and extracting the scalar value from the returned RandomVariable.
	 *
	 * @param model The tree model to use (providing discounting and conditional expectations).
	 * @return The time–0 price.
	 * @throws IllegalArgumentException If model is null or the evaluation fails.
	 */
	@Override
	public double getValue(final TreeModel model) {
		final RandomVariable v0 = getValue(0.0, model);
		return v0.get(0);
	}

	/**
	 * Returns the product value at a given evaluation time as a RandomVariable.
	 * The default implementation calls getValues(double, TreeModel) and returns the corresponding component.
	 * Subclasses should ensure their {@link #getValues(double, TreeModel)} respects this convention.
	 * Internally, the method creates all values from time zero and returns the level of interest. While this is
	 * inefficient for non-path-dependent products, it ensures a correct implementation for path dependent products.
	 * The alternative would be to provide as input the current value of the path-dependent functional, which would
	 * break the interface.
	 *
	 * @param evaluationTime The time at which the value is requested (must be >= 0).
	 * @param model The tree model to use.
	 * @return The value at evaluationTime as a random variable on the tree.
	 * @throws IllegalArgumentException If the inputs are invalid (see validate(double, TreeModel)).
	 */
	public RandomVariable getValue(final double evaluationTime, final TreeModel model) {
		final RandomVariable[] levels = getValues(0.0, model);
		// This is dangerous as it assumes a uniform time discretization.
		final int index = (int) Math.round(evaluationTime / model.getTimeStep());
		return levels[index];
	}

	/**
	 * Computes the vector of values at each time/state on the tree (via backward induction).
	 * Implementations should:
	 * <ul>
	 * 	<li>Validate inputs via validate(double, TreeModel).</li>
	 * 	<li>Return an array whose element at index k is a RandomVariable representing the value at time level k
	 * 		(with length equal to the number of states at that level).</li>
	 * </ul>
	 *
	 * @param evaluationTime The time at which valuation is performed.
	 * @param model The tree model (spot lattice, discounting, conditional expectation).
	 * @return An array of value random variables, one per time level, indexed from 0 to maturity level.
	 */
	public abstract RandomVariable[] getValues(double evaluationTime, TreeModel model);

	/**
	 * Basic input validation helper used by implementations.
	 *
	 * @param t The evaluation time (must be >= 0).
	 * @param m The model (must not be null).
	 * @throws IllegalArgumentException If {@code m == null} or {@code t < 0}.
	 */
	protected void validate(final double t, final TreeModel m) {
		if(m == null) {
			throw new IllegalArgumentException("model null");
		}
		if(t < 0) {
			throw new IllegalArgumentException("evaluationTime < 0");
		}
	}

	/**
	 * Returns the contract maturity.
	 *
	 * @return The maturity T.
	 */
	protected double getMaturity() {
		return maturity;
	}
}