///<summary> ///</summary> ///<param name="discount"></param> ///<param name="shift"></param> public void Populate(QuarterlyDiscounts discount, QuarterlyShifts shift) { var forward = new double[_maxTenor + 1]; var accumForward = new double[_maxTenor + 1]; var accumForwardTimesRate = new double[_maxTenor + 1]; var accumForwardTimesShiftedRate = new double[_maxTenor + 1]; accumForward[0] = 0; accumForwardTimesRate[0] = 0; accumForwardTimesShiftedRate[0] = 0; var w = new double[_maxTenor]; var h = new double[_maxTenor]; for (int i = 0; i < _maxExpiry; i++) { for (int j = 0; j < _maxTenor - i; j++) { //See "Engineering BGM" page 34 for explicit formula. Function definitions can be found in chapter 4. forward[j + 1] = RateAnalytics.ForwardContract(i + 1, i + j + 2, discount); accumForward[j + 1] = accumForward[j] + forward[j + 1]; accumForwardTimesRate[j + 1] = accumForwardTimesRate[j] + forward[j + 1] * RateAnalytics.CashForwardRate(i + j + 1, discount); accumForwardTimesShiftedRate[j + 1] = accumForwardTimesShiftedRate[j] + forward[j + 1] * RateAnalytics.ShiftedCashForwardRate(i + j + 1, discount, shift); h[j] = 0.25 * RateAnalytics.ShiftedCashForwardRate(i + j + 1, discount, shift) / (1 + 0.25 * RateAnalytics.CashForwardRate(i + j + 1, discount)); for (int k = 0; k < j + 1; k++) { w[k] = forward[k + 1] * RateAnalytics.ShiftedCashForwardRate(i + k + 1, discount, shift) / accumForwardTimesShiftedRate[j + 1]; _weights[i][j][k] = w[k] - h[k] * ((accumForwardTimesRate[j + 1] - accumForwardTimesRate[k]) / accumForwardTimesShiftedRate[j + 1] - (1 - accumForward[k] / accumForward[j + 1]) * accumForwardTimesRate[j + 1] / accumForwardTimesShiftedRate[j + 1]); } } } }
///<summary> ///</summary> ///<param name="discount"></param> ///<param name="shift"></param> public void AdjustImpliedVolsForShift(QuarterlyDiscounts discount, QuarterlyShifts shift) { if (!AdjustedForShift) { AdjustedForShift = true; for (int i = 0; i < CapletCount; i++) { CapletImpliedVol[i] = AdjustCapletImpliedVol(CapletExpiry[i], CapletImpliedVol[i], discount, shift); } for (int i = 0; i < SwaptionCount; i++) { SwaptionImpliedVol[i] = AdjustSwaptionImpliedVol(SwaptionExpiry[i], SwaptionTenor[i], SwaptionImpliedVol[i], discount, shift); } } }
/// <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 }
private static double AdjustSwaptionImpliedVol(int expiry, int tenor, double volatility, QuarterlyDiscounts discount, QuarterlyShifts shift) { double strike = RateAnalytics.SwapRate(expiry, tenor, discount); double swapShift = RateAnalytics.SwapShift(expiry, tenor, discount, shift); double swaptionPrice = BlackModel.GetValue(expiry / 4.0, strike, strike, volatility, PayStyle.Call); double result = BlackModel.GetImpliedVolatility(expiry / 4.0, strike + swapShift, strike + swapShift, swaptionPrice, volatility, PayStyle.Call); return(result); }
private static double AdjustCapletImpliedVol(int expiry, double volatility, QuarterlyDiscounts discount, QuarterlyShifts shift) { double strike = RateAnalytics.CashForwardRate(expiry, discount); double capletPrice = BlackModel.GetValue(expiry / 4.0, strike, strike, volatility, PayStyle.Call); double result = BlackModel.GetImpliedVolatility(expiry / 4.0, strike + shift.Get(expiry), strike + shift.Get(expiry), capletPrice, volatility, PayStyle.Call); return(result); }