All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.finmath.montecarlo.templatemethoddesign.LogNormalProcess Maven / Gradle / Ivy

Go to download

finmath lib is a Mathematical Finance Library in Java. It provides algorithms and methodologies related to mathematical finance.

There is a newer version: 6.0.19
Show newest version
/*
 * Created on 19.01.2004
 */
package net.finmath.montecarlo.templatemethoddesign;

import net.finmath.montecarlo.BrownianMotion;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.TimeDiscretization;

/**
 * This class is an abstract base class to implement an Euler scheme of a multi-dimensional multi-factor log-normal Ito process.
 * The dimension is called numberOfComponents here. The default for numberOfFactors is 1.
 *
 * @author Christian Fries
 * @date 19.04.2008
 * @version 1.5
 */
public abstract class LogNormalProcess {

	public enum Scheme { EULER, PREDICTOR_USING_EULERSTEP, PREDICTOR_USING_LASTREALIZATION }

	private BrownianMotion	brownianMotion;

	private RandomVariable[][]     discreteProcess         = null;
	private RandomVariable[]       discreteProcessWeights  = null;

	private final TimeDiscretization	timeDiscretization;
	private final int			numberOfComponents;
	private final int			numberOfFactors;
	private final int			numberOfPaths;

	private Scheme		scheme = Scheme.EULER;

	/**
	 * Create a log normal process.
	 *
	 * @param numberOfComponents The number of components (scalar processes).
	 * @param brownianMotion A Brownian motion
	 */
	public LogNormalProcess(
			final int numberOfComponents,
			final BrownianMotion brownianMotion) {
		super();
		timeDiscretization	= brownianMotion.getTimeDiscretization();
		this.numberOfComponents	= numberOfComponents;
		numberOfFactors	= brownianMotion.getNumberOfFactors();
		numberOfPaths		= brownianMotion.getNumberOfPaths();
		this.brownianMotion		= brownianMotion;
	}

	/**
	 * Create a simulation of log normal process.
	 *
	 * @param timeDiscretization The time discretization of the process.
	 * @param numberOfComponents The number of components (the dimension of the process).
	 * @param numberOfPaths The number of path of the simulation.
	 */
	public LogNormalProcess(
			final TimeDiscretization timeDiscretization,
			final int numberOfComponents,
			final int numberOfPaths) {
		super();
		this.timeDiscretization = timeDiscretization;
		this.numberOfComponents = numberOfComponents;
		numberOfFactors = 1;
		this.numberOfPaths = numberOfPaths;

		// Create a Brownian motion
		brownianMotion = new net.finmath.montecarlo.BrownianMotionLazyInit(
				timeDiscretization,
				numberOfFactors,
				numberOfPaths,
				3141 /* seed */);
	}

	/**
	 * Create a simulation of log normal process.
	 *
	 * @param timeDiscretization The time discretization of the process.
	 * @param numberOfComponents The number of components (the dimension of the process).
	 * @param numberOfFactors The number of factors of the process.
	 * @param numberOfPaths The number of path of the simulation.
	 * @param seed The seed of the underlying random number generator.
	 */
	public LogNormalProcess(
			final TimeDiscretization timeDiscretization,
			final int numberOfComponents,
			final int numberOfFactors,
			final int numberOfPaths,
			final int seed) {
		super();
		this.timeDiscretization	= timeDiscretization;
		this.numberOfComponents	= numberOfComponents;
		this.numberOfFactors	= numberOfFactors;
		this.numberOfPaths		= numberOfPaths;

		// Create a Brownian motion
		brownianMotion = new net.finmath.montecarlo.BrownianMotionLazyInit(
				timeDiscretization,
				numberOfFactors,
				numberOfPaths,
				seed);
	}


	public abstract RandomVariable[]	getInitialValue();
	public abstract RandomVariable	getDrift(int timeIndex, int componentIndex, RandomVariable[] realizationAtTimeIndex, RandomVariable[] realizationPredictor);

