/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.impl.credit.isda; import com.opengamma.strata.math.impl.util.Epsilon; /** * */ public class AnnuityForSpreadContPemiumApproxFunction extends AnnuityForSpreadFunction { private final int n; private final double[] knots; private final double[] rt; private final double lgd; private final double eta; /** * For a given quoted spread (aka 'flat' spread), this function returns the risky annuity * (aka risky PV01, RPV01 or risky duration). * This works by using the credit triangle approximation; that is, the premiums are assumed to be paid continuously. * * @param cds the analytic description of a CDS traded at a certain time * @param yieldCurve the calibrated yield curve */ public AnnuityForSpreadContPemiumApproxFunction(CdsAnalytic cds, IsdaCompliantYieldCurve yieldCurve) { this.knots = DoublesScheduleGenerator.truncateSetInclusive( cds.getEffectiveProtectionStart(), cds.getProtectionEnd(), yieldCurve.getKnotTimes()); this.n = this.knots.length; this.rt = new double[n]; for (int i = 0; i < n; i++) { this.rt[i] = yieldCurve.getRT(this.knots[i]); } this.lgd = cds.getLGD(); this.eta = cds.getCoupon(0).getYFRatio(); } @Override public Double apply(Double spread) { double lambda = eta * spread / lgd; return annuity(lambda); } private double annuity(double hazardRate) { double rt0 = rt[0]; double sum = 0; for (int i = 1; i < n; i++) { double rt1 = rt[i]; double dt = knots[i] - knots[i - 1]; double theta = rt1 - rt0 + hazardRate * dt; sum += dt * Math.exp(-rt0 - hazardRate * knots[i - 1]) * Epsilon.epsilon(-theta); rt0 = rt1; } return eta * sum; } }