Table of Contents

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

TCopula

The copula policy.

TInitTraits

The 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

m ConstantLossLatentModel<TCopula, TInitTraits>

The constant-loss latent model.

Exceptions

ArgumentNullException

m is 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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<double>

The factor's values.

Returns

(double Npv, double Bps)

The cumulant generating function and its second derivative.

CumGen1stDerivative(Date, double)

The cumulant generating function's first derivative by a date, unconditional.

protected double CumGen1stDerivative(Date date, double s)

Parameters

date Date

The date.

s double

The saddle point.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<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

date Date

The date.

s double

The saddle point.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<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

date Date

The date.

s double

The saddle point.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<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

date Date

The date.

s double

The saddle point.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

saddle double

The saddle point.

mktFactor ReadOnlySpan<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

date Date

The date.

s double

The saddle point.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

lossFraction double

The saddle point.

mktFactor ReadOnlySpan<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

d Date

The 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

d Date

The date.

percentile double

The percentile, in [0, 1].

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

lossPerc double

The loss, an amount.

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

lossPerc double

The loss, an amount.

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

lossPerc double

The percentile's loss, an amount.

percentile double

The percentile.

mktFactor ReadOnlySpan<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

d Date

The 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

invUncondPs double[]

The inverse cumulatives of the names' default probabilities.

lossLevel double

The loss level, a fraction of the whole live portfolio.

mktFactor ReadOnlySpan<double>

The factor's values.

accuracy double

The solver's accuracy.

maxEvaluations int

The 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

d Date

The 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

d Date

The date.

percentile double

The percentile, in [0, 1].

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

d Date

The date.

loss double

The loss, an amount.

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

invUncondPs double[]

The inverse cumulatives of the names' default probabilities.

loss double

The loss, an amount.

mktFactor ReadOnlySpan<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

d Date

The date.

trancheLossFract double

The fraction of the live tranche.

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

invUncondPs double[]

The inverse cumulatives of the names' default probabilities.

trancheLossFract double

The fraction of the tranche's notional, in [0, 1].

mktFactor ReadOnlySpan<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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

loss double

The loss, an amount.

mktFactor ReadOnlySpan<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

invUncondPs double[]

The inverse cumulatives of the names' default probabilities.

loss double

The loss, an amount.

mktFactor ReadOnlySpan<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

d Date

The date.

loss double

The loss, an amount.

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

invUncondProbs double[]

The inverse cumulatives of the names' default probabilities.

loss double

The loss, an amount.

mktFactor ReadOnlySpan<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

date Date

The date.

loss double

The loss level, an amount, equivalent to a percentile.

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).