/*
Copyright (C) 2011 Richard Gomes
This source code is release under the BSD License.
This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/
JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/
package org.jquantlib.termstructures;
import java.util.Arrays;
import org.jquantlib.QL;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.math.optimization.Constraint;
import org.jquantlib.math.optimization.CostFunction;
import org.jquantlib.math.optimization.EndCriteria;
import org.jquantlib.math.optimization.LevenbergMarquardt;
import org.jquantlib.math.optimization.NoConstraint;
import org.jquantlib.math.optimization.PositiveConstraint;
import org.jquantlib.termstructures.yieldcurves.PiecewiseYieldCurve;
import org.jquantlib.time.Date;
/**
* Localised-term-structure bootstrapper for most curve types.
*
* This algorithm enables a localised fitting for non-local
interpolation methods.
As in the similar class (IterativeBootstrap) the input term
structure is solved on a number of market instruments which
are passed as a vector of handles to BootstrapHelper
instances. Their maturities mark the boundaries of the
interpolated segments.
Unlike the IterativeBootstrap class, the solution for each
interpolated segment is derived using a local
approximation. This restricts the risk profile s.t. the risk
is localised. Therefore, we obtain a local IR risk profile
whilst using a smoother interpolation method. Particularly
good for the convex-monotone spline method.
*/
//FIXME: This class needs full code review
public class LocalBootstrap {
// typedef typename Curve::traits_type Traits;
// typedef typename Curve::interpolator_type Interpolator;
//
// private final fields
//
private Curve ts_;
private final /*Size*/ int localisation_;
private final boolean forcePositive_;
//
// private fields
//
private boolean validCurve_;
public LocalBootstrap() {
this(2, true);
}
public LocalBootstrap(/*Size*/ final int localisation) {
this(localisation, true);
}
public LocalBootstrap(/*Size*/ final int localisation, final boolean forcePositive) {
QL.validateExperimentalMode();
this.validCurve_ = false;
this.ts_ = null;
this.localisation_ = localisation;
this.forcePositive_ = forcePositive;
}
public void setup(final Curve ts) {
this.ts_ = ts;
/*Size*/ final int n = ts_.instruments().length;
QL.require(n >= ts.interpolator().requiredPoints(),
"not enough instruments: %d provided, %d required",
n, ts.interpolator().requiredPoints());
QL.require(n > localisation_,
"not enough instruments: %d provided, %d required.",
n, localisation_);
for (/*Size*/ int i=0; i(ts_)
}
// set initial guess only if the current curve cannot be used as guess
if (validCurve_)
QL.ensure(ts_.data().length == nInsts+1,
"dimension mismatch: expected %d, actual %d",
nInsts+1, ts_.data().length);
else {
final double[] data = new double[nInsts+1];
data[0] = ts_.traits().initialValue(ts_);
ts_.setData(data);
}
// calculate dates
{
final Date[] dates = new Date[nInsts+1];
dates[0] = ts_.traits().initialDate(ts_);
ts_.setDates(dates);
}
// calculate times
{
final double[] times = new double[nInsts+1];
times[0] = ts_.timeFromReference(ts_.dates()[0]);
ts_.setTimes(times);
}
for (/*Size*/ int i=0; i= localisation_) {
// startArray[localisation_-dataAdjust] = ts_.traits().guess(ts_, ts_.dates()[iInst]);
// } else {
// startArray[localisation_-dataAdjust] = ts_.data()[0];
// }
//
// final PenaltyFunction currentCost = new PenaltyFunction(
// ts_,
// initialDataPt,
// ts_.instruments().begin() + (iInst - localisation_+1),
// ts_.instruments().begin() + (iInst+1));
//
// final Problem toSolve = new Problem(currentCost, solverConstraint, startArray);
//
// final EndCriteria.Type endType = solver.minimize(toSolve, endCriteria);
//
// // check the end criteria
// QL.require(endType == EndCriteria.Type.StationaryFunctionAccuracy ||
// endType == EndCriteria.Type.StationaryFunctionValue,
// "Unable to strip yieldcurve to required accuracy " );
//
// ++iInst;
// } while ( iInst < nInsts );
//=========================================================================
validCurve_ = true;
}
//
// inner classes
//
private class PenaltyFunction extends CostFunction {
private final int initialIndex;
private final int rateHelpersStart;
private final int rateHelpersEnd;
private final int penaltylocalisation;
private PenaltyFunction(final int initialIndex, final int rateHelpersStart, final int rateHelpersEnd) {
this.initialIndex = initialIndex;
this.rateHelpersStart = rateHelpersStart;
this.rateHelpersEnd = rateHelpersEnd;
this.penaltylocalisation = rateHelpersEnd - rateHelpersStart;
}
@Override
public double value(final Array x) {
int i = initialIndex;
int guessIt = 0;
for (; guessIt < x.size(); ++guessIt, ++i) {
ts_.traits().updateGuess(ts_.data(), guessIt, i);
}
ts_.interpolation().update();
double penalty = 0.0;
int j = rateHelpersStart;
for (; j != rateHelpersEnd; ++j) {
penalty += Math.abs(ts_.instruments()[j].quoteError());
}
return penalty;
}
@Override
public Array values(final Array x) {
int guessIt = 0;
for (int i = initialIndex; guessIt < x.size(); ++guessIt, ++i) {
ts_.traits().updateGuess(ts_.data(), x.get(guessIt), i);
}
ts_.interpolation().update();
final Array penalties = new Array(penaltylocalisation);
int instIterator = rateHelpersStart;
for (int penIt = 0; instIterator != rateHelpersEnd; ++instIterator, ++penIt) {
penalties.set(penIt, Math.abs(ts_.instruments()[instIterator].quoteError()));
}
return penalties;
}
}
}
Ads help maintain this website.