Class SaddlePointLossModel<TCopula, TInitTraits>
- Namespace
- NanoQL.Experimental
- Assembly
- NanoQL.dll
The saddle-point portfolio credit default loss model: the saddle-point expansion's integrations of several default risk metrics, the dependence dealt with through a latent model that makes the integrals conditional on its factor, the latent variables integrated indirectly.
[Experimental("NQL0001")]
public class SaddlePointLossModel<TCopula, TInitTraits> : DefaultLossModel, IDefaultLossModel where TCopula : struct, ICopulaPolicy<TCopula, TInitTraits> where TInitTraits : struct
Type Parameters
TCopulaThe copula policy.
TInitTraitsThe policy's initialization parameters.
- Inheritance
-
SaddlePointLossModel<TCopula, TInitTraits>
- Implements
- Derived
-
SaddlePointTailLossModel<TCopula, TInitTraits>
- Inherited Members
Remarks
See R. Martin, K. Thompson and C. Browne, "Taking to the saddle", Risk, June 2001, p. 91; R. Martin, "The saddlepoint method and portfolio optionalities", Risk, December 2006; R. Martin, K. Thompson and C. Browne, "VAR: who contributes and how much?", Risk, August 2001; R. J. Martin, "Shortfall: Who contributes and how much?", Credit Suisse, 3 January 2007; J. Annaert, C. Garcia Joao Batista, J. Lamoot and G. Lanine, "Don't Fall from the Saddle: the Importance of Higher Moments of Credit Loss Distributions", Gent University, February 2006; A. Antonov, S. Mechkov and T. Misirpashaev, "Analytical techniques for synthetic CDOs and credit default risk measures", NumeriX, 23 May 2005; X. Huang, C. W. Oosterlee and M. Mesters, "Computation of VaR and VaR contribution in the Vasicek portfolio credit loss model: a comparative study", Journal of Credit Risk 3(3), Fall 2007, and "Higher-order saddlepoint approximations in the Vasicek portfolio credit loss model", Journal of Computational Finance 11(1), Fall 2007. A high order expansion is used, more expensive; see Antonov et al. for the terms retained. A. Owen, A. McLeod and K. Thompson's hybrid saddlepoint method fixes the error at low loss levels (Risk, August 2009), not implemented here; for the general theory, R. W. Butler, "Saddlepoint approximations with applications", Cambridge, 2007. To be done, as in QuantLib: some portfolios' instabilities in the high order terms; calls avoiding the copula inversions; the saddle point search's convergence in extreme cases (very high factors, factors not ordered from high to low). Random recoveries would have to be passed to the conditional methods as the probabilities are.
Kept, QuantLib's method: the expected tranche loss is the tranche of the conditional expected loss, a large-pool reading, not a saddle-point expansion; at correlation 0 on 100 names its four tranches read 292.78, 0, 0, 0 where the recursive model on the same latent model reads 245.40, 46.48, 0.89, 0.0022. SaddlePointTailLossModel<TCopula, TInitTraits> reads it from the model's own tail instead.
The tail's degenerate nodes and domain (Divergences/SaddlePointLossModelTests.cs). QuantLib's saddle
search brackets on the name of the largest loss, taking the logarithm of a ratio of its conditional probability p
and 1 − p, so a node where that name is at 0 or 1 throws ("invalid range"): at the evaluation date every probability
is 0, and on ten names every correlation from 0.9 throws. Here the bracket's name is the largest among those
strictly between 0 and 1, the certain ones carried by the cumulants (a name at 1 a linear term, one at 0 nothing),
and a node where every name is at 0 or 1 reads its exact conditional loss: its tail 1 or 0, its density 0, its split
and shortfall exact. Where QuantLib's throws (100 names, hazard 0.03, recovery 0.4), the tail at 10% of the pool
reads the exact (recursive) model's within 1.2% through correlation 0.9 and within 5% at 0.95, below it (5.0% at
three months), the expansion's own accuracy on near-comonotonic pools, where QuantLib's runs reading it within 1% at
0.7 and 0.75. Refused, naming the saddle-point expansion: a tail outside [0, 1] (beyond the quadrature's rounding,
1e-12), and a largest relative loss at or below the bracket's 1e-5, whose logarithm QuantLib takes of a negative
number. The factor nodes' tails are QuantLib's, inside [0, 1] or not: at low losses single nodes read up to 6.31 or
slightly below 0 where the integrated tail and the percentile are right (on 100 names, hazard 0.03, the percentile
at 50%, 90% and 99% within the exact distribution's loss unit at correlations 0.1 to 0.5 and 30 days to ten years).
Kept, the method's domain: on small pools the expansion misreads the tail inside [0, 1], on ten names at
correlation 0.3 P(L ≥ 1%) 0.983 for an exact 0.0223 at a month and 0.754 for 0.603 at five years, where 100 names
read 0.4389 for 0.4387 at a year; outside it (26.78 a day out at correlation 0.548, 2.61 at a week on ten names) the
refusal.
The saddle search. QuantLib's brackets the point on the name of the largest loss and, below or above the
bracket's losses, returns the bracket's end instead of solving, so on pools whose largest loss is a name unlikely to
default it reads up to 40 times the exact tail (0.978 for 0.198 at 1% of 100 names a year out at correlation 0.7,
0.2008 for 0.0049 at 10% at 0.9); here the bracket widens until it holds the level and the point is solved,
QuantLib's search wherever its bracket holds it. The cumulants keep QuantLib's arithmetic but for names at 0, out of
the sums, names at 1, their linear terms, and where QuantLib's form overflows the logistic form, so a widened point
reads no 0·∞; the split's contributions take the same treatment, where QuantLib's form reads ∞/∞. Above the largest
loss a factor node reaches, its names' losses given default but those certain not to default, no point exists: the
tail reads 0 there by QuantLib's own return above 1 less the average recovery, and the density and the conditional
shortfall read 0 too, where at the widened end QuantLib's expressions read 0/0, so the shortfall of a tranche
detaching above the pool's largest loss was NaN (QuantLib's TO DO list: "Failing when the tranche upper loss limit
goes over the max attainable loss"). Divergences/SaddlePointLossModelTests.cs.
ProbOverLoss(Date, double) reads 0 above the whole tranche, where QuantLib's compares the fraction with the detachment amount; ExpectedShortfall(Date, double) is the tranche loss's, at most the tranche's remaining notional, where QuantLib's integrates the whole portfolio's tail above the tranche's percentile and caps it at the tranche notional times the remaining ratio (9 for a 300 tranche; "ESF <- tranched????!!" in its TO DO list). Bound to a basket with realized defaults, the model prices its live names over the restated tranche.
Constructors
SaddlePointLossModel(ConstantLossLatentModel<TCopula, TInitTraits>)
Initializes a new instance of the SaddlePointLossModel<TCopula, TInitTraits> class.
public SaddlePointLossModel(ConstantLossLatentModel<TCopula, TInitTraits> m)
Parameters
mConstantLossLatentModel<TCopula, TInitTraits>The constant-loss latent model.
Exceptions
- ArgumentNullException
mis null.
Methods
ConditionalExpectedLoss(double[], ReadOnlySpan<double>)
The live portfolio's expected loss conditional on the factor.
protected double ConditionalExpectedLoss(double[] invUncondProbs, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional expected loss, an amount.
ConditionalExpectedTrancheLoss(double[], ReadOnlySpan<double>)
The live tranche's expected loss conditional on the factor: the tranche of the conditional expected loss, QuantLib's large-pool reading.
protected double ConditionalExpectedTrancheLoss(double[] invUncondProbs, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional expected tranche loss, an amount.
CumGen0234DerivCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function and its second to fourth derivatives conditional on the factor, together, as most methods expand on them.
protected (double Deriv0, double Deriv2, double Deriv3, double Deriv4) CumGen0234DerivCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- (double Deriv0, double Deriv2, double Deriv3, double Deriv4)
The cumulant generating function and its second, third and fourth derivatives.
CumGen02DerivCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function and its second derivative conditional on the factor.
protected (double Deriv0, double Deriv2) CumGen02DerivCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
CumGen1stDerivative(Date, double)
The cumulant generating function's first derivative by a date, unconditional.
protected double CumGen1stDerivative(Date date, double s)
Parameters
Returns
- double
The derivative.
Exceptions
- NanoQLException
The model isn't bound to a basket.
CumGen1stDerivativeCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function's first derivative conditional on the factor: at 0 the portfolio's expected loss, at infinity its maximum loss, fractions of the live notional.
protected double CumGen1stDerivativeCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The derivative.
CumGen2ndDerivative(Date, double)
The cumulant generating function's second derivative by a date, unconditional.
protected double CumGen2ndDerivative(Date date, double s)
Parameters
Returns
- double
The derivative.
Exceptions
- NanoQLException
The model isn't bound to a basket.
CumGen2ndDerivativeCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function's second derivative conditional on the factor.
protected double CumGen2ndDerivativeCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The derivative.
CumGen3rdDerivative(Date, double)
The cumulant generating function's third derivative by a date, unconditional.
protected double CumGen3rdDerivative(Date date, double s)
Parameters
Returns
- double
The derivative.
Exceptions
- NanoQLException
The model isn't bound to a basket.
CumGen3rdDerivativeCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function's third derivative conditional on the factor.
protected double CumGen3rdDerivativeCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The derivative.
CumGen4thDerivative(Date, double)
The cumulant generating function's fourth derivative by a date, unconditional.
protected double CumGen4thDerivative(Date date, double s)
Parameters
Returns
- double
The derivative.
Exceptions
- NanoQLException
The model isn't bound to a basket.
CumGen4thDerivativeCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function's fourth derivative conditional on the factor.
protected double CumGen4thDerivativeCond(double[] invUncondProbs, double saddle, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
saddledoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The derivative.
CumulantGenerating(Date, double)
The cumulant generating function by a date, the conditional one weighted by the factor's density; unused by the statistics, which integrate indirectly.
protected double CumulantGenerating(Date date, double s)
Parameters
Returns
- double
The cumulant generating function.
Exceptions
- NanoQLException
The model isn't bound to a basket.
CumulantGeneratingCond(double[], double, ReadOnlySpan<double>)
The cumulant generating function conditional on the factor (the zero-th order expansion term): K = Σⱼ ln(1 − pⱼ + pⱼ e^(Nⱼ·LGDⱼ·s)).
protected double CumulantGeneratingCond(double[] invUncondProbs, double lossFraction, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossFractiondoubleThe saddle point.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The cumulant generating function.
ExpectedPortfolioLoss(Date)
The whole (untranched) live portfolio's expected loss by a date: its conditional expected loss integrated over the factor.
protected double ExpectedPortfolioLoss(Date d)
Parameters
dDateThe date.
Returns
- double
The expected loss, an amount.
Exceptions
- NanoQLException
The model isn't bound to a basket.
ExpectedShortfall(Date, double)
The expected loss beyond a percentile's loss by a date, of the whole portfolio above it, at most the tranche's remaining notional.
public override double ExpectedShortfall(Date d, double percentile)
Parameters
Returns
- double
The expected shortfall, an amount.
Exceptions
- ArgumentOutOfRangeException
The percentile lies outside [0, 1].
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).
ExpectedShortfallFullPortfolioCond(double[], double, ReadOnlySpan<double>)
The whole portfolio's expected loss above an amount conditional on the factor, Martin's 2006 expression (see also S. A. Broda and M. S. Paolella, "Saddlepoint approximation of expected shortfall for transformed means", Amsterdam School of Economics); exact at a node where every name's probability is 0 or 1.
protected double ExpectedShortfallFullPortfolioCond(double[] invUncondProbs, double lossPerc, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossPercdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional expected loss above the amount, 0 above the node's largest loss.
Exceptions
- NanoQLException
The expansion refuses the node.
ExpectedShortfallSplitCond(double[], double, ReadOnlySpan<double>)
The live names' expected shortfall contributions conditional on the factor at a loss, a Gaussian approximation of each; unused by the statistics.
protected double[] ExpectedShortfallSplitCond(double[] invUncondProbs, double lossPerc, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossPercdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double[]
The contributions.
ExpectedShortfallTrancheCond(double[], double, double, ReadOnlySpan<double>)
The tranche's expected shortfall conditional on the factor, from the whole portfolio's with a tranche correction; unused by the statistics. To be done, as in QuantLib: a general expression valid in every situation.
protected double ExpectedShortfallTrancheCond(double[] invUncondProbs, double lossPerc, double percentile, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossPercdoubleThe percentile's loss, an amount.
percentiledoubleThe percentile.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional shortfall.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the saddle point refuses the node.
ExpectedTrancheLoss(Date)
The expected tranche loss by a date, an amount.
public override double ExpectedTrancheLoss(Date d)
Parameters
dDateThe date.
Returns
- double
The loss.
Exceptions
- NanoQLException
The model doesn't implement it.
FindSaddle(double[], double, ReadOnlySpan<double>, double, int)
The saddle point conditional on the factor for a loss level, the date implicit in the probabilities (passed for performance, the same at every node of the integration). To be done, as in QuantLib: the convergence speed (see the references and The Oxford Handbook of Credit Derivatives, section 2.9), and a requirement that the level be below the portfolio's maximum loss.
protected double FindSaddle(double[] invUncondPs, double lossLevel, ReadOnlySpan<double> mktFactor, double accuracy = 0.001, int maxEvaluations = 50)
Parameters
invUncondPsdouble[]The inverse cumulatives of the names' default probabilities.
lossLeveldoubleThe loss level, a fraction of the whole live portfolio.
mktFactorReadOnlySpan<double>The factor's values.
accuracydoubleThe solver's accuracy.
maxEvaluationsintThe solver's maximum evaluations.
Returns
- double
The saddle point; at a level below or above the bracket's losses, the bracket's end.
Exceptions
- NanoQLException
Every name's conditional probability is 0 or 1, so there is no expansion; the largest relative loss of a name between them is at or below 1e-5; or the solver fails.
LossDistribution(Date)
The full loss distribution: each loss level's probability.
public override ImmutableSortedDictionary<double, double> LossDistribution(Date d)
Parameters
dDateThe date.
Returns
- ImmutableSortedDictionary<double, double>
The distribution.
Exceptions
- NanoQLException
The model doesn't implement it.
Percentile(Date, double)
The loss amount by a date at which the probability of losing that amount or less is the percentile: a tranche loss.
public override double Percentile(Date d, double percentile)
Parameters
Returns
- double
The loss, an amount; 0 on or before the evaluation date.
Exceptions
- ArgumentOutOfRangeException
The percentile lies outside [0, 1] ("Incorrect percentile value.").
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).
ProbDensity(Date, double)
The probability density of the whole (untranched) live portfolio's loss at an amount by a date.
public double ProbDensity(Date d, double loss)
Parameters
Returns
- double
The density.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).
ProbDensityCond(double[], double, ReadOnlySpan<double>)
The probability density conditional on the factor of the whole (untranched) live portfolio's loss at an amount, from the expected shortfall's integrals (R. Martin, "The saddle point method and portfolio optionalities", Risk, December 2006, p. 93); 0 at a node where every name's probability is 0 or 1.
protected double ProbDensityCond(double[] invUncondPs, double loss, ReadOnlySpan<double> mktFactor)
Parameters
invUncondPsdouble[]The inverse cumulatives of the names' default probabilities.
lossdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional density, 0 above the node's largest loss.
Exceptions
- NanoQLException
The saddle point refuses the node.
ProbOverLoss(Date, double)
The probability of losing a fraction of the live tranche or more by a date.
public override double ProbOverLoss(Date d, double trancheLossFract)
Parameters
Returns
- double
The probability; 0 above the whole tranche.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).
ProbOverLossCond(double[], double, ReadOnlySpan<double>)
The probability conditional on the factor of losing a fraction of the live tranche or more.
protected double ProbOverLossCond(double[] invUncondPs, double trancheLossFract, ReadOnlySpan<double> mktFactor)
Parameters
invUncondPsdouble[]The inverse cumulatives of the names' default probabilities.
trancheLossFractdoubleThe fraction of the tranche's notional, in [0, 1].
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional probability.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the saddle point refuses the node.
ProbOverLossPortfCond(double[], double, ReadOnlySpan<double>)
The probability conditional on the factor of the whole (untranched) live portfolio losing an amount or more: the first order expansion's integral with the high order corrections, equation 8 of R. Martin, K. Thompson and C. Browne, "Taking to the Saddle", Risk, June 2001, p. 91; exact at a node where every name's probability is 0 or 1.
protected double ProbOverLossPortfCond(double[] invUncondProbs, double loss, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional probability.
Exceptions
- NanoQLException
The saddle point refuses the node.
ProbOverLossPortfCond1stOrder(double[], double, ReadOnlySpan<double>)
The first order expansion of ProbOverLossPortfCond(double[], double, ReadOnlySpan<double>), cheaper with fewer terms retained, though the cost lies in the saddle point; unused by the statistics.
protected double ProbOverLossPortfCond1stOrder(double[] invUncondPs, double loss, ReadOnlySpan<double> mktFactor)
Parameters
invUncondPsdouble[]The inverse cumulatives of the names' default probabilities.
lossdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double
The conditional probability.
Exceptions
- NanoQLException
The saddle point refuses the node.
ProbOverPortfLoss(Date, double)
The probability of losing an amount of the whole (untranched) live portfolio or more by a date.
public double ProbOverPortfLoss(Date d, double loss)
Parameters
Returns
- double
The probability.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).
ResetModel()
The model's per-basket precomputation, run once on the bound copy: QuantLib's resetModel.
protected override void ResetModel()
SplitLossCond(double[], double, ReadOnlySpan<double>)
The live names' contributions conditional on the factor to a loss of the whole (untranched) portfolio; exact at a node where every name's probability is 0 or 1.
protected double[] SplitLossCond(double[] invUncondProbs, double loss, ReadOnlySpan<double> mktFactor)
Parameters
invUncondProbsdouble[]The inverse cumulatives of the names' default probabilities.
lossdoubleThe loss, an amount.
mktFactorReadOnlySpan<double>The factor's values.
Returns
- double[]
The contributions, amounts.
Exceptions
- NanoQLException
The saddle point refuses the node.
SplitVaRLevel(Date, double)
The names' sensitivities to a loss level of the whole (untranched) portfolio: ratios to the structure's notional, which add up to the loss. Equation 8 of R. Martin, K. Thompson and C. Browne, "VAR: who contributes and how much?", Risk, August 2001. To be done, as in QuantLib: the tranched basket.
public override ImmutableArray<double> SplitVaRLevel(Date date, double loss)
Parameters
Returns
- ImmutableArray<double>
The contributions, by live name.
Exceptions
- NanoQLException
The model isn't bound to a basket, or the expansion refuses (a tail outside [0, 1], an unresolvable loss).