/// <summary> /// /// </summary> /// <param name="timeGrid">Time discretisation used.</param> /// <param name="factors">Number of factors in the model.</param> /// <param name="weights">Precomputed swaption weights.</param> /// <param name="correlation">A homogeneous forward correlation matrix.</param> public InterestRateVolatilities(PedersenTimeGrid timeGrid, int factors, SwaptionWeights weights, DenseMatrix correlation) { _volFixed = false; _timeGrid = timeGrid; _factors = factors; _weights = weights; _correlation = correlation; _volatility = new Matrix[_timeGrid.MaxExpiry]; for (int i = 0; i < _timeGrid.MaxExpiry; i++) { _volatility[i] = new Matrix(_timeGrid.MaxTenor, _factors); } _storedImpliedVol = new double[_timeGrid.MaxExpiry][]; _storedImpliedVolSq = new double[_timeGrid.MaxExpiry][]; _storedImpliedVolTerm = new double[_timeGrid.MaxExpiry][][]; for (int i = 0; i < _timeGrid.MaxExpiry; i++) { _storedImpliedVol[i] = new double[_timeGrid.MaxTenor - i]; _storedImpliedVolSq[i] = new double[_timeGrid.MaxTenor - i]; _storedImpliedVolTerm[i] = new double[_timeGrid.MaxTenor - i][]; for (int j = 0; j < _timeGrid.MaxTenor - i; j++) { _storedImpliedVolTerm[i][j] = new double[i + 1]; } } }
///<summary> ///</summary> ///<param name="timeGrid"></param> ///<param name="capletData"></param> ///<param name="swaptionData"></param> public CalibrationTargets(PedersenTimeGrid timeGrid, double[,] capletData, double[,] swaptionData) { AdjustedForShift = false; var capletExpiry = new List <int>(); var capletImpliedVol = new List <double>(); var swaptionExpiry = new List <int>(); var swaptionTenor = new List <int>(); var swaptionImpliedVol = new List <double>(); int tempExpiry; for (int i = capletData.GetLowerBound(0); i <= capletData.GetUpperBound(0); i++) { try { tempExpiry = int.Parse(capletData[i, 0].ToString(CultureInfo.InvariantCulture)); if (tempExpiry <= timeGrid.MaxExpiry && tempExpiry > 0) { capletExpiry.Add(tempExpiry); capletImpliedVol.Add(capletData[i, 1]); } } catch { } } for (int i = swaptionData.GetLowerBound(0); i <= swaptionData.GetUpperBound(0); i++) { try { tempExpiry = int.Parse(swaptionData[i, 0].ToString(CultureInfo.InvariantCulture)); var tempTenor = int.Parse(swaptionData[i, 1].ToString(CultureInfo.InvariantCulture)); if (tempExpiry > 0 && tempTenor > 0 && tempExpiry <= timeGrid.MaxExpiry && tempExpiry + tempTenor - 1 <= timeGrid.MaxTenor) { swaptionExpiry.Add(tempExpiry); swaptionTenor.Add(tempTenor); swaptionImpliedVol.Add(swaptionData[i, 2]); } } catch { } } CapletExpiry = capletExpiry.ToArray(); CapletImpliedVol = capletImpliedVol.ToArray(); SwaptionExpiry = swaptionExpiry.ToArray(); SwaptionTenor = swaptionTenor.ToArray(); SwaptionImpliedVol = swaptionImpliedVol.ToArray(); CapletCount = CapletImpliedVol.GetLength(0); SwaptionCount = SwaptionImpliedVol.GetLength(0); }
/// <summary> /// Constructor /// </summary> /// <param name="volatilities">Existing volatilities</param> /// <param name="timeGrid">Time discretisation</param> /// <param name="swaptionWeights"></param> /// <param name="targets"></param> /// <param name="parameters"></param> /// <param name="factors"></param> public CascadeAlgorithm(InterestRateVolatilities volatilities, PedersenTimeGrid timeGrid, SwaptionWeights swaptionWeights, CalibrationTargets targets, CascadeParameters parameters, int factors) { _targets = targets; _timeGrid = timeGrid; _volatilities = volatilities; _parameters = parameters; _swaptionWeights = swaptionWeights; _factors = factors; _scales = new double[_timeGrid.MaxExpiry][]; _isScaled = new bool[_timeGrid.MaxExpiry][]; for (int i = 0; i < _timeGrid.MaxExpiry; i++) { _scales[i] = new double[_timeGrid.MaxTenor - i]; _isScaled[i] = new bool[_timeGrid.MaxTenor - i]; } }
/// <summary> /// Constructor /// </summary> /// <param name="targets">Calibration targets containing swaption and caplet data</param> /// <param name="timeGrid">Time discretisation</param> /// <param name="volatilities">Volatility to be calibrated</param> /// <param name="parameters">Calibration parameter settings</param> public CalibrationObjective(CalibrationTargets targets, PedersenTimeGrid timeGrid, InterestRateVolatilities volatilities, CalibrationSettings parameters) { Finished = false; _gradPhase = false; _iterationCounter = 0; _taskCounter = new TaskCounter(); //_currentInput = new DenseVector(0); _targets = targets; _timeGrid = timeGrid; _volatilities = volatilities; _parameters = parameters; _hFactor = 1.0 / (_timeGrid.ExpiryCount * (_timeGrid.TenorCount - 1)); _vFactor = 1.0 / ((_timeGrid.ExpiryCount - 1) * _timeGrid.TenorCount); _sFactor = 1.0 / _targets.SwaptionCount; _cFactor = 1.0 / _targets.CapletCount; }
/// <summary> /// Main calibration method. /// </summary> /// <param name="timeGrid">Time discretisation</param> /// <param name="discount">Quarterly discount factors</param> /// <param name="shift">Quarterly shift values</param> /// <param name="correlation">Correlation matrix, corresponding the tenor time discretisation</param> /// <param name="targets">Caplet and swaption implied vols</param> /// <param name="parameters">Calibration settings</param> /// <param name="factors">Factors used</param> /// <param name="useCascade">Whether to apply cascade algorithm post-calibration</param> /// <param name="output"></param> /// <returns></returns> public static InterestRateVolatilities Calibrate(PedersenTimeGrid timeGrid, QuarterlyDiscounts discount, QuarterlyShifts shift, DenseMatrix correlation, CalibrationTargets targets, CalibrationSettings parameters, int factors, bool useCascade, ref string output) { #region Initialisations targets.AdjustImpliedVolsForShift(discount, shift); var swaptionWeights = new SwaptionWeights(timeGrid.MaxExpiry, timeGrid.MaxTenor); swaptionWeights.Populate(discount, shift); var volatilities = new InterestRateVolatilities(timeGrid, factors, swaptionWeights, correlation); var objective = new CalibrationObjective(targets, timeGrid, volatilities, parameters); Func <Vector <double>, double> f = objective.ObjFun; Func <Vector <double>, Vector <double> > g = objective.ObjGrad; var initialGuess = new DenseVector(timeGrid.ExpiryCount * timeGrid.TenorCount); double guessValue = targets.AverageImpliedVol(); if (guessValue == 0) { throw new Exception("The selected time range does not include any calibration targets."); } if (parameters.ExponentialForm) { for (var i = 0; i < initialGuess.Count; i++) { initialGuess[i] = Math.Log(guessValue) / 20; } } else { for (var i = 0; i < initialGuess.Count; i++) { initialGuess[i] = guessValue; } } Trace.WriteLine(String.Format("Calibration Starting...")); objective.StartOtherThreads(); var solution = BfgsSolver.Solve(initialGuess, f, g); objective.Finished = true; Trace.WriteLine($"Value at extremum: {solution}"); objective.PopulateVol(solution); objective.AverageAbsVol(); #endregion #region Cascade if (useCascade) { Trace.WriteLine(String.Format("Applying Cascade Algorithm...")); var cascade = new CascadeAlgorithm(volatilities, timeGrid, swaptionWeights, targets, parameters.CascadeParam, factors); cascade.ApplyCascade(); } #endregion #region Output output = objective.AverageAbsVol(); return(objective.ReturnVol(solution)); #endregion }