#include #include #include #define MIN(x, y) (((x) < (y)) ? (x) : (y)) void lossdistrib(double *p, int *np, double *w, double *S, int *N, int* defaultflag, double *q) { /* recursive algorithm with first order correction for computing the loss distribution. p vector of default probabilities np length of p S vector of severities (should be same length as p) N number of ticks in the grid defaultflat if true compute the default distribution q the loss distribution */ int i, j, d1, d2, M; double lu, d, p1, p2, sum; double *qtemp; lu = 1./(*N-1); qtemp = Calloc(*N, double); q[0] = 1; M = 1; for(i=0; i<(*np); i++){ d = (*defaultflag)? w[i]/lu : S[i] * w[i]/ lu; d1 = floor(d); d2 = ceil(d); p1 = p[i] * (d2-d); p2 = p[i] - p1; memcpy(qtemp, q, MIN(M, *N) * sizeof(double)); for(j=0; j < MIN(M, *N); j++){ q[j] = (1-p[i]) * q[j]; } for(j=0; j < MIN(M, *N-d2); j++){ q[d1+j] += p1 * qtemp[j]; q[d2+j] += p2 * qtemp[j]; }; M+=d2; } /* correction for weight loss */ if(M>*N){ sum = 0; for(j=0; j*N || My>*N){ sum = 0; for(m=0; m < MIN(Mx, *N); m++){ for(n=0; n < MIN(My, *N); n++){ sum += q[m+n*(*N)]; } } q[MIN(*N, Mx)*MIN(My,*N)-1] += 1 - sum; } Free(qtemp); } void recovdist(double *dp, double *pp, int *n, double *w, double *S, int *N, double *q) { /* recursive algorithm with first order correction for computing the recovery distribution in case of prepayment. dp vector of default probabilities pp vector of prepay probabilities n length of p S vector of severities (should be same length as p) w vector of weights N number of ticks in the grid q the loss distribution */ int i, j, d1l, d1u, d2l, d2u; int M; double lu, d1, d2, dp1, dp2, pp1, pp2, sum; double *qtemp; lu = 1./(*N - 1); qtemp = Calloc( (*N), double); q[0] = 1; M=1; for(i=0; i<(*n); i++){ d1 = w[i] * (1-S[i]) /lu; d2 = w[i]/lu; d1l = floor(d1); d1u = d1l + 1; d2l = floor(d2); d2u = d2l + 1; dp1 = dp[i] * (d1u - d1); dp2 = dp[i] - dp1; pp1 = pp[i] * (d2u - d2); pp2 = pp[i] - pp1; memcpy(qtemp, q, MIN(M, *N) * sizeof(double)); for(j = 0; j< MIN(M, *N); j++){ q[j] = (1-dp[i]-pp[i]) * q[j]; } for(j=0; j < MIN(M, *N-d2u); j++){ q[d1l+j] += dp1 * qtemp[j]; q[d1u+j] += dp2 * qtemp[j]; q[d2l+j] += pp1 * qtemp[j]; q[d2u+j] += pp2 * qtemp[j]; }; M += d2u; } /* correction for weight loss */ if(M>*N){ sum = 0; for(j=0; j*N || My>*N){ sum = 0; for(m=0; m < MIN(Mx, *N); m++){ for(n=0; n < MIN(My, *N); n++){ sum += q[m+n*(*N)]; } } q[MIN(*N, Mx)*MIN(My,*N)-1] += 1 - sum; } Free(qtemp); } double shockprob(double p, double rho, double Z, int give_log){ return( pnorm( (qnorm(p, 0, 1, 1, 0) -sqrt(rho) * Z)/sqrt(1 - rho), 0, 1, 1, give_log)); } double shockseverity(double S, double Z, double rho, double p){ return( exp(shockprob(S * p, rho, Z, 1) - shockprob(p, rho, Z, 1)) ); } void addandmultiply(double *X, double alpha, double *Y, int n) { int i; for(i = 0; i