// to constrained <- from unconstrained public AbcdCalibration(List <double> t, List <double> blackVols, double aGuess = -0.06, double bGuess = 0.17, double cGuess = 0.54, double dGuess = 0.17, bool aIsFixed = false, bool bIsFixed = false, bool cIsFixed = false, bool dIsFixed = false, bool vegaWeighted = false, EndCriteria endCriteria = null, OptimizationMethod method = null) { aIsFixed_ = aIsFixed; bIsFixed_ = bIsFixed; cIsFixed_ = cIsFixed; dIsFixed_ = dIsFixed; a_ = aGuess; b_ = bGuess; c_ = cGuess; d_ = dGuess; abcdEndCriteria_ = QLCore.EndCriteria.Type.None; endCriteria_ = endCriteria; optMethod_ = method; weights_ = new InitializedList <double>(blackVols.Count, 1.0 / blackVols.Count); vegaWeighted_ = vegaWeighted; times_ = t; blackVols_ = blackVols; AbcdMathFunction.validate(aGuess, bGuess, cGuess, dGuess); Utils.QL_REQUIRE(blackVols.Count == t.Count, () => "mismatch between number of times (" + t.Count + ") and blackVols (" + blackVols.Count + ")"); // if no optimization method or endCriteria is provided, we provide one if (optMethod_ == null) { double epsfcn = 1.0e-8; double xtol = 1.0e-8; double gtol = 1.0e-8; bool useCostFunctionsJacobian = false; optMethod_ = new LevenbergMarquardt(epsfcn, xtol, gtol, useCostFunctionsJacobian); } if (endCriteria_ == null) { int maxIterations = 10000; int maxStationaryStateIterations = 1000; double rootEpsilon = 1.0e-8; double functionEpsilon = 0.3e-4; // Why 0.3e-4 ? double gradientNormEpsilon = 0.3e-4; // Why 0.3e-4 ? endCriteria_ = new EndCriteria(maxIterations, maxStationaryStateIterations, rootEpsilon, functionEpsilon, gradientNormEpsilon); } }
public void calculate() { validCurve_ = false; int nInsts = ts_.instruments_.Count, i; // ensure rate helpers are sorted ts_.instruments_.Sort((x, y) => x.latestDate().CompareTo(y.latestDate())); // check that there is no instruments with the same maturity for (i = 1; i < nInsts; ++i) { Date m1 = ts_.instruments_[i - 1].latestDate(), m2 = ts_.instruments_[i].latestDate(); Utils.QL_REQUIRE(m1 != m2, () => "two instruments have the same maturity (" + m1 + ")"); } // check that there is no instruments with invalid quote Utils.QL_REQUIRE((i = ts_.instruments_.FindIndex(x => !x.quoteIsValid())) == -1, () => "instrument " + i + " (maturity: " + ts_.instruments_[i].latestDate() + ") has an invalid quote"); // setup instruments and register with them ts_.instruments_.ForEach((x, j) => ts_.setTermStructure(j)); // set initial guess only if the current curve cannot be used as guess if (validCurve_) { Utils.QL_REQUIRE(ts_.data_.Count == nInsts + 1, () => "dimension mismatch: expected " + nInsts + 1 + ", actual " + ts_.data_.Count); } else { ts_.data_ = new InitializedList <double>(nInsts + 1); ts_.data_[0] = ts_.initialValue(); } // calculate dates and times ts_.dates_ = new InitializedList <Date>(nInsts + 1); ts_.times_ = new InitializedList <double>(nInsts + 1); ts_.dates_[0] = ts_.initialDate(); ts_.times_[0] = ts_.timeFromReference(ts_.dates_[0]); for (i = 0; i < nInsts; ++i) { ts_.dates_[i + 1] = ts_.instruments_[i].latestDate(); ts_.times_[i + 1] = ts_.timeFromReference(ts_.dates_[i + 1]); if (!validCurve_) { ts_.data_[i + 1] = ts_.data_[i]; } } LevenbergMarquardt solver = new LevenbergMarquardt(ts_.accuracy_, ts_.accuracy_, ts_.accuracy_); EndCriteria endCriteria = new EndCriteria(100, 10, 0.00, ts_.accuracy_, 0.00); PositiveConstraint posConstraint = new PositiveConstraint(); NoConstraint noConstraint = new NoConstraint(); Constraint solverConstraint = forcePositive_ ? (Constraint)posConstraint : (Constraint)noConstraint; // now start the bootstrapping. int iInst = localisation_ - 1; int dataAdjust = (ts_.interpolator_ as ConvexMonotone).dataSizeAdjustment; do { int initialDataPt = iInst + 1 - localisation_ + dataAdjust; Vector startArray = new Vector(localisation_ + 1 - dataAdjust); for (int j = 0; j < startArray.size() - 1; ++j) { startArray[j] = ts_.data_[initialDataPt + j]; } // here we are extending the interpolation a point at a // time... but the local interpolator can make an // approximation for the final localisation period. // e.g. if the localisation is 2, then the first section // of the curve will be solved using the first 2 // instruments... with the local interpolator making // suitable boundary conditions. ts_.interpolation_ = (ts_.interpolator_ as ConvexMonotone).localInterpolate(ts_.times_, iInst + 2, ts_.data_, localisation_, ts_.interpolation_ as ConvexMonotoneInterpolation, nInsts + 1); if (iInst >= localisation_) { startArray[localisation_ - dataAdjust] = ts_.guess(iInst, ts_, false, 0); } else { startArray[localisation_ - dataAdjust] = ts_.data_[0]; } var currentCost = new PenaltyFunction <T, U>(ts_, initialDataPt, ts_.instruments_, iInst - localisation_ + 1, iInst + 1); Problem toSolve = new Problem(currentCost, solverConstraint, startArray); EndCriteria.Type endType = solver.minimize(toSolve, endCriteria); // check the end criteria Utils.QL_REQUIRE(endType == EndCriteria.Type.StationaryFunctionAccuracy || endType == EndCriteria.Type.StationaryFunctionValue, () => "Unable to strip yieldcurve to required accuracy "); ++iInst; }while (iInst < nInsts); validCurve_ = true; }