39 const Date& paymentDate,
41 const ext::shared_ptr<IborIndex>& index,
42 const Date& startDate,
48 const Date& refPeriodStart,
49 const Date& refPeriodEnd,
50 ext::shared_ptr<Schedule> observationsSchedule,
65 observationsSchedule_(
std::move(observationsSchedule)), lowerTrigger_(lowerTrigger),
66 upperTrigger_(upperTrigger) {
69 "lowerTrigger_>=upperTrigger");
71 "incompatible start date");
73 "incompatible end date");
81 index->forwardingTermStructure();
82 Date referenceDate = rateCurve->referenceDate();
119 ext::shared_ptr<IborIndex> index =
122 index->forwardingTermStructure();
123 discount_ = rateCurve->discount(paymentDate);
134 const std::vector<Date> &observationDates =
137 "incompatible size of initialValues vector");
140 Calendar calendar = index->fixingCalendar();
141 for(
Size i=0; i<observationDates.size(); i++) {
143 calendar.
advance(observationDates[i],
155 QL_FAIL(
"RangeAccrualPricer::capletPrice not implemented");
159 QL_FAIL(
"RangeAccrualPricer::capletRate not implemented");
163 QL_FAIL(
"RangeAccrualPricer::floorletPrice not implemented");
167 QL_FAIL(
"RangeAccrualPricer::floorletRate not implemented");
174 ext::shared_ptr<SmileSection> smilesOnExpiry,
175 ext::shared_ptr<SmileSection> smilesOnPayment,
178 :
correlation_(correlation), withSmile_(withSmile), byCallSpread_(byCallSpread),
179 smilesOnExpiry_(
std::move(smilesOnExpiry)), smilesOnPayment_(
std::move(smilesOnPayment)) {}
187 result += digitalFloater;
195 Real correlation)
const{
196 std::vector<Real> result;
202 const Real driftBeforeFixing =
204 q*lambdaS*lambdaS + p*lambdaS*lambdaT*correlation
205 -0.5*
lambda(U,lambdaS,lambdaT)*
lambda(U,lambdaS,lambdaT);
208 result.push_back(driftBeforeFixing);
209 result.push_back(driftAfterFixing);
217 std::vector<Real> result;
222 const Real lambdaBeforeFixing =
q*lambdaS + p*lambdaT;
223 const Real lambdaAfterFixing = lambdaT;
225 result.push_back(lambdaBeforeFixing);
226 result.push_back(lambdaAfterFixing);
233 Real correlation)
const{
240 const Real driftBeforeFixing =
242 q*lambdaS*lambdaS + p*lambdaS*lambdaT*correlation;
245 if(
startTime_ > 0){result = driftBeforeFixing;}
246 else {result = driftAfterFixing;}
259 if(
startTime_ > 0){result =
q*lambdaS + p*lambdaT;}
260 else {result = lambdaT;}
269 Real correlation)
const{
276 const Real driftBeforeFixing =
278 2*
q*lambdaS + p*lambdaT*correlation;
279 const Real driftAfterFixing = 0.;
281 if(
startTime_ > 0){result = driftBeforeFixing;}
282 else {result = driftAfterFixing;}
300 Real correlation)
const{
307 const Real driftBeforeFixing =
309 + p*lambdaS*correlation;
312 if(
startTime_ > 0){result = driftBeforeFixing;}
313 else {result = driftAfterFixing;}
332 Real deflator)
const{
333 const Real lowerPrice =
digitalPrice(lowerTrigger, initialValue, expiry, deflator);
334 const Real upperPrice =
digitalPrice(upperTrigger, initialValue, expiry, deflator);
335 const Real result = lowerPrice - upperPrice;
337 "RangeAccrualPricerByBgm::digitalRangePrice:\n digitalPrice("<<upperTrigger<<
338 "): "<<upperPrice<<
" > digitalPrice("<<lowerTrigger<<
"): "<<lowerPrice);
345 Real deflator)
const {
346 Real result = deflator;
359 Real deflator)
const {
378 const Real result = deflator*phi(d2);
381 "RangeAccrualPricerByBgm::digitalPriceWithoutSmile: result< 0. Result:"<<result);
383 "RangeAccrualPricerByBgm::digitalPriceWithoutSmile: result/deflator > 1. Ratio: "
384 << result/deflator <<
" result: " << result<<
" deflator: " << deflator);
392 Real deflator)
const {
397 const Real previousStrike = strike -
eps_/2;
403 const Real previousVariance = std::max(
startTime_, 0.)*lambdaU[0]*lambdaU[0]+
404 std::min(expiry-
startTime_, expiry)*lambdaU[1]*lambdaU[1];
409 const Real previousAdjustment = std::exp(std::max(
startTime_, 0.)*muU[0] +
411 const Real previousForward = initialValue * previousAdjustment ;
414 const Real nextStrike = strike +
eps_/2;
419 const Real nextVariance = std::max(
startTime_, 0.)*lambdaU[0]*lambdaU[0]+
420 std::min(expiry-
startTime_, expiry)*lambdaU[1]*lambdaU[1];
423 const Real nextAdjustment = std::exp(std::max(
startTime_, 0.)*muU[0] +
425 const Real nextForward = initialValue * nextAdjustment ;
427 result =
callSpreadPrice(previousForward,nextForward,previousStrike, nextStrike,
428 deflator, previousVariance, nextVariance);
437 "RangeAccrualPricerByBgm::digitalPriceWithSmile: result< 0 Result:"<<result);
439 "RangeAccrualPricerByBgm::digitalPriceWithSmile: result/deflator > 1. Ratio: "
440 << result/deflator <<
" result: " << result<<
" deflator: " << deflator);
448 Real deflator)
const {
450 const Real previousStrike = strike -
eps_/2;
451 const Real nextStrike = strike +
eps_/2;
470 std::vector<Real> lambdasOverPeriodU =
lambdasOverPeriod(expiry, lambdaS, lambdaT);
475 std::min(expiry-
startTime_, expiry)*lambdasOverPeriodU[1]*lambdasOverPeriodU[1];
477 const Real forwardAdjustment = std::exp(std::max(
startTime_, 0.)*muU[0] +
479 const Real forwardAdjusted = forward * forwardAdjustment;
483 const Real sqrtOfTimeToExpiry = (std::max(
startTime_, 0.)*lambdasOverPeriodU[0] +
484 std::min(expiry-
startTime_, expiry)*lambdasOverPeriodU[1])*
489 Real result = - forwardAdjusted*psi(d1)*sqrtOfTimeToExpiry*derLambdaDerK ;
495 "RangeAccrualPricerByBgm::smileCorrection: abs(result/deflator) > 1. Ratio: "
496 << result/deflator <<
" result: " << result<<
" deflator: " << deflator);
502 Real previousForward,
507 Real previousVariance,
508 Real nextVariance)
const{
509 const Real nextCall =
511 const Real previousCall =
514 QL_ENSURE(nextCall <previousCall,"RangeAccrualPricerByBgm::callSpreadPrice: nextCall > previousCall
"
515 "\
n nextCall: strike :
" << nextStrike << ";
variance:
" << nextVariance <<
516 " adjusted initial value
" << nextForward <<
517 "\
n previousCall: strike :
" << previousStrike << ";
variance:
" << previousVariance <<
518 " adjusted initial value
" << previousForward );
520 const Real result = (previousCall-nextCall)/(nextStrike-previousStrike);
526 RangeAccrualLeg::RangeAccrualLeg(Schedule schedule, ext::shared_ptr<IborIndex> index)
527 : schedule_(std::move(schedule)), index_(std::move(index)) {}
529 RangeAccrualLeg& RangeAccrualLeg::withNotionals(Real notional) {
530 notionals_ = std::vector<Real>(1,notional);
534 RangeAccrualLeg& RangeAccrualLeg::withNotionals(
535 const std::vector<Real>& notionals) {
536 notionals_ = notionals;
540 RangeAccrualLeg& RangeAccrualLeg::withPaymentDayCounter(
541 const DayCounter& dayCounter) {
542 paymentDayCounter_ = dayCounter;
546 RangeAccrualLeg& RangeAccrualLeg::withPaymentAdjustment(
547 BusinessDayConvention convention) {
548 paymentAdjustment_ = convention;
552 RangeAccrualLeg& RangeAccrualLeg::withFixingDays(Natural fixingDays) {
553 fixingDays_ = std::vector<Natural>(1,fixingDays);
557 RangeAccrualLeg& RangeAccrualLeg::withFixingDays(
558 const std::vector<Natural>& fixingDays) {
559 fixingDays_ = fixingDays;
563 RangeAccrualLeg& RangeAccrualLeg::withGearings(Real gearing) {
564 gearings_ = std::vector<Real>(1,gearing);
568 RangeAccrualLeg& RangeAccrualLeg::withGearings(
569 const std::vector<Real>& gearings) {
570 gearings_ = gearings;
574 RangeAccrualLeg& RangeAccrualLeg::withSpreads(Spread spread) {
575 spreads_ = std::vector<Spread>(1,spread);
579 RangeAccrualLeg& RangeAccrualLeg::withSpreads(
580 const std::vector<Spread>& spreads) {
585 RangeAccrualLeg& RangeAccrualLeg::withLowerTriggers(Rate trigger) {
586 lowerTriggers_ = std::vector<Rate>(1,trigger);
590 RangeAccrualLeg& RangeAccrualLeg::withLowerTriggers(
591 const std::vector<Rate>& triggers) {
592 lowerTriggers_ = triggers;
596 RangeAccrualLeg& RangeAccrualLeg::withUpperTriggers(Rate trigger) {
597 upperTriggers_ = std::vector<Rate>(1,trigger);
601 RangeAccrualLeg& RangeAccrualLeg::withUpperTriggers(
602 const std::vector<Rate>& triggers) {
603 upperTriggers_ = triggers;
607 RangeAccrualLeg& RangeAccrualLeg::withObservationTenor(
608 const Period& tenor) {
609 observationTenor_ = tenor;
613 RangeAccrualLeg& RangeAccrualLeg::withObservationConvention(
614 BusinessDayConvention convention) {
615 observationConvention_ = convention;
619 RangeAccrualLeg::operator Leg() const {
621 QL_REQUIRE(!notionals_.empty(), "no notional given
");
623 Size n = schedule_.size()-1;
624 QL_REQUIRE(notionals_.size() <= n,
625 "too many nominals (
" << notionals_.size() <<
626 "), only
" << n << " required
");
627 QL_REQUIRE(fixingDays_.size() <= n,
628 "too many fixingDays (
" << fixingDays_.size() <<
629 "), only
" << n << " required
");
630 QL_REQUIRE(gearings_.size()<=n,
631 "too many gearings (
" << gearings_.size() <<
632 "), only
" << n << " required
");
633 QL_REQUIRE(spreads_.size()<=n,
634 "too many spreads (
" << spreads_.size() <<
635 "), only
" << n << " required
");
636 QL_REQUIRE(lowerTriggers_.size()<=n,
637 "too many lowerTriggers (
" << lowerTriggers_.size() <<
638 "), only
" << n << " required
");
639 QL_REQUIRE(upperTriggers_.size()<=n,
640 "too many upperTriggers (
" << upperTriggers_.size() <<
641 "), only
" << n << " required
");
645 // the following is not always correct
646 Calendar calendar = schedule_.calendar();
648 Date refStart, start, refEnd, end;
650 std::vector<ext::shared_ptr<Schedule> > observationsSchedules;
652 for (Size i=0; i<n; ++i) {
653 refStart = start = schedule_.date(i);
654 refEnd = end = schedule_.date(i+1);
655 paymentDate = calendar.adjust(end, paymentAdjustment_);
656 if (i==0 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1)) {
657 BusinessDayConvention bdc = schedule_.businessDayConvention();
658 refStart = calendar.adjust(end - schedule_.tenor(), bdc);
660 if (i==n-1 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1)) {
661 BusinessDayConvention bdc = schedule_.businessDayConvention();
662 refEnd = calendar.adjust(start + schedule_.tenor(), bdc);
664 if (detail::get(gearings_, i, 1.0) == 0.0) { // fixed coupon
665 leg.push_back(ext::shared_ptr<CashFlow>(new
666 FixedRateCoupon(paymentDate,
667 detail::get(notionals_, i, Null<Real>()),
668 detail::get(spreads_, i, 0.0),
670 start, end, refStart, refEnd)));
671 } else { // floating coupon
672 observationsSchedules.push_back(
673 ext::make_shared<Schedule>(start, end,
674 observationTenor_, calendar,
675 observationConvention_,
676 observationConvention_,
677 DateGeneration::Forward, false));
679 leg.push_back(ext::shared_ptr<CashFlow>(new
680 RangeAccrualFloatersCoupon(
682 detail::get(notionals_, i, Null<Real>()),
685 detail::get(fixingDays_, i, 2),
687 detail::get(gearings_, i, 1.0),
688 detail::get(spreads_, i, 0.0),
690 observationsSchedules.back(),
691 detail::get(lowerTriggers_, i, Null<Rate>()),
692 detail::get(upperTriggers_, i, Null<Rate>()))));
Cash flow vector builders.
degenerate base class for the Acyclic Visitor pattern
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
virtual Real nominal() const
Date date() const override
Time accrualPeriod() const
accrual period as fraction of year
Cumulative normal distribution function.
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
base floating-rate coupon class
Natural fixingDays() const
fixing days
void accept(AcyclicVisitor &) override
Real gearing() const
index gearing, i.e. multiplicative coefficient for the index
DayCounter dayCounter() const override
day counter for accrual calculation
virtual Rate indexFixing() const
fixing of the underlying index
const ext::shared_ptr< InterestRateIndex > & index() const
floating index
Spread spread() const
spread paid over the fixing of the underlying index
virtual Real swapletPrice() const =0
Shared handle to an observable.
Normal distribution function.
std::vector< Real > observationTimes_
Real upperTrigger() const
Real lowerTrigger() const
const std::vector< Real > & observationTimes() const
std::vector< Date > observationDates_
Real priceWithoutOptionality(const Handle< YieldTermStructure > &discountCurve) const
void accept(AcyclicVisitor &) override
Size observationsNo() const
ext::shared_ptr< Schedule > observationsSchedule() const
const ext::shared_ptr< Schedule > observationsSchedule_
RangeAccrualFloatersCoupon(const Date &paymentDate, Real nominal, const ext::shared_ptr< IborIndex > &index, const Date &startDate, const Date &endDate, Natural fixingDays, const DayCounter &dayCounter, Real gearing, Rate spread, const Date &refPeriodStart, const Date &refPeriodEnd, ext::shared_ptr< Schedule > observationsSchedule, Real lowerTrigger, Real upperTrigger)
RangeAccrualPricerByBgm(Real correlation, ext::shared_ptr< SmileSection > smilesOnExpiry, ext::shared_ptr< SmileSection > smilesOnPayment, bool withSmile, bool byCallSpread)
Real drift(Real U, Real lambdaS, Real lambdaT, Real correlation) const
std::vector< Real > driftsOverPeriod(Real U, Real lambdaS, Real lambdaT, Real correlation) const
Real derDriftDerLambdaS(Real U, Real lambdaS, Real lambdaT, Real correlation) const
Real digitalRangePrice(Real lowerTrigger, Real upperTrigger, Real initialValue, Real expiry, Real deflator) const
Real derDriftDerLambdaT(Real U, Real lambdaS, Real lambdaT, Real correlation) const
Real callSpreadPrice(Real previousInitialValue, Real nextInitialValue, Real previousStrike, Real nextStrike, Real deflator, Real previousVariance, Real nextVariance) const
ext::shared_ptr< SmileSection > smilesOnPayment_
Real derLambdaDerLambdaT(Real U) const
Real lambda(Real U, Real lambdaS, Real lambdaT) const
Real derLambdaDerLambdaS(Real U) const
std::vector< Real > lambdasOverPeriod(Real U, Real lambdaS, Real lambdaT) const
ext::shared_ptr< SmileSection > smilesOnExpiry_
Real digitalPriceWithSmile(Real strike, Real initialValue, Real expiry, Real deflator) const
Real smileCorrection(Real strike, Real initialValue, Real expiry, Real deflator) const
Real digitalPriceWithoutSmile(Real strike, Real initialValue, Real expiry, Real deflator) const
Real swapletPrice() const override
Real digitalPrice(Real strike, Real initialValue, Real expiry, Real deflator) const
std::vector< Real > observationTimes_
Real capletPrice(Rate effectiveCap) const override
Rate floorletRate(Rate effectiveFloor) const override
std::vector< Real > initialValues_
void initialize(const FloatingRateCoupon &coupon) override
const RangeAccrualFloatersCoupon * coupon_
Real floorletPrice(Rate effectiveFloor) const override
Rate swapletRate() const override
Rate capletRate(Rate effectiveCap) const override
Visitor for a specific class
virtual void visit(T &)=0
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
LinearInterpolation variance
unsigned QL_INTEGER Natural
positive integer
QL_INTEGER Integer
integer number
std::size_t Size
size of a container
base class for Inter-Bank-Offered-Rate indexes
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)
normal, cumulative and inverse cumulative distributions
ext::shared_ptr< YieldTermStructure > q
ext::shared_ptr< BlackVolTermStructure > v
Interest-rate term structure.