	/**
	 * Get the the drift.
	 *
	 * @param timeIndex The time index (related to the model times discretization).
	 * @param realizationAtTimeIndex The given realization at timeIndex
	 * @param realizationPredictor The given realization at timeIndex+1 or null of no predictor is available.
	 * @return The (average) drift from timeIndex to timeIndex+1
	 */
	public RandomVariable[] getDrift(final int timeIndex, final RandomVariable[] realizationAtTimeIndex, final RandomVariable[] realizationPredictor) {

		final RandomVariable[] drift = new RandomVariable[getNumberOfComponents()];

		/*
		 * We implemented several different methods to calculate the drift
		 */
		for(int componentIndex=0; componentIndex
	 * dS(j) = (...) dt + S(j) * (λ(1,j) dW(1) + ... + λ(m,j) dW(m)) 
* in an m-factor model. Here j denotes index of the component of the resulting * log-normal process and i denotes the index of the factor.

* Overwrite this method if you would like to implement a multi factor model. * * @param timeIndex The time index of the simulation time discretization. * @param factor The factor index. * @param component The component index. * @param realizationAtTimeIndex The realization at the current time index. * @return factor loading for given factor and component */ public abstract RandomVariable getFactorLoading(int timeIndex, int factor, int component, RandomVariable[] realizationAtTimeIndex); /** * This method returns the realization of the process at a certain time index. * * @param timeIndex Time index at which the process should be observed * @return A vector of process realizations (on path) */ public RandomVariable[] getProcessValue(final int timeIndex) { // Thread safe lazy initialization synchronized(this) { if(discreteProcess == null || discreteProcess.length == 0) { doPrecalculateProcess(); } } // Return value of process return discreteProcess[timeIndex]; } /** * This method returns the realization of the process at a certain time index. * * @param timeIndex Time index at which the process should be observed * @param componentIndex Component of the process vector * @return A vector of process realizations (on path) */ public RandomVariable getProcessValue(final int timeIndex, final int componentIndex) { if(timeIndex == 0) { return getInitialValue()[componentIndex]; } // Lazy initialization, synchronized for thread safety synchronized(this) { if(discreteProcess == null || discreteProcess.length == 0) { doPrecalculateProcess(); } } // Return value of process return discreteProcess[timeIndex][componentIndex]; } /** * This method returns the weights of a weighted Monte Carlo method (the probability density). * * @param timeIndex Time index at which the process should be observed * @return A vector of positive weights which sums up to one */ public RandomVariable getMonteCarloWeights(final int timeIndex) { // Lazy initialization, synchronized for thread safety synchronized(this) { if(discreteProcessWeights == null || discreteProcessWeights.length == 0) { doPrecalculateProcess(); } } // Return value of process return discreteProcessWeights[timeIndex]; } /** * Calculates the whole (discrete) process. */ private void doPrecalculateProcess() { if(discreteProcess != null && discreteProcess.length != 0) { return; } // Allocate Memory discreteProcess = new RandomVariable[timeDiscretization.getNumberOfTimeSteps()+1][numberOfComponents]; discreteProcessWeights = new RandomVariable[getTimeDiscretization().getNumberOfTimeSteps()+1]; // Set initial Monte-Carlo weights discreteProcessWeights[0] = new RandomVariableFromDoubleArray(0.0, 1.0/numberOfPaths); // Store components discreteProcess[0] = getInitialValue(); // Evolve process for(int timeIndex = 1; timeIndex < timeDiscretization.getNumberOfTimeSteps()+1; timeIndex++) { // Generate process at timeIndex final double deltaT = timeDiscretization.getTime(timeIndex) - timeDiscretization.getTime(timeIndex-1); // Temp storage for variance and diffusion final RandomVariable[] variance = new RandomVariable[numberOfComponents]; final RandomVariable[] diffusion = new RandomVariable[numberOfComponents]; // Calculate new realization for(int componentIndex = numberOfComponents-1; componentIndex >= 0; componentIndex--) { // Calculate diffusion // Temp storage for variance and diffusion RandomVariable varianceOfComponent = new RandomVariableFromDoubleArray(getTime(timeIndex-1),0.0); RandomVariable diffusionOfComponent = new RandomVariableFromDoubleArray(getTime(timeIndex-1),0.0); // Generate values for diffusionOfComponent and varianceOfComponent for(int factor=0; factor= 0; componentIndex--) { final RandomVariable driftOfComponent = drift[componentIndex]; final RandomVariable varianceOfComponent = variance[componentIndex]; final RandomVariable diffusionOfComponent = diffusion[componentIndex]; if(driftOfComponent == null) { discreteProcess[timeIndex][componentIndex] = discreteProcess[timeIndex-1][componentIndex]; continue; } // Allocate memory for on path-realizations final double[] newRealization = new double[numberOfPaths]; // Euler Scheme final RandomVariable previouseRealization = discreteProcess[timeIndex-1][componentIndex]; // Generate values for(int pathIndex = 0; pathIndex < numberOfPaths; pathIndex++) { final double previousValue = previouseRealization.get(pathIndex); final double driftOnPath = driftOfComponent.get(pathIndex); final double varianceOnPath = varianceOfComponent.get(pathIndex); final double diffusionOnPath = diffusionOfComponent.get(pathIndex); // The scheme newRealization[pathIndex] = previousValue * Math.exp(driftOnPath * deltaT - 0.5 * varianceOnPath * deltaT + diffusionOnPath); } // Store components discreteProcess[timeIndex][componentIndex] = new RandomVariableFromDoubleArray(getTime(timeIndex),newRealization); } if(scheme == Scheme.PREDICTOR_USING_EULERSTEP) { final RandomVariable[] newRealization = new RandomVariableFromDoubleArray[numberOfComponents]; // Note: This is actually more than a predictor corrector: The drift of componentIndex already uses the corrected predictor from the previous components drift = getDrift(timeIndex-1, discreteProcess[timeIndex-1], discreteProcess[timeIndex]); // Apply corrector step to realizations at next time step for(int componentIndex = 0; componentIndex < numberOfComponents; componentIndex++) { final RandomVariable driftOfComponent = drift[componentIndex]; final RandomVariable varianceOfComponent = variance[componentIndex]; final RandomVariable diffusionOfComponent = diffusion[componentIndex]; // Euler Scheme with corrected drift final RandomVariable previouseRealization = discreteProcess[timeIndex-1][componentIndex]; // The scheme // newValue = previousValue * Math.exp(driftValue * deltaT - 0.5 * varianceOnPath * deltaT + diffusionOnPath); newRealization[componentIndex] = previouseRealization.mult((driftOfComponent.mult(deltaT).sub(varianceOfComponent.mult(0.5 * deltaT)).add(diffusionOfComponent)).exp()); } // End for(componentIndex) // Store predictor-corrector corrected process. discreteProcess[timeIndex] = newRealization; } // End if(scheme == LogNormalProcess.SCHEME_PREDICTOR_USES_EULER) // Set Monte-Carlo weights (since there is no Monte-Carlo weighting, the weights remain the same (namely 1.0/numberOfPaths). discreteProcessWeights[timeIndex] = discreteProcessWeights[timeIndex-1]; } // End for(timeIndex) } /** * @return Returns the numberOfComponents. */ public int getNumberOfComponents() { return numberOfComponents; } /** * @return Returns the numberOfPaths. */ public int getNumberOfPaths() { return numberOfPaths; } /** * @return Returns the numberOfFactors. */ public int getNumberOfFactors() { return numberOfFactors; } /** * @return Returns the timeDiscretizationFromArray. */ public TimeDiscretization getTimeDiscretization() { return timeDiscretization; } /** * Returns the time for a given simulation time index. * * @param timeIndex Time index * @return Returns the time for a given time index. */ public double getTime(final int timeIndex) { return timeDiscretization.getTime(timeIndex); } /** * Returns the time index for a given simulation time. * * @param time A simulation time * @return Returns the time index for a given time. */ public int getTimeIndex(final double time) { return timeDiscretization.getTimeIndex(time); } /** * @return Returns the Brownian motion used in the generation of the process */ public BrownianMotion getBrownianMotion() { return brownianMotion; } /** * @return Returns the scheme. */ public Scheme getScheme() { return scheme; } /** * A derived class may change the Brownian motion. This is only allowed prior to lazy initialization. * The method should be used only while constructing new object. Do not use in flight. * * @param brownianMotion The brownianMotion to set. */ protected synchronized void setBrownianMotion(final BrownianMotion brownianMotion) { if(discreteProcessWeights != null && discreteProcessWeights.length != 0) { throw new RuntimeException("Tying to change lazy initialized immutable object after initialization."); } this.brownianMotion = brownianMotion; } /** * @param scheme The scheme to set. */ public synchronized void setScheme(final Scheme scheme) { if(discreteProcessWeights != null && discreteProcessWeights.length != 0) { throw new RuntimeException("Tying to change lazy initialized immutable object after initialization."); } this.scheme = scheme; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy