void SquareRootAndersen::DoOneSubStep(Real& vt, Real z, Size j) { Real eminuskT = eMinuskDt_[j]; Real m = theta_+(vt-theta_)*eminuskT; Real s2= vt*epsilon_*epsilon_*eminuskT*(1-eminuskT)/k_ + theta_*epsilon_*epsilon_*(1- eminuskT)*(1- eminuskT)/(2*k_); Real s = std::sqrt(s2); Real psi = s*s/(m*m); if (psi<= PsiC_) { Real psiinv = 1.0/psi; Real b2 = 2.0*psiinv -1+std::sqrt(2*psiinv*(2*psiinv-1.0)); Real b = std::sqrt(b2); Real a= m/(1+b2); vt= a*(b+z)*(b+z); } else { Real p = (psi-1.0)/(psi+1.0); Real beta = (1.0-p)/m; Real u = CumulativeNormalDistribution()(z); if (u < p) { vt=0; return; } vt = std::log((1.0-p)/(1.0-u))/beta; } }
void DoubleExponentialCalibration::compute() { if (vegaWeighted_) { Real weightsSum = 0.0; for (Size i=0; i<times_.size() ; i++) { Real stdDev = std::sqrt(blackVols_[i]* blackVols_[i]* times_[i]); // when strike==forward, the blackFormulaStdDevDerivative becomes weights_[i] = CumulativeNormalDistribution().derivative(.5*stdDev); weightsSum += weights_[i]; } // weight normalization for (Size i=0; i<times_.size() ; i++) { weights_[i] /= weightsSum; } } // there is nothing to optimize if (sigmaIsFixed_ && b1IsFixed_ && b2IsFixed_ && lambdaIsFixed_) { dblexpEndCriteria_ = EndCriteria::None; //error_ = interpolationError(); //maxError_ = interpolationMaxError(); return; } else { DoubleExponentialError costFunction(this); Array guess(4); guess[0] = sigma_; guess[1] = b1_; guess[2] = b2_; guess[3] = lambda_; std::vector<bool> parameterAreFixed(4); parameterAreFixed[0] = sigmaIsFixed_; parameterAreFixed[1] = b1IsFixed_; parameterAreFixed[2] = b2IsFixed_; parameterAreFixed[3] = lambdaIsFixed_; ProjectedCostFunction projectedDoubleExponentialCostFunction(costFunction, guess, parameterAreFixed); Array projectedGuess (projectedDoubleExponentialCostFunction.project(guess)); // NoConstraint constraint; //PositiveConstraint constraint; BoundaryConstraint constraint(0.0, 1.0); Problem problem(projectedDoubleExponentialCostFunction, constraint, projectedGuess); dblexpEndCriteria_ = optMethod_->minimize(problem, *endCriteria_); Array projectedResult(problem.currentValue()); Array result(projectedDoubleExponentialCostFunction.include(projectedResult)); sigma_ = result[0]; b1_ = result[1]; b2_ = result[2]; lambda_ = result[3]; validateDoubleExponentialParameters(sigma_, b1_, b2_, lambda_); } }
//----------------------------------------------------------------------- Real OneFactorGaussianCopula::testCumulativeY (Real y) const { //----------------------------------------------------------------------- Real c = correlation_->value(); if (c == 0) return CumulativeNormalDistribution()(y); if (c == 1) return CumulativeNormalDistribution()(y); NormalDistribution dz; NormalDistribution dm; Real minimum = -10; Real maximum = +10; int steps = 200; Real delta = (maximum - minimum) / steps; Real cumulated = 0; if (c < 0.5) { // outer integral -> 1 for c -> 0 // inner integral -> CumulativeNormal()(y) for c-> 0 for (Real m = minimum; m < maximum; m += delta) for (Real z = minimum; z < (y - std::sqrt(c) * m) / std::sqrt (1. - c); z += delta) cumulated += dm (m) * dz (z); } else { // outer integral -> 1 for c -> 1 // inner integral -> CumulativeNormal()(y) for c-> 1 for (Real z = minimum; z < maximum; z += delta) for (Real m = minimum; m < (y - std::sqrt(1.0 - c) * z) / std::sqrt(c); m += delta) cumulated += dm (m) * dz (z); } cumulated *= (delta * delta); return cumulated; }
void GaussianRandomDefaultModel::nextSequence(Real tmax) { const std::vector<Real>& values = rsg_.nextSequence().value; Real a = sqrt(copula_->correlation()); for (Size j = 0; j < pool_->size(); j++) { const string name = pool_->names()[j]; const Handle<DefaultProbabilityTermStructure>& dts = pool_->get(name).defaultProbability(defaultKeys_[j]); Real y = a * values[0] + sqrt(1-a*a) * values[j+1]; Real p = CumulativeNormalDistribution()(y); if (dts->defaultProbability(tmax) < p) pool_->setTime(name, tmax+1); else pool_->setTime(name, Brent().solve(Root(dts,p),accuracy_,0,1)); } }
//------------------------------------------------------------------------- Real OneFactorStudentGaussianCopula::cumulativeYintegral (Real y) const { //------------------------------------------------------------------------- Real c = correlation_->value(); if (c == 0) return CumulativeNormalDistribution()(y); if (c == 1) return CumulativeStudentDistribution(nm_)(y / scaleM_); StudentDistribution dm (nm_); NormalDistribution dz; // FIXME: // Find a sensitive way of setting these parameters, // e.g. depending on nm and nz, and the desired table range Real minimum = -10; Real maximum = +10; int steps = 400; Real delta = (maximum - minimum) / steps; Real cumulated = 0; if (c < 0.5) { // outer integral -> 1 for c -> 0 // inner integral -> cumulativeNormal(y) for c-> 0 for (Real m = minimum + delta/2; m < maximum; m += delta) for (Real z = minimum + delta/2; z < (y - std::sqrt(c) * m) / std::sqrt (1. - c); z += delta) cumulated += dm (m / scaleM_) / scaleM_ * dz (z); } else { // outer integral -> 1 for c -> 1 // inner integral -> cumulativeStudent(nm)(y) for c-> 1 for (Real z = minimum + delta/2; z < maximum; z += delta) for (Real m = minimum + delta/2; m < (y - std::sqrt(1.0 - c) * z) / std::sqrt(c); m += delta) cumulated += dm (m / scaleM_) / scaleM_ * dz (z); } return cumulated * delta * delta; }
Disposable<Array> HestonSLVProcess::evolve( Time t0, const Array& x0, Time dt, const Array& dw) const { Array retVal(2); const Real ex = std::exp(-kappa_*dt); const Real m = theta_+(x0[1]-theta_)*ex; const Real s2 = x0[1]*sigma_*sigma_*ex/kappa_*(1-ex) + theta_*sigma_*sigma_/(2*kappa_)*(1-ex)*(1-ex); const Real psi = s2/(m*m); if (psi < 1.5) { const Real b2 = 2/psi-1+std::sqrt(2/psi*(2/psi-1)); const Real b = std::sqrt(b2); const Real a = m/(1+b2); retVal[1] = a*(b+dw[1])*(b+dw[1]); } else { const Real p = (psi-1)/(psi+1); const Real beta = (1-p)/m; const Real u = CumulativeNormalDistribution()(dw[1]); retVal[1] = ((u <= p) ? 0.0 : std::log((1-p)/(1-u))/beta); } const Real mu = riskFreeRate()->forwardRate(t0, t0+dt, Continuous) - dividendYield()->forwardRate(t0, t0+dt, Continuous); const Real rho1 = std::sqrt(1-rho_*rho_); const Volatility l_0 = leverageFct_->localVol(t0, x0[0], true); const Real v_0 = 0.5*(x0[1]+retVal[1])*l_0*l_0; retVal[0] = x0[0]*std::exp(mu*dt - 0.5*v_0*dt + rho_/sigma_*l_0 * ( retVal[1] - kappa_*theta_*dt + 0.5*(x0[1]+retVal[1])*kappa_*dt - x0[1]) + rho1*std::sqrt(v_0*dt)*dw[0]); return retVal; }
Real blackFormulaStdDevDerivative(Rate strike, Rate forward, Real stdDev, Real discount, Real displacement) { checkParameters(strike, forward, displacement); QL_REQUIRE(stdDev>=0.0, "stdDev (" << stdDev << ") must be non-negative"); QL_REQUIRE(discount>0.0, "discount (" << discount << ") must be positive"); forward = forward + displacement; strike = strike + displacement; if (stdDev==0.0 || strike==0.0) return 0.0; Real d1 = std::log(forward/strike)/stdDev + .5*stdDev; return discount * forward * CumulativeNormalDistribution().derivative(d1); }
namespace QuantLib { CumulativeNormalDistribution const GaussianLHPLossModel::phi_ = CumulativeNormalDistribution(); GaussianLHPLossModel::GaussianLHPLossModel( const Handle<Quote>& correlQuote, const std::vector<Handle<RecoveryRateQuote> >& quotes) : LatentModel<GaussianCopulaPolicy>(sqrt(correlQuote->value()), quotes.size(), //g++ complains default value not seen as typename GaussianCopulaPolicy::initTraits()), sqrt1minuscorrel_(std::sqrt(1.-correlQuote->value())), correl_(correlQuote), rrQuotes_(quotes), beta_(sqrt(correlQuote->value())), biphi_(-sqrt(correlQuote->value())) { registerWith(correl_); for(Size i=0; i<quotes.size(); i++) registerWith(quotes[i]); } GaussianLHPLossModel::GaussianLHPLossModel( Real correlation, const std::vector<Real>& recoveries) : LatentModel<GaussianCopulaPolicy>(sqrt(correlation), recoveries.size(), //g++ complains default value not seen as typename GaussianCopulaPolicy::initTraits()), sqrt1minuscorrel_(std::sqrt(1.-correlation)), correl_(Handle<Quote>(boost::make_shared<SimpleQuote>(correlation))), beta_(sqrt(correlation)), biphi_(-sqrt(correlation)) { for(Size i=0; i<recoveries.size(); i++) rrQuotes_.push_back(Handle<RecoveryRateQuote>( boost::make_shared<RecoveryRateQuote>(recoveries[i]))); } GaussianLHPLossModel::GaussianLHPLossModel( const Handle<Quote>& correlQuote, const std::vector<Real>& recoveries) : LatentModel<GaussianCopulaPolicy>(sqrt(correlQuote->value()), recoveries.size(), //g++ complains default value not seen as typename GaussianCopulaPolicy::initTraits()), sqrt1minuscorrel_(std::sqrt(1.-correlQuote->value())), correl_(correlQuote), beta_(sqrt(correlQuote->value())), biphi_(-sqrt(correlQuote->value())) { registerWith(correl_); for(Size i=0; i<recoveries.size(); i++) rrQuotes_.push_back(Handle<RecoveryRateQuote>( boost::make_shared<RecoveryRateQuote>(recoveries[i]))); } Real GaussianLHPLossModel::expectedTrancheLossImpl( Real remainingNot, // << at the given date 'd' Real prob, // << at the given date 'd' Real averageRR, // << at the given date 'd' // these are percentual values: Real attachLimit, Real detachLimit) const { if (attachLimit >= detachLimit) return 0.;// or is it an error? // expected remaining notional: if (remainingNot == 0.) return 0.; const Real one = 1.0 - 1.0e-12; // FIXME DUE TO THE INV CUMUL AT 1 const Real k1 = std::min(one, attachLimit /(1.0 - averageRR) ) + QL_EPSILON; const Real k2 = std::min(one, detachLimit /(1.0 - averageRR) ) + QL_EPSILON; if (prob > 0) { const Real ip = InverseCumulativeNormal::standard_value(prob); const Real invFlightK1 = (ip-sqrt1minuscorrel_ * InverseCumulativeNormal::standard_value(k1))/beta_; const Real invFlightK2 = (ip-sqrt1minuscorrel_* InverseCumulativeNormal::standard_value(k2))/beta_; return remainingNot * (detachLimit * phi_(invFlightK2) - attachLimit * phi_(invFlightK1) + (1.-averageRR) * (biphi_(ip, -invFlightK2) - biphi_(ip, -invFlightK1)) ); } else return 0.0; } Real GaussianLHPLossModel::probOverLoss(const Date& d, Real remainingLossFraction) const { // these test goes into basket<<<<<<<<<<<<<<<<<<<<<<<<< QL_REQUIRE(remainingLossFraction >=0., "Incorrect loss fraction."); QL_REQUIRE(remainingLossFraction <=1., "Incorrect loss fraction."); Real remainingAttachAmount = basket_->remainingAttachmentAmount(); Real remainingDetachAmount = basket_->remainingDetachmentAmount(); // live unerlying portfolio loss fraction (remaining portf fraction) const Real remainingBasktNot = basket_->remainingNotional(d); const Real attach = std::min(remainingAttachAmount / remainingBasktNot, 1.); const Real detach = std::min(remainingDetachAmount / remainingBasktNot, 1.); Real portfFract = attach + remainingLossFraction * (detach - attach); Real averageRR = averageRecovery(d); Real maxAttLossFract = (1.-averageRR); if(portfFract > maxAttLossFract) return 0.; // for non-equity losses add the probability jump at zero tranche // losses (since this method returns prob of losing more or // equal to) if(portfFract <= QL_EPSILON) return 1.; Probability prob = averageProb(d); Real ip = InverseCumulativeNormal::standard_value(prob); Real invFlightK = (ip-sqrt1minuscorrel_* InverseCumulativeNormal::standard_value(portfFract /(1.-averageRR)))/beta_; return phi_(invFlightK);//probOver } Real GaussianLHPLossModel::expectedShortfall(const Date& d, Probability perctl) const { // loss as a fraction of the live portfolio Real ptflLossPerc = percentilePortfolioLossFraction(d, perctl); Real remainingAttachAmount = basket_->remainingAttachmentAmount(); Real remainingDetachAmount = basket_->remainingDetachmentAmount(); const Real remainingNot = basket_->remainingNotional(d); const Real attach = std::min(remainingAttachAmount / remainingNot, 1.); const Real detach = std::min(remainingDetachAmount / remainingNot, 1.); if(ptflLossPerc >= detach-QL_EPSILON) return remainingNot * (detach-attach);//equivalent Real maxLossLevel = std::max(attach, ptflLossPerc); Probability prob = averageProb(d); Real averageRR = averageRecovery(d); Real valA = expectedTrancheLossImpl(remainingNot, prob, averageRR, maxLossLevel, detach); Real valB = // probOverLoss(d, maxLossLevel);//in live tranche units // from fraction of basket notional to fraction of tranche notional probOverLoss(d, std::min(std::max((maxLossLevel - attach) /(detach - attach), 0.), 1.)); return ( valA + (maxLossLevel - attach) * remainingNot * valB ) / (1.-perctl); } Real GaussianLHPLossModel::percentilePortfolioLossFraction( const Date& d, Real perctl) const { // this test goes into basket<<<<<<<<<<<<<<<<<<<<<<<<< QL_REQUIRE(perctl >= 0. && perctl <=1., "Percentile argument out of bounds."); if(perctl==0.) return 0.;// portfl == attach if(perctl==1.) perctl = 1. - QL_EPSILON; // portfl == detach return (1.-averageRecovery(d)) * phi_( ( InverseCumulativeNormal::standard_value(averageProb(d)) + beta_ * InverseCumulativeNormal::standard_value(perctl) ) /sqrt1minuscorrel_); } }
Disposable<Array> HestonDupireProcess::evolve(Time t0, const Array& x0, Time dt, const Array& dw) const { Array retVal(2); Real mu; const Real sdt = std::sqrt(dt); const Real sqrhov = std::sqrt(1.0 - rho_*rho_); Real leverageVal = leverSurf_->localVol(t0, x0[0]);; switch (discretization_) { case QuadraticExponential: { // for details of the quadratic exponential discretization scheme // see Leif Andersen, // Efficient Simulation of the Heston Stochastic Volatility Model // For local freezing of lsv leverage // see Anthonie W Van der Stoep // The heston stochastic local volatility model: efficient monte carlo simulation const Real ex = std::exp(-kappa_*dt); const Real m = theta_+(x0[1]-theta_)*ex; const Real s2 = x0[1]*sigma_*sigma_*ex/kappa_*(1-ex) + theta_*sigma_*sigma_/(2*kappa_)*(1-ex)*(1-ex); const Real psi = s2/(m*m); const Real g1 = 0.5; const Real g2 = 0.5; Real k0 = -rho_*kappa_*theta_*dt/sigma_; const Real k1 = g1*dt*(kappa_*rho_/sigma_-0.5)-rho_/sigma_; const Real k2 = g2*dt*(kappa_*rho_/sigma_-0.5)+rho_/sigma_; const Real k3 = g1*dt*(1-rho_*rho_); const Real k4 = g2*dt*(1-rho_*rho_); const Real A = k2+0.5*k4; if (psi < 1.5) { const Real b2 = 2/psi-1+std::sqrt(2/psi*(2/psi-1)); const Real b = std::sqrt(b2); const Real a = m/(1+b2); retVal[1] = a*(b+dw[1])*(b+dw[1]); } else { const Real p = (psi-1)/(psi+1); const Real beta = (1-p)/m; const Real u = CumulativeNormalDistribution()(dw[1]); retVal[1] = ((u <= p) ? 0.0 : std::log((1-p)/(1-u))/beta); } mu = riskFreeRate_->forwardRate(t0, t0+dt, Continuous) - dividendYield_->forwardRate(t0, t0+dt, Continuous); // local freezing part double c0 = leverageVal*leverageVal*x0[1]*dt; double k5 = rho_*(retVal[1]-x0[1]+kappa_*dt*x0[1]-kappa_*dt*theta_)/sigma_; retVal[0] = x0[0]*std::exp(mu*dt - 0.5*c0 + k5 + sqrhov*sqrt(c0)*dw[0]); } break; default: QL_FAIL("unknown discretization schema"); } return retVal; }
Real BSMRNDCalculator::cdf(Real x, Time t) const { std::pair<Real, Volatility> p = distributionParams(x, t); return CumulativeNormalDistribution(p.first, p.second)(x); }