org.ojalgo.random.process.GeometricBrownianMotion Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ojalgo Show documentation
Show all versions of ojalgo Show documentation
oj! Algorithms - ojAlgo - is Open Source Java code that has to do with mathematics, linear algebra and optimisation.
/*
* Copyright 1997-2024 Optimatika
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.ojalgo.random.process;
import static org.ojalgo.function.constant.PrimitiveMath.*;
import org.ojalgo.array.Array1D;
import org.ojalgo.function.special.ErrorFunction;
import org.ojalgo.random.LogNormal;
import org.ojalgo.random.SampleSet;
import org.ojalgo.structure.Access1D;
/**
* Diffusion process defined by a stochastic differential equation:
*
*
* dX = r X dt + s X dW
*
*
* A stochastic process is said to follow a geometric Brownian motion if it satisfies this stochastic
* differential equation.
*
* @author apete
*/
public final class GeometricBrownianMotion extends SingleValueBasedProcess implements Process1D.ComponentProcess {
private static final WienerProcess GENERATOR = new WienerProcess();
/**
* @param seriesOfSamples A series of samples, evenly spaced in time.
* @param samplePeriod The amount of time (in which ever unit you prefer) between each sample in the
* series.
*/
public static GeometricBrownianMotion estimate(final Access1D> seriesOfSamples, final double samplePeriod) {
int sizeMinusOne = seriesOfSamples.size() - 1;
Array1D logDiffSeries = Array1D.R064.make(sizeMinusOne);
for (int i = 0; i < sizeMinusOne; i++) {
logDiffSeries.set(i, LOG.invoke(seriesOfSamples.doubleValue(i + 1) / seriesOfSamples.doubleValue(i)));
}
SampleSet sampleSet = SampleSet.wrap(logDiffSeries);
double tmpExp = sampleSet.getMean();
double tmpVar = sampleSet.getVariance();
double tmpDiff = SQRT.invoke(tmpVar / samplePeriod);
double tmpDrift = (tmpExp / samplePeriod) + ((tmpDiff * tmpDiff) / TWO);
GeometricBrownianMotion retVal = new GeometricBrownianMotion(tmpDrift, tmpDiff);
retVal.setValue(seriesOfSamples.doubleValue(sizeMinusOne));
return retVal;
}
/**
* Assuming initial value = 1.0 and horizon = 1.0.
*/
public static GeometricBrownianMotion make(final double expected, final double variance) {
return GeometricBrownianMotion.make(ONE, expected, variance, ONE);
}
/**
* Assuming initial value = 1.0.
*/
public static GeometricBrownianMotion make(final double expected, final double variance, final double horizon) {
return GeometricBrownianMotion.make(ONE, expected, variance, horizon);
}
/**
* @param initialValue The process initial value.
* @param expectedFutureValue An expected value (sometime in the future).
* @param aVariance The variance of that future value.
* @param aHorizon When do you expect that value?
*/
public static GeometricBrownianMotion make(final double initialValue, final double expectedFutureValue, final double aVariance, final double aHorizon) {
double tmpDrift = LOG.invoke(expectedFutureValue / initialValue) / aHorizon;
double tmpDiff = SQRT.invoke(LOG1P.invoke(aVariance / (expectedFutureValue * expectedFutureValue)) / aHorizon);
GeometricBrownianMotion retVal = new GeometricBrownianMotion(tmpDrift, tmpDiff);
retVal.setValue(initialValue);
return retVal;
}
private final double myDiffusionFunction;
private final double myLocalDrift;
public GeometricBrownianMotion(final double localDrift, final double diffusionFunction) {
super();
this.setValue(ONE);
myLocalDrift = localDrift;
myDiffusionFunction = diffusionFunction;
}
@SuppressWarnings("unused")
private GeometricBrownianMotion() {
this(ZERO, ZERO);
}
/**
* @param convertionFactor A step size change factor.
*/
public GeometricBrownianMotion convert(final double convertionFactor) {
double tmpDrift = myLocalDrift * convertionFactor;
double tmpDiff = myDiffusionFunction * SQRT.invoke(convertionFactor);
return new GeometricBrownianMotion(tmpDrift, tmpDiff);
}
public LogNormal getDistribution(final double evaluationPoint) {
double tmpVar = this.getDistributionVariance(evaluationPoint);
double tmpLocation = this.getDistributionLocation(evaluationPoint, tmpVar);
double tmpScale = SQRT.invoke(tmpVar);
return new LogNormal(tmpLocation, tmpScale);
}
public double getValue() {
return this.getCurrentValue();
}
public void setValue(final double newValue) {
this.setCurrentValue(newValue);
}
@Override
public double step(final double stepSize, final double standardGaussianInnovation) {
return this.doStep(stepSize, standardGaussianInnovation);
}
private double getDistributionLocation(final double stepSize, final double variance) {
return (LOG.invoke(this.getValue()) + (myLocalDrift * stepSize)) - (HALF * variance);
}
private double getDistributionVariance(final double stepSize) {
return myDiffusionFunction * myDiffusionFunction * stepSize;
}
@Override
double doStep(final double stepSize, final double normalisedRandomIncrement) {
double detPart = (myLocalDrift - ((myDiffusionFunction * myDiffusionFunction) / TWO)) * stepSize;
double randPart = myDiffusionFunction * SQRT.invoke(stepSize) * normalisedRandomIncrement;
double retVal = this.getCurrentValue() * EXP.invoke(detPart + randPart);
this.setCurrentValue(retVal);
return retVal;
}
/**
* Expected future value
*/
@Override
double getExpected(final double stepSize) {
return this.getValue() * EXP.invoke(myLocalDrift * stepSize);
}
@Override
double getLowerConfidenceQuantile(final double stepSize, final double confidence) {
double tmpVar = this.getDistributionVariance(stepSize);
double tmpLocation = this.getDistributionLocation(stepSize, tmpVar);
double tmpScale = SQRT.invoke(tmpVar);
return EXP.invoke(tmpLocation - (tmpScale * SQRT_TWO * ErrorFunction.erfi(confidence)));
}
@Override
double getNormalisedRandomIncrement() {
return GENERATOR.getNormalisedRandomIncrement();
}
@Override
double getStandardDeviation(final double stepSize) {
return SQRT.invoke(this.getVariance(stepSize));
}
@Override
double getUpperConfidenceQuantile(final double stepSize, final double confidence) {
double tmpVar = this.getDistributionVariance(stepSize);
double tmpLocation = this.getDistributionLocation(stepSize, tmpVar);
double tmpScale = SQRT.invoke(tmpVar);
return EXP.invoke(tmpLocation + (tmpScale * SQRT_TWO * ErrorFunction.erfi(confidence)));
}
@Override
double getVariance(final double stepSize) {
return this.getValue() * this.getValue() * EXP.invoke(TWO * myLocalDrift * stepSize) * EXPM1.invoke(this.getDistributionVariance(stepSize));
}
}