diff --git a/src/main/java/net/finmath/fouriermethod/calibration/models/CalibratableMertonModel.java b/src/main/java/net/finmath/fouriermethod/calibration/models/CalibratableMertonModel.java index 429b0f9596..fabd481453 100644 --- a/src/main/java/net/finmath/fouriermethod/calibration/models/CalibratableMertonModel.java +++ b/src/main/java/net/finmath/fouriermethod/calibration/models/CalibratableMertonModel.java @@ -1,11 +1,13 @@ package net.finmath.fouriermethod.calibration.models; +import java.time.LocalDate; import java.util.Arrays; import net.finmath.fouriermethod.calibration.ScalarParameterInformation; import net.finmath.fouriermethod.calibration.ScalarParameterInformationImplementation; import net.finmath.fouriermethod.calibration.Unconstrained; import net.finmath.fouriermethod.models.MertonModel; +import net.finmath.marketdata.model.curves.DiscountCurve; import net.finmath.modelling.ModelDescriptor; import net.finmath.modelling.descriptor.MertonModelDescriptor; @@ -100,10 +102,18 @@ public ModelDescriptor getModelDescriptor() { @Override public MertonModel getCharacteristicFunctionModel() { - return new MertonModel(descriptor.getReferenceDate(),descriptor.getInitialValue(),descriptor.getDiscountCurveForForwardRate(), - descriptor.getDiscountCurveForDiscountRate(),descriptor.getVolatility(), - descriptor.getJumpIntensity(),descriptor.getJumpSizeMean(),descriptor.getJumpSizeStdDev()); - } + final LocalDate referenceDate = descriptor.getReferenceDate(); + final double initialValue = descriptor.getInitialValue(); + final DiscountCurve forwardDiscountCurve = descriptor.getDiscountCurveForForwardRate(); + final DiscountCurve discountCurveForDiscountRate = descriptor.getDiscountCurveForDiscountRate(); + final double volatility = descriptor.getVolatility(); + final double jumpIntensity = descriptor.getJumpIntensity(); + final double jumpSizeMean = descriptor.getJumpSizeMean(); + final double jumpSizeStdDev = descriptor.getJumpSizeStdDev(); + + return new MertonModel(referenceDate, initialValue, forwardDiscountCurve, discountCurveForDiscountRate, volatility, jumpIntensity, jumpSizeMean, jumpSizeStdDev); +} + @Override public double[] getParameterLowerBounds() { diff --git a/src/main/java/net/finmath/interpolation/ConstantExtrapolation.java b/src/main/java/net/finmath/interpolation/ConstantExtrapolation.java new file mode 100644 index 0000000000..329a4be55a --- /dev/null +++ b/src/main/java/net/finmath/interpolation/ConstantExtrapolation.java @@ -0,0 +1,8 @@ +package net.finmath.interpolation; + +public class ConstantExtrapolation extends Extrapolation { + @Override + public double getValue(double[] points, double[] values, double x) { + return values[0]; + } +} diff --git a/src/main/java/net/finmath/interpolation/Extrapolation.java b/src/main/java/net/finmath/interpolation/Extrapolation.java new file mode 100644 index 0000000000..aa953fc2a4 --- /dev/null +++ b/src/main/java/net/finmath/interpolation/Extrapolation.java @@ -0,0 +1,5 @@ +package net.finmath.interpolation; + +public abstract class Extrapolation { + public abstract double getValue(double[] points, double[] values, double x); +} diff --git a/src/main/java/net/finmath/interpolation/LinearExtrapolation.java b/src/main/java/net/finmath/interpolation/LinearExtrapolation.java new file mode 100644 index 0000000000..fc832292d2 --- /dev/null +++ b/src/main/java/net/finmath/interpolation/LinearExtrapolation.java @@ -0,0 +1,9 @@ +package net.finmath.interpolation; + +public class LinearExtrapolation extends Extrapolation { + @Override + public double getValue(double[] points, double[] values, double x) { + return values[0] + (values[1] - values[0]) / (points[1] - points[0]) * (x - points[0]); + } +} + diff --git a/src/main/java/net/finmath/interpolation/RationalFunctionInterpolation.java b/src/main/java/net/finmath/interpolation/RationalFunctionInterpolation.java index 6a3ddc19e9..1da71c5016 100755 --- a/src/main/java/net/finmath/interpolation/RationalFunctionInterpolation.java +++ b/src/main/java/net/finmath/interpolation/RationalFunctionInterpolation.java @@ -181,49 +181,55 @@ public InterpolationMethod getInterpolationMethod() { * @param x The abscissa at which the interpolation should be performed. * @return The interpolated value (ordinate). */ - public double getValue(final double x) - { + public double getValue(final double x) { synchronized(interpolatingRationalFunctionsLazyInitLock) { if(interpolatingRationalFunctions == null) { doCreateRationalFunctions(); } } - + // Get interpolating rational function for the given point x final int pointIndex = java.util.Arrays.binarySearch(points, x); if(pointIndex >= 0) { return values[pointIndex]; } - + int intervalIndex = -pointIndex-2; - + // Check for extrapolation + Extrapolation extrapolation; if(intervalIndex < 0) { // Extrapolation - if(extrapolationMethod == ExtrapolationMethod.CONSTANT) { - return values[0]; - } else if(extrapolationMethod == ExtrapolationMethod.LINEAR) { - return values[0]+(values[1]-values[0])/(points[1]-points[0])*(x-points[0]); - } else { - intervalIndex = 0; - } - } - else if(intervalIndex > points.length-2) { + extrapolation = getExtrapolationMethod(); + intervalIndex = 0; + } else if(intervalIndex > points.length-2) { // Extrapolation - if(extrapolationMethod == ExtrapolationMethod.CONSTANT) { - return values[points.length-1]; - } else if(extrapolationMethod == ExtrapolationMethod.LINEAR) { - return values[points.length-1]+(values[points.length-2]-values[points.length-1])/(points[points.length-2]-points[points.length-1])*(x-points[points.length-1]); - } else { - intervalIndex = points.length-2; - } + extrapolation = getExtrapolationMethod(); + intervalIndex = points.length-2; + } else { + extrapolation = null; + } + + // Calculate interpolating value or use extrapolation + if(extrapolation == null) { + final RationalFunction rationalFunction = interpolatingRationalFunctions[intervalIndex]; + return rationalFunction.getValue(x-points[intervalIndex]); + } else { + return extrapolation.getValue(points, values, x); + } + } + + public Extrapolation getExtrapolationMethod() { + if(extrapolationMethod == ExtrapolationMethod.CONSTANT) { + return new ConstantExtrapolation(); + } else if(extrapolationMethod == ExtrapolationMethod.LINEAR) { + return new LinearExtrapolation(); + } else { + return null; } - - final RationalFunction rationalFunction = interpolatingRationalFunctions[intervalIndex]; - - // Calculate interpolating value - return rationalFunction.getValue(x-points[intervalIndex]); } + + private void doCreateRationalFunctions() { diff --git a/src/main/java/net/finmath/marketdata/calibration/CalibratedCurves.java b/src/main/java/net/finmath/marketdata/calibration/CalibratedCurves.java index 5e40fc5c5f..226712556d 100644 --- a/src/main/java/net/finmath/marketdata/calibration/CalibratedCurves.java +++ b/src/main/java/net/finmath/marketdata/calibration/CalibratedCurves.java @@ -756,13 +756,9 @@ else if(ForwardCurve.class.isInstance(calibrationCurveOld)) { * @return The discount factor curve associated with the given name. */ private DiscountCurve createDiscountCurve(final String discountCurveName) { - DiscountCurve discountCurve = model.getDiscountCurve(discountCurveName); - if(discountCurve == null) { - discountCurve = DiscountCurveInterpolation.createDiscountCurveFromDiscountFactors(discountCurveName, new double[] { 0.0 }, new double[] { 1.0 }); - model = model.addCurves(discountCurve); - } + DiscountedAnalyticCurves discountedAnalyticCurves = new DiscountedAnalyticCurves(); - return discountCurve; + return discountedAnalyticCurves.createDiscountCurve(discountCurveName, model); } /** diff --git a/src/main/java/net/finmath/marketdata/calibration/DiscountedAnalyticCurves.java b/src/main/java/net/finmath/marketdata/calibration/DiscountedAnalyticCurves.java new file mode 100644 index 0000000000..3db155e5b8 --- /dev/null +++ b/src/main/java/net/finmath/marketdata/calibration/DiscountedAnalyticCurves.java @@ -0,0 +1,18 @@ +package net.finmath.marketdata.calibration; + +import net.finmath.marketdata.model.AnalyticModel; +import net.finmath.marketdata.model.curves.DiscountCurve; +import net.finmath.marketdata.model.curves.DiscountCurveInterpolation; + +public class DiscountedAnalyticCurves { + public DiscountCurve createDiscountCurve(final String discountCurveName, AnalyticModel model) { + DiscountCurve discountCurve = model.getDiscountCurve(discountCurveName); + if(discountCurve == null) { + discountCurve = DiscountCurveInterpolation.createDiscountCurveFromDiscountFactors(discountCurveName, new double[] { 0.0 }, new double[] { 1.0 }); + model = model.addCurves(discountCurve); + } + + return discountCurve; + } + +} diff --git a/src/main/java/net/finmath/marketdata/products/MarketForwardRateAgreement.java b/src/main/java/net/finmath/marketdata/products/MarketForwardRateAgreement.java index 988ef8ee7f..ce1f17dff2 100644 --- a/src/main/java/net/finmath/marketdata/products/MarketForwardRateAgreement.java +++ b/src/main/java/net/finmath/marketdata/products/MarketForwardRateAgreement.java @@ -64,7 +64,7 @@ public double getValue(final double evaluationTime, final AnalyticModel model) { final DiscountCurve discountCurve = model.getDiscountCurve(discountCurveName); DiscountCurve discountCurveForForward = null; - if(forwardCurve == null && forwardCurveName != null && forwardCurveName.length() > 0) { + if(checkForwardCurve(forwardCurve, forwardCurveName)) { // User might like to get forward from discount curve. discountCurveForForward = model.getDiscountCurve(forwardCurveName); @@ -88,4 +88,8 @@ else if(discountCurveForForward != null) { return payoff * discountFactor / discountCurve.getDiscountFactor(model, evaluationTime); } + + public boolean checkForwardCurve(ForwardCurve forwardCurve, String forwardCurveName){ + return (forwardCurve == null && forwardCurveName != null && forwardCurveName.length() > 0); + } } diff --git a/src/main/java/net/finmath/montecarlo/GammaProcess.java b/src/main/java/net/finmath/montecarlo/GammaProcess.java index 79f07184d0..3475d81823 100644 --- a/src/main/java/net/finmath/montecarlo/GammaProcess.java +++ b/src/main/java/net/finmath/montecarlo/GammaProcess.java @@ -55,7 +55,7 @@ public class GammaProcess implements IndependentIncrements, Serializable { private final RandomVariableFactory randomVariableFactory = new RandomVariableFromArrayFactory(); - private transient RandomVariable[][] gammaIncrements; + private transient RandomVariable[][] gammaIncrements; /** * Construct a Gamma process with a given shape parameter. @@ -122,12 +122,12 @@ public RandomVariable getIncrement(final int timeIndex, final int factor) { doGenerateGammaIncrements(); } } - /* * For performance reasons we return directly the stored data (no defensive copy). * We return an immutable object to ensure that the receiver does not alter the data. */ - return gammaIncrements[timeIndex][factor]; + RandomVariableLazyEvaluation randomVariableLazyEvaluation = new RandomVariableLazyEvaluation(null); + return randomVariableLazyEvaluation.getIncrement(timeIndex, factor); } /** diff --git a/src/main/java/net/finmath/montecarlo/RandomVariableLazyEvaluation.java b/src/main/java/net/finmath/montecarlo/RandomVariableLazyEvaluation.java index 24b8a7d372..a9a97b7c36 100644 --- a/src/main/java/net/finmath/montecarlo/RandomVariableLazyEvaluation.java +++ b/src/main/java/net/finmath/montecarlo/RandomVariableLazyEvaluation.java @@ -36,7 +36,10 @@ public class RandomVariableLazyEvaluation implements RandomVariable { /** * */ + + private static final long serialVersionUID = 8413020544732461630L; + private transient RandomVariable[][] gammaIncrements; private final double time; // Time (filtration) @@ -59,6 +62,7 @@ public RandomVariableLazyEvaluation(final RandomVariable value) { realizations = value.isDeterministic() ? null : value::get; size = value.size(); valueIfNonStochastic = value.isDeterministic() ? value.get(0) : Double.NaN; + gammaIncrements = null; // Lazy initialization } /** @@ -68,8 +72,9 @@ public RandomVariableLazyEvaluation(final RandomVariable value) { */ public RandomVariableLazyEvaluation(final double value) { this(0.0, value); - } + gammaIncrements = null; // Lazy initialization + } /** * Create a random variable by applying a function to a given other implementation of RandomVariable. * @@ -87,6 +92,8 @@ public double applyAsDouble(final int i) { }; size = value.size(); valueIfNonStochastic = value.isDeterministic() ? function.applyAsDouble(value.get(0)) : Double.NaN; + gammaIncrements = null; // Lazy initialization + } /** @@ -101,6 +108,17 @@ public RandomVariableLazyEvaluation(final double time, final double value) { realizations = null; size = 1; valueIfNonStochastic = value; + gammaIncrements = null; // Lazy initialization + + } + + public RandomVariable getIncrement(final int timeIndex, final int factor) { + // Thread safe lazy initialization + /* + * For performance reasons we return directly the stored data (no defensive copy). + * We return an immutable object to ensure that the receiver does not alter the data. + */ + return gammaIncrements[timeIndex][factor]; } /** diff --git a/src/main/java/net/finmath/timeseries/models/parametric/ARMAGARCH.java b/src/main/java/net/finmath/timeseries/models/parametric/ARMAGARCH.java index fec32da024..4a44bd668b 100644 --- a/src/main/java/net/finmath/timeseries/models/parametric/ARMAGARCH.java +++ b/src/main/java/net/finmath/timeseries/models/parametric/ARMAGARCH.java @@ -73,35 +73,35 @@ public double getLogLikelihoodForParameters(final double[] parameters) double logLikelihood = 0.0; final double volScaling = 1; - double evalPrev = 0.0; - double eval = volScaling * (Math.log((timeSeries.getValue(1))/(timeSeries.getValue(0)))); - if(Double.isInfinite(eval) || Double.isNaN(eval)) { - eval = 0; + double evaluationPrev = 0.0; + double evaluation = volScaling * (Math.log((timeSeries.getValue(1))/(timeSeries.getValue(0)))); + if(Double.isInfinite(evaluation) || Double.isNaN(evaluation)) { + evaluation = 0; } double h = omega / (1.0 - alpha - beta); double m = 0.0; // xxx how to init? - logLikelihood += - Math.log(h) - 2 * Math.log((Math.abs(timeSeries.getValue(1)))/volScaling) - eval*eval / h; + logLikelihood += - Math.log(h) - 2 * Math.log((Math.abs(timeSeries.getValue(1)))/volScaling) - evaluation*evaluation / h; final int length = timeSeries.getNumberOfTimePoints(); for (int i = 1; i < length-1; i++) { - m = -mu -theta * m + eval - phi * evalPrev; + m = -mu -theta * m + evaluation - phi * evaluationPrev; h = (omega + alpha * m * m) + beta * h; - final double value1 = timeSeries.getValue(i); - final double value2 = timeSeries.getValue(i+1); + final double currentValue = timeSeries.getValue(i); + final double nextValue = timeSeries.getValue(i+1); - double evalNext = volScaling * (Math.log((value2)/(value1))); + double evalNext = volScaling * (Math.log((nextValue)/(currentValue))); if(Double.isInfinite(evalNext) || Double.isNaN(evalNext)) { evalNext = 0; } - final double mNext = -mu - theta * m + evalNext - phi * eval; + final double mNext = -mu - theta * m + evalNext - phi * evaluation; // We need to take abs here, which corresponds to the assumption that -x is lognormal, given that we encounter a negative values. - logLikelihood += - Math.log(h) - 2 * Math.log((Math.abs(value2))/volScaling) - mNext* mNext / h; + logLikelihood += - Math.log(h) - 2 * Math.log((Math.abs(nextValue))/volScaling) - mNext* mNext / h; - evalPrev = eval; - eval = evalNext; + evaluationPrev = evaluation; + evaluation = evalNext; } logLikelihood += - Math.log(2 * Math.PI) * (length-1); logLikelihood *= 0.5;