/// <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]; } } }
private DenseMatrix SetXi(int exp, Vector x) { var cor = _economy.Correlation; var cov = new Matrix(_param.NumberOfTenors, _param.NumberOfTenors); for (int i = 0; i < _param.NumberOfTenors; i++) { for (int j = 0; j <= i; j++) { cov[i, j] = cor[i, j] * x[i] * x[j]; } } var eigenValueDecomposition = new EigenvalueDecomposition(cov); var baseVector = eigenValueDecomposition.RealEigenvalues.ToList(); var eval = baseVector.GetRange(_param.NumberOfTenors - _param.NumberOfFactors, _param.NumberOfTenors - 1 + _param.NumberOfFactors);//Select the sub-vector starting at the index i and with length y var baseMatrix = eigenValueDecomposition.EigenVectors; var eigenVectors = baseMatrix.GetMatrix(0, baseMatrix.RowCount - 1, _param.NumberOfTenors - _param.NumberOfFactors, _param.NumberOfTenors - 1); var xiSection = new DenseMatrix(_param.UnderlyingTenor, _param.NumberOfFactors); for (int j = 0; j < _param.NumberOfFactors; j++) { eval[j] = Math.Sqrt(eval[j]); for (int i = 0; i < _param.NumberOfTenors; i++) { var temp = eval[j] * eigenVectors[i, j]; for (int n = _param.Tenor[i]; n < Math.Min(_param.Tenor[i + 1], _param.UnderlyingTenor - _param.Expiry[exp]); n++) { xiSection[n, j] = temp; } } } return(xiSection); }
/// <summary> /// Computes the implied volatility of swaption with given expiry and tenor, or a caplet with given expiry, /// with the volatility at one particular expiry time bucket replaced with temporary values. /// A caplet implied volatility is equivalent to that of a swaption with the tenor length of 1. /// Saves computation time when checking the effect of a simple perturbation. /// </summary> /// <param name="expiry"></param> /// <param name="tenor"></param> /// <param name="newRow">Indicating the expiry time bucket to be replaced.</param> /// <param name="replacedRow">New interest rate volatility values for the expiry time bucket.</param> /// <returns></returns> public double FindImpliedVolatility(int expiry, int tenor, Matrix newRow, int replacedRow) { int exp = expiry - 1; int ten = tenor - 1; double result; if (exp >= _timeGrid.ExpiryGrid[replacedRow]) { result = _storedImpliedVolSq[exp][ten]; for (int i = _timeGrid.ExpiryGrid[replacedRow]; i < Math.Min(_timeGrid.ExpiryGrid[replacedRow + 1], expiry); i++) { var tempVector = new DenseVector(_factors); for (int j = 0; j <= ten; j++) { tempVector = tempVector + _weights.Get(expiry, tenor, j + 1) * newRow.RowD(j + exp - i); } double tempSum = tempVector * tempVector; result += tempSum - _storedImpliedVolTerm[exp][ten][i]; } result = Math.Sqrt(result / expiry); } else { result = _storedImpliedVol[exp][ten]; } return(result); }
/// <summary> /// Computes the volatilities of a particular expiry time bucket. /// </summary> /// <param name="row"></param> /// <param name="inputVol"></param> /// <returns></returns> public Matrix SingleRowOfVolatilities(int row, Vector inputVol) { //create covariance var covariance = new Matrix(_timeGrid.TenorCount, _timeGrid.TenorCount); for (int i = 0; i < _timeGrid.TenorCount; i++) { for (int j = 0; j <= i; j++) { covariance[i, j] = _correlation[i, j] * inputVol[i] * inputVol[j]; } } //principal component analysis var eigenValueDecomposition = new EigenvalueDecomposition(covariance); var baseVector = eigenValueDecomposition.RealEigenvalues.ToList(); var eval = baseVector.GetRange(_timeGrid.TenorCount - 1 - _factors, _factors);//Select the sub-vector starting at the index i and with length y var baseMatrix = eigenValueDecomposition.EigenVectors; var eigenVectors = baseMatrix.GetMatrix(0, baseMatrix.RowCount - 1, _timeGrid.TenorCount - _factors, _timeGrid.TenorCount - 1); var resultVol = new Matrix(_timeGrid.MaxTenor, _factors); for (int j = 0; j < _factors; j++) { eval[j] = Math.Sqrt(eval[j]); for (int i = 0; i < _timeGrid.TenorCount; i++) { var temp = eval[j] * eigenVectors[i, j]; for (int n = _timeGrid.TenorGrid[i]; n < Math.Min(_timeGrid.TenorGrid[i + 1], _timeGrid.MaxTenor - _timeGrid.ExpiryGrid[row]); n++) { resultVol[n, j] = temp; } } } return(resultVol); }
private double SmoothV(Matrix <double> xMatrix) { double total = 0; for (int i = 0; i < _param.NumberOfExpiries - 1; i++) { for (int j = 0; j < _param.NumberOfTenors; j++) { double temp = Math.Log(xMatrix[i, j] / xMatrix[i + 1, j]); total += temp * temp; } } total = total * _vFactor; return(total); }
private void PopulateXi(Matrix <double> xMatrix) { for (int i = 0; i < _param.NumberOfExpiries; i++) { var gm = SetXi(i, (DenseVector)xMatrix.Row(i)); for (int j = _param.Expiry[i]; j < _param.Expiry[i + 1]; j++) { for (int k = 0; k < _param.UnderlyingTenor - j; k++) { for (int l = 0; l < _param.NumberOfFactors; l++) { _economy.Xi[j][k, l] = gm[k, l]; } } //economy.Xi[j] = (GeneralMatrix)gm.Clone(); } } }
/// <summary> /// Computes the multi-factored volatilities given a particular input volatility grid, using principal component analysis. /// (See Pedersen, M. B. (1998) Calibrating Libor market models. Working paper, Financial Research Department, SimCorp.) /// </summary> /// <param name="inputVolMat"></param> public void Populate(Matrix inputVolMat) { if (!_volFixed) { for (int i = 0; i < _timeGrid.ExpiryCount; i++) { var currentRow = SingleRowOfVolatilities(i, inputVolMat.RowD(i)); for (int j = _timeGrid.ExpiryGrid[i]; j < _timeGrid.ExpiryGrid[i + 1]; j++) { for (int k = 0; k < _timeGrid.MaxTenor - j; k++) { for (int l = 0; l < _factors; l++) { _volatility[j][k, l] = currentRow[k, l]; } } } } } else { throw new Exception("Cannot alter finalised volatility."); } }