public InterpolatedPiecewiseZeroSpreadedTermStructure(Handle <YieldTermStructure> h, List <Handle <Quote> > spreads, List <Date> dates, Compounding compounding = Compounding.Continuous, Frequency frequency = Frequency.NoFrequency, DayCounter dc = default(DayCounter), Interpolator factory = default(Interpolator)) { originalCurve_ = h; spreads_ = spreads; dates_ = dates; times_ = new InitializedList <double>(dates.Count); spreadValues_ = new InitializedList <double>(dates.Count); compounding_ = compounding; frequency_ = frequency; dc_ = dc ?? new DayCounter(); factory_ = factory ?? FastActivator <Interpolator> .Create(); Utils.QL_REQUIRE(!spreads_.empty(), () => "no spreads given"); Utils.QL_REQUIRE(spreads_.Count == dates_.Count, () => "spread and date vector have different sizes"); originalCurve_.registerWith(update); for (int i = 0; i < spreads_.Count; i++) { spreads_[i].registerWith(update); } if (!originalCurve_.empty()) { updateInterpolation(); } }
public virtual void setCapletVolatility(Handle <YoYOptionletVolatilitySurface> capletVol) { Utils.QL_REQUIRE(!capletVol.empty(), () => "empty capletVol handle"); capletVol_ = capletVol; capletVol_.registerWith(update); }
// Instrument interface public override void calculate() { if (discountCurve_.empty()) { throw new ArgumentException("no discounting term structure set"); } results_.value = results_.cash = 0; results_.errorEstimate = null; results_.legNPV = new InitializedList <double?>(arguments_.legs.Count); results_.legBPS = new InitializedList <double?>(arguments_.legs.Count); List <double?> startDiscounts = new InitializedList <double?>(arguments_.legs.Count); for (int i = 0; i < arguments_.legs.Count; ++i) { results_.legNPV[i] = arguments_.payer[i] * CashFlows.npv(arguments_.legs[i], discountCurve_); results_.legBPS[i] = arguments_.payer[i] * CashFlows.bps(arguments_.legs[i], discountCurve_); results_.value += results_.legNPV[i]; results_.cash += arguments_.payer[i] * CashFlows.cash(arguments_.legs[i]); try { Date d = CashFlows.startDate(arguments_.legs[i]); startDiscounts[i] = discountCurve_.link.discount(d); } catch { startDiscounts[i] = null; } } results_.additionalResults.Add("startDiscounts", startDiscounts); }
protected SwaptionVolatilityCube(Handle <SwaptionVolatilityStructure> atmVol, List <Period> optionTenors, List <Period> swapTenors, List <double> strikeSpreads, List <List <Handle <Quote> > > volSpreads, SwapIndex swapIndexBase, SwapIndex shortSwapIndexBase, bool vegaWeightedSmileFit) : base(optionTenors, swapTenors, 0, atmVol.link.calendar(), atmVol.link.businessDayConvention(), atmVol.link.dayCounter()) { atmVol_ = atmVol; nStrikes_ = strikeSpreads.Count; strikeSpreads_ = strikeSpreads; localStrikes_ = new InitializedList <double>(nStrikes_); localSmile_ = new List <double>(nStrikes_); volSpreads_ = volSpreads; swapIndexBase_ = swapIndexBase; shortSwapIndexBase_ = shortSwapIndexBase; vegaWeightedSmileFit_ = vegaWeightedSmileFit; Utils.QL_REQUIRE(!atmVol_.empty(), () => "atm vol handle not linked to anything"); for (int i = 1; i < nStrikes_; ++i) { Utils.QL_REQUIRE(strikeSpreads_[i - 1] < strikeSpreads_[i], () => "non increasing strike spreads: " + i + " is " + strikeSpreads_[i - 1] + ", " + (i + 1) + " is " + strikeSpreads_[i]); } Utils.QL_REQUIRE(!volSpreads_.empty(), () => "empty vol spreads matrix"); Utils.QL_REQUIRE(nOptionTenors_ * nSwapTenors_ == volSpreads_.Count, () => "mismatch between number of option tenors * swap tenors (" + nOptionTenors_ * nSwapTenors_ + ") and number of rows (" + volSpreads_.Count + ")"); for (int i = 0; i < volSpreads_.Count; i++) { Utils.QL_REQUIRE(nStrikes_ == volSpreads_[i].Count, () => "mismatch between number of strikes (" + nStrikes_ + ") and number of columns (" + volSpreads_[i].Count + ") in the " + (i + 1) + " row"); } atmVol_.registerWith(update); atmVol_.link.enableExtrapolation(); swapIndexBase_.registerWith(update); shortSwapIndexBase_.registerWith(update); Utils.QL_REQUIRE(shortSwapIndexBase_.tenor() < swapIndexBase_.tenor(), () => "short index tenor (" + shortSwapIndexBase_.tenor() + ") is not less than index tenor (" + swapIndexBase_.tenor() + ")"); registerWithVolatilitySpread(); Settings.registerWith(update); evaluationDate_ = Settings.evaluationDate(); }
public IborCouponPricer(Handle <OptionletVolatilityStructure> v) { capletVol_ = v; if (!capletVol_.empty()) { capletVol_.registerWith(update); } }
public double forecastFixing(Date d1, Date d2, double t) { Utils.QL_REQUIRE(!termStructure_.empty(), () => "null term structure set to this instance of " + name()); double disc1 = termStructure_.link.discount(d1); double disc2 = termStructure_.link.discount(d2); return((disc1 / disc2 - 1.0) / t); }
protected override void performCalculations() { if (quote_.empty()) { throw new ApplicationException("null quote set"); } NPV_ = quote_.link.value(); }
public virtual void setCapletVolatility(Handle <YoYOptionletVolatilitySurface> capletVol) { if (capletVol.empty()) { throw new ApplicationException("empty capletVol handle"); } capletVol_ = capletVol; capletVol_.registerWith(update); }
protected override double forecastFixing(Date fixingDate) { if (termStructure_.empty()) { throw new ApplicationException("null term structure set to this instance of " + name()); } Date start = fixingCalendar_.advance(fixingDate, 1, TimeUnit.Days); Date end = maturityDate(start); return(termStructure_.link.forwardRate(start, end, dayCounter_, Compounding.Simple).rate()); }
public SpreadFittingMethod(FittedBondDiscountCurve.FittingMethod method, Handle <YieldTermStructure> discountCurve) : base(method != null ? method.constrainAtZero() : true, method != null ? method.weights() : null, method != null ? method.optimizationMethod() : null) { method_ = method; discountingCurve_ = discountCurve; Utils.QL_REQUIRE(method != null, () => "Fitting method is empty"); Utils.QL_REQUIRE(!discountingCurve_.empty(), () => "Discounting curve cannot be empty"); }
public void setCapletVolatility(Handle <OptionletVolatilityStructure> v) { capletVol_.unregisterWith(update); capletVol_ = v; if (!capletVol_.empty()) { capletVol_.registerWith(update); } update(); }
protected override void performCalculations() { if (discountCurve_.empty()) { throw new ApplicationException("no discounting term structure set to Forward"); } ForwardTypePayoff ftpayoff = payoff_ as ForwardTypePayoff; double fwdValue = forwardValue(); NPV_ = ftpayoff.value(fwdValue) * discountCurve_.link.discount(maturityDate_); }
public CPICouponPricer(Handle <CPIVolatilitySurface> capletVol = null) { if (capletVol == null) { capletVol = new Handle <CPIVolatilitySurface>(); } capletVol_ = capletVol; if (!capletVol_.empty()) { capletVol_.registerWith(update); } }
public IborIndex(string familyName, Period tenor, int settlementDays, Currency currency, Calendar fixingCalendar, BusinessDayConvention convention, bool endOfMonth, DayCounter dayCounter, Handle <YieldTermStructure> h) : base(familyName, tenor, settlementDays, currency, fixingCalendar, dayCounter) { convention_ = convention; termStructure_ = h; endOfMonth_ = endOfMonth; // observer interface if (!termStructure_.empty()) { termStructure_.registerWith(update); } }
protected override double forecastFixing(Date fixingDate) { if (termStructure_.empty()) { throw new ArgumentException("null term structure set to this instance of " + name()); } Date fixingValueDate = valueDate(fixingDate); Date endValueDate = maturityDate(fixingValueDate); double fixingDiscount = termStructure_.link.discount(fixingValueDate); double endDiscount = termStructure_.link.discount(endValueDate); double fixingPeriod = dayCounter().yearFraction(fixingValueDate, endValueDate); return((fixingDiscount / endDiscount - 1.0) / fixingPeriod); }
public override void update() { if (!curve1_.empty() && !curve2_.empty()) { base.update(); enableExtrapolation(curve1_.link.allowsExtrapolation() && curve2_.link.allowsExtrapolation()); } else { /* The implementation inherited from YieldTermStructure * asks for our reference date, which we don't have since * the original curve is still not set. Therefore, we skip * over that and just call the base-class behavior. */ base.update(); } }
protected new void update() { if (!originalCurve_.empty()) { updateInterpolation(); base.update(); } else { /* The implementation inherited from YieldTermStructure * asks for our reference date, which we don't have since * the original curve is still not set. Therefore, we skip * over that and just call the base-class behavior. */ base.update(); } }
public override void calculate() { if (discountCurve_.empty()) { throw new ArgumentException("no discounting term structure set"); } results_.value = results_.cash = 0; results_.errorEstimate = null; results_.legNPV = new InitializedList <double?>(arguments_.legs.Count); for (int i = 0; i < arguments_.legs.Count; ++i) { results_.legNPV[i] = arguments_.payer[i] * CashFlows.npv(arguments_.legs[i], discountCurve_); results_.value += results_.legNPV[i]; results_.cash += arguments_.payer[i] * CashFlows.cash(arguments_.legs[i]); } }
public VannaVolgaDoubleBarrierEngine(Handle <DeltaVolQuote> atmVol, Handle <DeltaVolQuote> vol25Put, Handle <DeltaVolQuote> vol25Call, Handle <Quote> spotFX, Handle <YieldTermStructure> domesticTS, Handle <YieldTermStructure> foreignTS, GetOriginalEngine getEngine, bool adaptVanDelta = false, double bsPriceWithSmile = 0.0, int series = 5) : base() { atmVol_ = atmVol; vol25Put_ = vol25Put; vol25Call_ = vol25Call; T_ = atmVol_.link.maturity(); spotFX_ = spotFX; domesticTS_ = domesticTS; foreignTS_ = foreignTS; adaptVanDelta_ = adaptVanDelta; bsPriceWithSmile_ = bsPriceWithSmile; series_ = series; getOriginalEngine_ = getEngine; Utils.QL_REQUIRE(vol25Put_.link.delta() == -0.25, () => "25 delta put is required by vanna volga method"); Utils.QL_REQUIRE(vol25Call_.link.delta() == 0.25, () => "25 delta call is required by vanna volga method"); Utils.QL_REQUIRE(vol25Put_.link.maturity() == vol25Call_.link.maturity() && vol25Put_.link.maturity() == atmVol_.link.maturity(), () => "Maturity of 3 vols are not the same"); Utils.QL_REQUIRE(!domesticTS_.empty(), () => "domestic yield curve is not defined"); Utils.QL_REQUIRE(!foreignTS_.empty(), () => "foreign yield curve is not defined"); atmVol_.registerWith(update); vol25Put_.registerWith(update); vol25Call_.registerWith(update); spotFX_.registerWith(update); domesticTS_.registerWith(update); foreignTS_.registerWith(update); }
public CompositeZeroYieldStructure(Handle <YieldTermStructure> h1, Handle <YieldTermStructure> h2, Func <double, double, double> f, Compounding comp = Compounding.Continuous, Frequency freq = Frequency.NoFrequency) { curve1_ = h1; curve2_ = h2; f_ = f; comp_ = comp; freq_ = freq; if (!curve1_.empty() && !curve2_.empty()) { enableExtrapolation(curve1_.link.allowsExtrapolation() && curve2_.link.allowsExtrapolation()); } curve1_.registerWith(update); curve2_.registerWith(update); }
public override void calculate() { Utils.QL_REQUIRE(!discountCurve_.empty(), "discounting term structure handle is empty"); results_.valuationDate = discountCurve_.link.referenceDate(); bool includeRefDateFlows = includeSettlementDateFlows_.HasValue ? includeSettlementDateFlows_.Value : Settings.includeReferenceDateEvents; results_.value = CashFlows.npv(arguments_.cashflows, discountCurve_, includeRefDateFlows, results_.valuationDate, results_.valuationDate); results_.cash = CashFlows.cash(arguments_.cashflows, arguments_.settlementDate); // a bond's cashflow on settlement date is never taken into // account, so we might have to play it safe and recalculate if (!includeRefDateFlows && results_.valuationDate == arguments_.settlementDate) { // same parameters as above, we can avoid another call results_.settlementValue = results_.value; } else { // no such luck results_.settlementValue = CashFlows.npv(arguments_.cashflows, discountCurve_, false, arguments_.settlementDate, arguments_.settlementDate); } }
///////////////////////////////////////////////////// //! FuturesRateHelper inspectors public double convexityAdjustment() { return(convAdj_.empty() ? 0.0 : convAdj_.link.value()); }
public override double swapletRate() { OvernightIndex index = coupon_.index() as OvernightIndex; List <Date> fixingDates = coupon_.fixingDates(); List <double> dt = coupon_.dt(); int n = dt.Count(); int i = 0; double compoundFactor = 1.0; // already fixed part Date today = Settings.evaluationDate(); while (fixingDates[i] < today && i < n) { // rate must have been fixed double pastFixing = IndexManager.instance().getHistory( index.name()).value()[fixingDates[i]]; if (pastFixing == default(double)) { throw new ApplicationException("Missing " + index.name() + " fixing for " + fixingDates[i].ToString()); } compoundFactor *= (1.0 + pastFixing * dt[i]); ++i; } // today is a border case if (fixingDates[i] == today && i < n) { // might have been fixed try { double pastFixing = IndexManager.instance().getHistory( index.name()).value()[fixingDates[i]]; if (pastFixing != default(double)) { compoundFactor *= (1.0 + pastFixing * dt[i]); ++i; } else { ; // fall through and forecast } } catch (Exception e) { ; // fall through and forecast } } // forward part using telescopic property in order // to avoid the evaluation of multiple forward fixings if (i < n) { Handle <YieldTermStructure> curve = index.forwardingTermStructure(); if (curve.empty()) { throw new ArgumentException("null term structure set to this instance of" + index.name()); } List <Date> dates = coupon_.valueDates(); double startDiscount = curve.link.discount(dates[i]); double endDiscount = curve.link.discount(dates[n]); compoundFactor *= startDiscount / endDiscount; } double rate = (compoundFactor - 1.0) / coupon_.accrualPeriod(); return(coupon_.gearing() * rate + coupon_.spread()); }
public OvernightIndexedSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { Date refDate = Settings.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = calendar_.adjust(refDate); Date spotDate = calendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = calendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = calendar_.adjust(startDate, BusinessDayConvention.Following); } } // OIS end of month default bool usedEndOfMonth = isDefaultEOM_ ? calendar_.isEndOfMonth(startDate) : endOfMonth_; Date endDate = terminationDate_; if (endDate == null) { if (usedEndOfMonth) { endDate = calendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, usedEndOfMonth); } else { endDate = startDate + swapTenor_; } } Schedule schedule = new Schedule(startDate, endDate, new Period(paymentFrequency_), calendar_, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, rule_, usedEndOfMonth); double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { OvernightIndexedSwap temp = new OvernightIndexedSwap(type_, nominal_, schedule, 0.0, // fixed rate fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + overnightIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } OvernightIndexedSwap ois = new OvernightIndexedSwap(type_, nominal_, schedule, usedFixedRate.Value, fixedDayCount_, overnightIndex_, overnightSpread_); if (engine_ == null) { Handle <YieldTermStructure> disc = overnightIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); ois.setPricingEngine(engine); } else { ois.setPricingEngine(engine_); } return(ois); }
//! set up the interpolations for capPrice_ and floorPrice_ //! since we know ATM, and we have single flows, //! we can use put/call parity to extend the surfaces //! across all strikes protected override void performCalculations() { allStrikes_ = new List <double>(); int nMat = cfMaturities_.Count, ncK = cStrikes_.Count, nfK = fStrikes_.Count, nK = ncK + nfK; Matrix cP = new Matrix(nK, nMat), fP = new Matrix(nK, nMat); Handle <ZeroInflationTermStructure> zts = zii_.link.zeroInflationTermStructure(); Handle <YieldTermStructure> yts = this.nominalTermStructure(); Utils.QL_REQUIRE(!zts.empty(), () => "Zts is empty!!!"); Utils.QL_REQUIRE(!yts.empty(), () => "Yts is empty!!!"); for (int i = 0; i < nfK; i++) { allStrikes_.Add(fStrikes_[i]); for (int j = 0; j < nMat; j++) { Period mat = cfMaturities_[j]; double df = yts.link.discount(cpiOptionDateFromTenor(mat)); double atm_quote = zts.link.zeroRate(cpiOptionDateFromTenor(mat)); double atm = Math.Pow(1.0 + atm_quote, mat.length()); double S = atm * df; double K_quote = fStrikes_[i] / 100.0; double K = Math.Pow(1.0 + K_quote, mat.length()); cP[i, j] = fPrice_[i, j] + S - K * df; fP[i, j] = fPrice_[i, j]; } } for (int i = 0; i < ncK; i++) { allStrikes_.Add(cStrikes_[i]); for (int j = 0; j < nMat; j++) { Period mat = cfMaturities_[j]; double df = yts.link.discount(cpiOptionDateFromTenor(mat)); double atm_quote = zts.link.zeroRate(cpiOptionDateFromTenor(mat)); double atm = Math.Pow(1.0 + atm_quote, mat.length()); double S = atm * df; double K_quote = cStrikes_[i] / 100.0; double K = Math.Pow(1.0 + K_quote, mat.length()); cP[i + nfK, j] = cPrice_[i, j]; fP[i + nfK, j] = cPrice_[i, j] + K * df - S; } } // copy to store cPriceB_ = cP; fPriceB_ = fP; cfMaturityTimes_ = new List <double>(); for (int i = 0; i < cfMaturities_.Count; i++) { cfMaturityTimes_.Add(timeFromReference(cpiOptionDateFromTenor(cfMaturities_[i]))); } capPrice_ = interpolator2d_.interpolate(cfMaturityTimes_, cfMaturityTimes_.Count, allStrikes_, allStrikes_.Count, cPriceB_); capPrice_.enableExtrapolation(); floorPrice_ = interpolator2d_.interpolate(cfMaturityTimes_, cfMaturityTimes_.Count, allStrikes_, allStrikes_.Count, fPriceB_); floorPrice_.enableExtrapolation(); }
//! \name SwapRateHelper inspectors public double spread() { return(spread_.empty() ? 0.0 : spread_.link.value()); }
public VanillaSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { //int fixingDays = iborIndex_.fixingDays(); Date refDate = Settings.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = floatCalendar_.adjust(refDate); Date spotDate = floatCalendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Following); } } Date endDate = terminationDate_; if (endDate == null) { if (floatEndOfMonth_) { endDate = floatCalendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, floatEndOfMonth_); } else { endDate = startDate + swapTenor_; } } Currency curr = iborIndex_.currency(); Period fixedTenor = null; if (fixedTenor_ != null) { fixedTenor = fixedTenor_; } else { if ((curr == new EURCurrency()) || (curr == new USDCurrency()) || (curr == new CHFCurrency()) || (curr == new SEKCurrency()) || (curr == new GBPCurrency() && swapTenor_ <= new Period(1, TimeUnit.Years))) { fixedTenor = new Period(1, TimeUnit.Years); } else if ((curr == new GBPCurrency() && swapTenor_ > new Period(1, TimeUnit.Years) || (curr == new JPYCurrency()) || (curr == new AUDCurrency() && swapTenor_ >= new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(6, TimeUnit.Months); } else if ((curr == new HKDCurrency() || (curr == new AUDCurrency() && swapTenor_ < new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(3, TimeUnit.Months); } else { Utils.QL_FAIL("unknown fixed leg default tenor for " + curr); } } Schedule fixedSchedule = new Schedule(startDate, endDate, fixedTenor, fixedCalendar_, fixedConvention_, fixedTerminationDateConvention_, fixedRule_, fixedEndOfMonth_, fixedFirstDate_, fixedNextToLastDate_); Schedule floatSchedule = new Schedule(startDate, endDate, floatTenor_, floatCalendar_, floatConvention_, floatTerminationDateConvention_, floatRule_, floatEndOfMonth_, floatFirstDate_, floatNextToLastDate_); DayCounter fixedDayCount = null; if (fixedDayCount_ != null) { fixedDayCount = fixedDayCount_; } else { if (curr == new USDCurrency()) { fixedDayCount = new Actual360(); } else if (curr == new EURCurrency() || curr == new CHFCurrency() || curr == new SEKCurrency()) { fixedDayCount = new Thirty360(Thirty360.Thirty360Convention.BondBasis); } else if (curr == new GBPCurrency() || curr == new JPYCurrency() || curr == new AUDCurrency() || curr == new HKDCurrency()) { fixedDayCount = new Actual365Fixed(); } else { Utils.QL_FAIL("unknown fixed leg day counter for " + curr); } } double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { VanillaSwap temp = new VanillaSwap(type_, nominal_, fixedSchedule, 0.0, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + iborIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } VanillaSwap swap = new VanillaSwap(type_, nominal_, fixedSchedule, usedFixedRate.Value, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); swap.setPricingEngine(engine); } else { swap.setPricingEngine(engine_); } return(swap); }
protected override void performCalculations() { Utils.QL_REQUIRE(!quote_.empty(), () => "null quote set"); NPV_ = quote_.link.value(); }
//! Implemented in order to manage the case of par coupon public override double indexFixing() { #if QL_USE_INDEXED_COUPON return(index_.fixing(fixingDate())); #else if (isInArrears()) { return(index_.fixing(fixingDate())); } else { Date today = Settings.evaluationDate(); Date fixingDate = this.fixingDate(); TimeSeries <double> fixings = IndexManager.instance().getHistory(index_.name()).value(); if (fixings.ContainsKey(fixingDate)) { return(fixings[fixingDate]); } else { if (fixingDate < today) { // must have been fixed if (IndexManager.MissingPastFixingCallBack == null) { throw new ArgumentException("Missing " + index_.name() + " fixing for " + fixingDate); } else { // try to load missing fixing from external source double fixing = IndexManager.MissingPastFixingCallBack(index_, fixingDate); // add to history index_.addFixing(fixingDate, fixing); return(fixing); } } if (fixingDate == today) { // might have been fixed // fall through and forecast } } // forecast: 0) forecasting curve Handle <YieldTermStructure> termStructure = iborIndex_.forwardingTermStructure(); if (termStructure.empty()) { throw new ApplicationException("null term structure set to this instance of " + index_.name()); } // forecast: 1) startDiscount Date fixingValueDate = index_.fixingCalendar().advance(fixingDate, index_.fixingDays(), TimeUnit.Days); double startDiscount = termStructure.link.discount(fixingValueDate); // forecast: 2) endDiscount Date nextFixingDate = index_.fixingCalendar().advance(accrualEndDate_, -fixingDays, TimeUnit.Days); Date nextFixingValueDate = index_.fixingCalendar().advance(nextFixingDate, index_.fixingDays(), TimeUnit.Days); double endDiscount = termStructure.link.discount(nextFixingValueDate); // forecast: 3) spanningTime double spanningTime = index_.dayCounter().yearFraction(fixingValueDate, nextFixingValueDate); if (!(spanningTime > 0.0)) { throw new ApplicationException("cannot calculate forward rate between " + fixingValueDate + " and " + nextFixingValueDate + ": non positive time using " + index_.dayCounter().name()); } // forecast: 4) implied fixing return((startDiscount / endDiscount - 1.0) / spanningTime); } #endif }
// Instrument interface public override void calculate() { Utils.QL_REQUIRE(!discountCurve_.empty(), () => "discounting term structure handle is empty"); results_.value = results_.cash = 0; results_.errorEstimate = null; Date refDate = discountCurve_.link.referenceDate(); Date settlementDate = settlementDate_; if (settlementDate_ == null) { settlementDate = refDate; } else { Utils.QL_REQUIRE(settlementDate >= refDate, () => "settlement date (" + settlementDate + ") before " + "discount curve reference date (" + refDate + ")"); } results_.valuationDate = npvDate_; if (npvDate_ == null) { results_.valuationDate = refDate; } else { Utils.QL_REQUIRE(npvDate_ >= refDate, () => "npv date (" + npvDate_ + ") before " + "discount curve reference date (" + refDate + ")"); } results_.npvDateDiscount = discountCurve_.link.discount(results_.valuationDate); int n = arguments_.legs.Count; results_.legNPV = new InitializedList <double?>(n); results_.legBPS = new InitializedList <double?>(n); results_.startDiscounts = new InitializedList <double?>(n); results_.endDiscounts = new InitializedList <double?>(n); bool includeRefDateFlows = includeSettlementDateFlows_.HasValue ? includeSettlementDateFlows_.Value : Settings.includeReferenceDateEvents; for (int i = 0; i < n; ++i) { try { YieldTermStructure discount_ref = discountCurve_.currentLink(); double npv = 0, bps = 0; CashFlows.npvbps(arguments_.legs[i], discount_ref, includeRefDateFlows, settlementDate, results_.valuationDate, out npv, out bps); results_.legNPV[i] = npv * arguments_.payer[i]; results_.legBPS[i] = bps * arguments_.payer[i]; if (!arguments_.legs[i].empty()) { Date d1 = CashFlows.startDate(arguments_.legs[i]); if (d1 >= refDate) { results_.startDiscounts[i] = discountCurve_.link.discount(d1); } else { results_.startDiscounts[i] = null; } Date d2 = CashFlows.maturityDate(arguments_.legs[i]); if (d2 >= refDate) { results_.endDiscounts[i] = discountCurve_.link.discount(d2); } else { results_.endDiscounts[i] = null; } } else { results_.startDiscounts[i] = null; results_.endDiscounts[i] = null; } } catch (Exception e) { Utils.QL_FAIL((i + 1) + " leg: " + e.Message); } results_.value += results_.legNPV[i]; } }