CreditDefaultSwap::CreditDefaultSwap(Protection::Side side,
Real notional,
Rate upfront,
Rate runningSpread,
const Schedule& schedule,
BusinessDayConvention convention,
const DayCounter& dayCounter,
bool settlesAccrual,
bool paysAtDefaultTime,
const Date& protectionStart,
const Date& upfrontDate,
const boost::shared_ptr<Claim>& claim,
const DayCounter& lastPeriodDayCounter,
const Natural standardCdsStartDelayDays,
const Natural standardCdsUpfrontDelayDays)
: side_(side), notional_(notional), upfront_(upfront),
runningSpread_(runningSpread), settlesAccrual_(settlesAccrual),
paysAtDefaultTime_(paysAtDefaultTime), claim_(claim),
protectionStart_(protectionStart == Null<Date>() ? schedule[0] :
protectionStart) {
Date d = upfrontDate == Null<Date>() ? schedule[0] : upfrontDate;
try {
if (schedule.rule() ==
DateGeneration::CDS) { // a standard CDS is identified
// by the schedule rule
Date evalDate = Settings::instance().evaluationDate();
if (protectionStart == Null<Date>())
protectionStart_ =
evalDate + standardCdsStartDelayDays; // if protection
// start is given it
// is not set here
if (upfrontDate == Null<Date>())
d = schedule.calendar().advance(
evalDate, standardCdsUpfrontDelayDays * Days,
schedule.businessDayConvention(),
schedule.endOfMonth()); // if upfront date is
// given it is not set
// here
QL_REQUIRE(protectionStart_ >= schedule[0],
"protection must start on or after accrual "
"start for standard CDS");
}
} catch (...) {
QL_REQUIRE(protectionStart_ <= schedule[0],
"protection can not start after accrual for non "
"standard CDS");
}
leg_ = FixedRateLeg(schedule)
.withNotionals(notional)
.withCouponRates(runningSpread, dayCounter)
.withPaymentAdjustment(convention)
.withLastPeriodDayCounter(lastPeriodDayCounter);
upfrontPayment_.reset(new SimpleCashFlow(notional*upfront, d));
QL_REQUIRE(upfrontPayment_->date() >= protectionStart_,
"upfront can not be due before contract start");
if (!claim_)
claim_ = boost::shared_ptr<Claim>(new FaceValueClaim);
registerWith(claim_);
}
void KahaleSmileSection::compute() {
std::pair<Size,Size> afIdx = ssutils_->arbitragefreeIndices();
leftIndex_ = afIdx.first;
rightIndex_ = afIdx.second;
if(deleteArbitragePoints_) {
while(leftIndex_>1 || rightIndex_<k_.size()-1) {
ssutils_ = boost::shared_ptr<SmileSectionUtils>(new SmileSectionUtils(*source_,moneynessGrid_,f_));
std::pair<Size,Size> afIdx = ssutils_->arbitragefreeIndices();
leftIndex_ = afIdx.first;
rightIndex_ = afIdx.second;
QL_REQUIRE(rightIndex_>leftIndex_,
"arbitrage free region must at least contain two points (only index is " << leftIndex_ << ")");
if(leftIndex_>1) {
moneynessGrid_.erase(moneynessGrid_.begin()+leftIndex_-1);
k_.erase(k_.begin()+leftIndex_-1);
c_.erase(c_.begin()+leftIndex_-1);
leftIndex_--;
rightIndex_--;
}
if(rightIndex_<k_.size()-1) {
moneynessGrid_.erase(moneynessGrid_.begin()+rightIndex_+1);
k_.erase(k_.begin()+rightIndex_+1);
c_.erase(c_.begin()+rightIndex_+1);
rightIndex_--;
}
}
}
cFunctions_ = std::vector<boost::shared_ptr<cFunction> >(rightIndex_-leftIndex_+2);
// extrapolation in the leftmost interval
Brent brent;
bool success;
Real secl = 0.0;
do {
success=true;
try {
Real k1 = k_[leftIndex_];
Real c1 = c_[leftIndex_];
Real c0 = c_[0];
secl = (c_[leftIndex_]-c_[0]) / (k_[leftIndex_]-k_[0]);
Real sec = (c_[leftIndex_+1]-c_[leftIndex_]) / (k_[leftIndex_+1]-k_[leftIndex_]);
Real c1p;
if(interpolate_) c1p=(secl+sec)/2;
else {
c1p=(blackFormula(Option::Call, k1+gap_, f_, sqrt(source_->variance(k1+gap_)))-
blackFormula(Option::Call, k1, f_, sqrt(source_->variance(k1))))/gap_;
QL_REQUIRE(secl < c1p && c1p <= 0.0,"dummy");
// can not extrapolate so throw exception which is caught below
}
sHelper1 sh1(k1,c0,c1,c1p);
Real s = brent.solve(sh1,QL_KAHALE_ACC,0.20,0.00,QL_KAHALE_SMAX); // numerical parameters hardcoded here
sh1(s);
boost::shared_ptr<cFunction> cFct1(new cFunction(sh1.f_,s,0.0,sh1.b_));
cFunctions_[0]=cFct1;
} catch(...) {
leftIndex_++;
success=false;
}
} while(!success && leftIndex_ < rightIndex_);
QL_REQUIRE(leftIndex_ < rightIndex_, "can not extrapolate to left, right index of af region reached ("
<< rightIndex_ << ")");
// interpolation
Real cp0 = 0.0, cp1 = 0.0;
if(interpolate_) {
for(Size i = leftIndex_; i<rightIndex_; i++) {
Real k0 = k_[i];
Real k1 = k_[i+1];
Real c0 = c_[i];
Real c1 = c_[i+1];
Real sec = (c_[i+1]-c_[i]) / (k_[i+1]-k_[i]);
if(i==leftIndex_) cp0 = leftIndex_ > 0 ? (secl + sec) / 2.0 : sec;
Real secr;
if(i==rightIndex_-1) secr=0.0;
else secr = (c_[i+2]-c_[i+1]) / (k_[i+2]-k_[i+1]);
cp1 = (sec+secr) / 2.0;
aHelper ah(k0,k1,c0,c1,cp0,cp1);
Real a;
try {
a = brent.solve(ah,QL_KAHALE_ACC,0.5*(cp1+(1.0+cp0)),cp1+QL_KAHALE_EPS,1.0+cp0-QL_KAHALE_EPS);
// numerical parameters hardcoded here
} catch(...) {
// from theory there must exist a zero. if the solver does not find it, it most
// probably lies close one of the interval bounds. Just choose the better bound
// and relax the accuracy. This does not matter in practice usually.
Real la = std::fabs(ah(cp1+QL_KAHALE_EPS));
//.........这里部分代码省略.........
void LocalBootstrap<Curve>::calculate() const {
validCurve_ = false;
Size nInsts = ts_->instruments_.size();
// ensure rate helpers are sorted
std::sort(ts_->instruments_.begin(), ts_->instruments_.end(),
detail::BootstrapHelperSorter());
// check that there is no instruments with the same maturity
for (Size i=1; i<nInsts; ++i) {
Date m1 = ts_->instruments_[i-1]->latestDate(),
m2 = ts_->instruments_[i]->latestDate();
QL_REQUIRE(m1 != m2,
"two instruments have the same maturity ("<< m1 <<")");
}
// check that there is no instruments with invalid quote
for (Size i=0; i<nInsts; ++i)
QL_REQUIRE(ts_->instruments_[i]->quote()->isValid(),
io::ordinal(i+1) << " instrument (maturity: " <<
ts_->instruments_[i]->latestDate() <<
") has an invalid quote");
// setup instruments
for (Size i=0; i<nInsts; ++i) {
// don't try this at home!
// This call creates instruments, and removes "const".
// There is a significant interaction with observability.
ts_->instruments_[i]->setTermStructure(const_cast<Curve*>(ts_));
}
// set initial guess only if the current curve cannot be used as guess
if (validCurve_)
QL_ENSURE(ts_->data_.size() == nInsts+1,
"dimension mismatch: expected " << nInsts+1 <<
", actual " << ts_->data_.size());
else {
ts_->data_ = std::vector<Rate>(nInsts+1);
ts_->data_[0] = Traits::initialValue(ts_);
}
// calculate dates and times
ts_->dates_ = std::vector<Date>(nInsts+1);
ts_->times_ = std::vector<Time>(nInsts+1);
ts_->dates_[0] = Traits::initialDate(ts_);
ts_->times_[0] = ts_->timeFromReference(ts_->dates_[0]);
for (Size i=0; i<nInsts; ++i) {
ts_->dates_[i+1] = ts_->instruments_[i]->latestDate();
ts_->times_[i+1] = ts_->timeFromReference(ts_->dates_[i+1]);
if (!validCurve_)
ts_->data_[i+1] = ts_->data_[i];
}
LevenbergMarquardt solver(ts_->accuracy_,
ts_->accuracy_,
ts_->accuracy_);
EndCriteria endCriteria(100, 10, 0.00, ts_->accuracy_, 0.00);
PositiveConstraint posConstraint;
NoConstraint noConstraint;
Constraint& solverConstraint = forcePositive_ ?
static_cast<Constraint&>(posConstraint) :
static_cast<Constraint&>(noConstraint);
// now start the bootstrapping.
Size iInst = localisation_-1;
Size dataAdjust = Curve::interpolator_type::dataSizeAdjustment;
do {
Size initialDataPt = iInst+1-localisation_+dataAdjust;
Array startArray(localisation_+1-dataAdjust);
for (Size j = 0; j < startArray.size()-1; ++j)
startArray[j] = ts_->data_[initialDataPt+j];
// here we are extending the interpolation a point at a
// time... but the local interpolator can make an
// approximation for the final localisation period.
// e.g. if the localisation is 2, then the first section
// of the curve will be solved using the first 2
// instruments... with the local interpolator making
// suitable boundary conditions.
ts_->interpolation_ =
ts_->interpolator_.localInterpolate(
ts_->times_.begin(),
ts_->times_.begin()+(iInst + 2),
ts_->data_.begin(),
localisation_,
ts_->interpolation_,
nInsts+1);
if (iInst >= localisation_) {
startArray[localisation_-dataAdjust] =
Traits::guess(iInst, ts_, false, 0); // ?
} else {
startArray[localisation_-dataAdjust] = ts_->data_[0];
}
PenaltyFunction<Curve> currentCost(
ts_,
initialDataPt,
//.........这里部分代码省略.........
void BinomialBarrierEngine<T,D>::calculate() const {
DayCounter rfdc = process_->riskFreeRate()->dayCounter();
DayCounter divdc = process_->dividendYield()->dayCounter();
DayCounter voldc = process_->blackVolatility()->dayCounter();
Calendar volcal = process_->blackVolatility()->calendar();
Real s0 = process_->stateVariable()->value();
QL_REQUIRE(s0 > 0.0, "negative or null underlying given");
Volatility v = process_->blackVolatility()->blackVol(
arguments_.exercise->lastDate(), s0);
Date maturityDate = arguments_.exercise->lastDate();
Rate r = process_->riskFreeRate()->zeroRate(maturityDate,
rfdc, Continuous, NoFrequency);
Rate q = process_->dividendYield()->zeroRate(maturityDate,
divdc, Continuous, NoFrequency);
Date referenceDate = process_->riskFreeRate()->referenceDate();
// binomial trees with constant coefficient
Handle<YieldTermStructure> flatRiskFree(
boost::shared_ptr<YieldTermStructure>(
new FlatForward(referenceDate, r, rfdc)));
Handle<YieldTermStructure> flatDividends(
boost::shared_ptr<YieldTermStructure>(
new FlatForward(referenceDate, q, divdc)));
Handle<BlackVolTermStructure> flatVol(
boost::shared_ptr<BlackVolTermStructure>(
new BlackConstantVol(referenceDate, volcal, v, voldc)));
boost::shared_ptr<StrikedTypePayoff> payoff =
boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
QL_REQUIRE(payoff, "non-striked payoff given");
Time maturity = rfdc.yearFraction(referenceDate, maturityDate);
boost::shared_ptr<StochasticProcess1D> bs(
new GeneralizedBlackScholesProcess(
process_->stateVariable(),
flatDividends, flatRiskFree, flatVol));
// correct timesteps to ensure a (local) minimum, using Boyle and Lau
// approach. See Journal of Derivatives, 1/1994,
// "Bumping up against the barrier with the binomial method"
// Note: this approach works only for CoxRossRubinstein lattices, so
// is disabled if T is not a CoxRossRubinstein or derived from it.
Size optimum_steps = timeSteps_;
if (boost::is_base_of<CoxRossRubinstein, T>::value &&
maxTimeSteps_ > timeSteps_ && s0 > 0 && arguments_.barrier > 0) {
Real divisor;
if (s0 > arguments_.barrier)
divisor = std::pow(std::log(s0 / arguments_.barrier), 2);
else
divisor = std::pow(std::log(arguments_.barrier / s0), 2);
if (!close(divisor,0)) {
for (Size i=1; i < timeSteps_ ; ++i) {
Size optimum = Size(( i*i * v*v * maturity) / divisor);
if (timeSteps_ < optimum) {
optimum_steps = optimum;
break; // found first minimum with iterations>=timesteps
}
}
}
if (optimum_steps > maxTimeSteps_)
optimum_steps = maxTimeSteps_; // too high, limit
}
TimeGrid grid(maturity, optimum_steps);
boost::shared_ptr<T> tree(new T(bs, maturity, optimum_steps,
payoff->strike()));
boost::shared_ptr<BlackScholesLattice<T> > lattice(
new BlackScholesLattice<T>(tree, r, maturity, optimum_steps));
D option(arguments_, *process_, grid);
option.initialize(lattice, maturity);
// Partial derivatives calculated from various points in the
// binomial tree
// (see J.C.Hull, "Options, Futures and other derivatives", 6th edition, pp 397/398)
// Rollback to third-last step, and get underlying prices (s2) &
// option values (p2) at this point
option.rollback(grid[2]);
Array va2(option.values());
QL_ENSURE(va2.size() == 3, "Expect 3 nodes in grid at second step");
Real p2u = va2[2]; // up
Real p2m = va2[1]; // mid
Real p2d = va2[0]; // down (low)
Real s2u = lattice->underlying(2, 2); // up price
Real s2m = lattice->underlying(2, 1); // middle price
Real s2d = lattice->underlying(2, 0); // down (low) price
// calculate gamma by taking the first derivate of the two deltas
Real delta2u = (p2u - p2m)/(s2u-s2m);
Real delta2d = (p2m-p2d)/(s2m-s2d);
Real gamma = (delta2u - delta2d) / ((s2u-s2d)/2);
// Rollback to second-last step, and get option values (p1) at
//.........这里部分代码省略.........
void LinearTsrPricer::initialize(const FloatingRateCoupon &coupon) {
coupon_ = dynamic_cast<const CmsCoupon *>(&coupon);
QL_REQUIRE(coupon_, "CMS coupon needed");
gearing_ = coupon_->gearing();
spread_ = coupon_->spread();
fixingDate_ = coupon_->fixingDate();
paymentDate_ = coupon_->date();
swapIndex_ = coupon_->swapIndex();
forwardCurve_ = swapIndex_->forwardingTermStructure();
if (swapIndex_->exogenousDiscount())
discountCurve_ = swapIndex_->discountingTermStructure();
else
discountCurve_ = forwardCurve_;
// if no coupon discount curve is given just use the discounting curve
// from the swap index. for rate calculation this curve cancels out in
// the computation, so e.g. the discounting swap engine will produce
// correct results, even if the couponDiscountCurve is not set here.
// only the price member function in this class will be dependent on the
// coupon discount curve.
today_ = QuantLib::Settings::instance().evaluationDate();
if (paymentDate_ > today_ && !couponDiscountCurve_.empty())
couponDiscountRatio_ =
couponDiscountCurve_->discount(paymentDate_) /
discountCurve_->discount(paymentDate_);
else
couponDiscountRatio_ = 1.;
spreadLegValue_ = spread_ * coupon_->accrualPeriod() *
discountCurve_->discount(paymentDate_) *
couponDiscountRatio_;
if (fixingDate_ > today_) {
swapTenor_ = swapIndex_->tenor();
swap_ = swapIndex_->underlyingSwap(fixingDate_);
swapRateValue_ = swap_->fairRate();
annuity_ = 1.0E4 * std::fabs(swap_->fixedLegBPS());
ext::shared_ptr<SmileSection> sectionTmp =
swaptionVolatility()->smileSection(fixingDate_, swapTenor_);
adjustedLowerBound_ = settings_.lowerRateBound_;
adjustedUpperBound_ = settings_.upperRateBound_;
if(sectionTmp->volatilityType() == Normal) {
// adjust lower bound if it was not set explicitly
if(settings_.defaultBounds_)
adjustedLowerBound_ = std::min(adjustedLowerBound_, -adjustedUpperBound_);
} else {
// adjust bounds by section's shift
adjustedLowerBound_ -= sectionTmp->shift();
adjustedUpperBound_ -= sectionTmp->shift();
}
// if the section does not provide an atm level, we enhance it to
// have one, no need to exit with an exception ...
if (sectionTmp->atmLevel() == Null<Real>())
smileSection_ = ext::make_shared<AtmSmileSection>(
sectionTmp, swapRateValue_);
else
smileSection_ = sectionTmp;
// compute linear model's parameters
Real gx = 0.0, gy = 0.0;
for (Size i = 0; i < swap_->fixedLeg().size(); i++) {
ext::shared_ptr<Coupon> c =
ext::dynamic_pointer_cast<Coupon>(swap_->fixedLeg()[i]);
Real yf = c->accrualPeriod();
Date d = c->date();
Real pv = yf * discountCurve_->discount(d);
gx += pv * GsrG(d);
gy += pv;
}
Real gamma = gx / gy;
Date lastd = swap_->fixedLeg().back()->date();
a_ = discountCurve_->discount(paymentDate_) *
(gamma - GsrG(paymentDate_)) /
(discountCurve_->discount(lastd) * GsrG(lastd) +
swapRateValue_ * gy * gamma);
b_ = discountCurve_->discount(paymentDate_) / gy -
a_ * swapRateValue_;
}
}
Real DigitalPathPricer::operator()(const Path& path) const {
Size n = path.length();
QL_REQUIRE(n>1, "the path cannot be empty");
Real log_asset_price = std::log(path.front());
Real x, y;
Volatility vol;
TimeGrid timeGrid = path.timeGrid();
Time dt;
std::vector<Real> u = sequenceGen_.nextSequence().value;
Real log_strike = std::log(payoff_->strike());
Size i;
switch (payoff_->optionType()) {
case Option::Call:
for (i=0; i<n-1; i++) {
x = std::log(path[i+1]/path[i]);
// terminal or initial vol?
vol = diffProcess_->diffusion(timeGrid[i+1],
std::exp(log_asset_price));
// vol = diffProcess_->diffusion(timeGrid[i+2],
// std::exp(log_asset_price+x));
dt = timeGrid.dt(i);
y = log_asset_price +
0.5*(x + std::sqrt(x*x-2*vol*vol*dt*std::log((1-u[i]))));
// cross the strike
if (y >= log_strike) {
if (exercise_->payoffAtExpiry()) {
return payoff_->cashPayoff() *
discountTS_->discount(path.timeGrid().back());
} else {
// the discount should be calculated at the exercise
// time between path.timeGrid()[i+1] and
// path.timeGrid()[i+2]
return payoff_->cashPayoff() *
discountTS_->discount(path.timeGrid()[i+1]);
}
}
log_asset_price += x;
}
break;
case Option::Put:
for (i=0; i<n-1; i++) {
x = std::log(path[i+1]/path[i]);
// terminal or initial vol?
// initial (timeGrid[i+1]) for the time being
vol = diffProcess_->diffusion(timeGrid[i+1],
std::exp(log_asset_price));
// vol = diffProcess_->diffusion(timeGrid[i+2],
// std::exp(log_asset_price+x));
dt = timeGrid.dt(i);
y = log_asset_price +
0.5*(x - std::sqrt(x*x - 2*vol*vol*dt*std::log(u[i])));
if (y <= log_strike) {
if (exercise_->payoffAtExpiry()) {
return payoff_->cashPayoff() *
discountTS_->discount(path.timeGrid().back());
} else {
// the discount should be calculated at the exercise
// time between path.timeGrid()[i+1] and
// path.timeGrid()[i+2]
return payoff_->cashPayoff() *
discountTS_->discount(path.timeGrid()[i+1]);
}
}
log_asset_price += x;
}
break;
default:
QL_FAIL("unknown option type");
}
return 0.0;
}
请发表评论