/*! Forecasting index values requires an inflation term * structure. The inflation term structure (ITS) defines the * usual lag (not the index). I.e. an ITS is always relatve * to a base date that is earlier than its asof date. This * must be so because indices are available only with a lag. * However, the index availability lag only sets a minimum * lag for the ITS. An ITS may be relative to an earlier * date, e.g. an index may have a 2-month delay in * publication but the inflation swaps may take as their base * the index 3 months before. */ public override double fixing(Date fixingDate, bool forecastTodaysFixing = false) { return(0); }
public override bool isValidFixingDate(Date fixingDate) { return(true); }
public override List <CashFlow> value() { Utils.QL_REQUIRE(!notionals_.empty(), () => "no notional given"); int n = schedule_.Count - 1; List <CashFlow> leg = new List <CashFlow>(n + 1); if (n > 0) { Utils.QL_REQUIRE(!fixedRates_.empty() || !spreads_.empty(), () => "no fixedRates or spreads given"); Date refStart, start, refEnd, end; for (int i = 0; i < n; ++i) { refStart = start = schedule_.date(i); refEnd = end = schedule_.date(i + 1); Date paymentDate = paymentCalendar_.adjust(end, paymentAdjustment_); Date exCouponDate = null; if (exCouponPeriod_ != null) { exCouponDate = exCouponCalendar_.advance(paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_); } if (i == 0 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refStart = schedule_.calendar().adjust(end - schedule_.tenor(), bdc); } if (i == n - 1 && !schedule_.isRegular(i + 1)) { BusinessDayConvention bdc = schedule_.businessDayConvention(); refEnd = schedule_.calendar().adjust(start + schedule_.tenor(), bdc); } if (Utils.Get(fixedRates_, i, 1.0).IsEqual(0.0)) { // fixed coupon leg.Add(new FixedRateCoupon(paymentDate, Utils.Get(notionals_, i, 0.0), Utils.effectiveFixedRate(spreads_, caps_, floors_, i), paymentDayCounter_, start, end, refStart, refEnd, exCouponDate)); } else { // zero inflation coupon if (Utils.noOption(caps_, floors_, i)) { // just swaplet CPICoupon coup; coup = new CPICoupon(baseCPI_, // all have same base for ratio paymentDate, Utils.Get(notionals_, i, 0.0), start, end, Utils.Get(fixingDays_, i, 0), index_, observationLag_, observationInterpolation_, paymentDayCounter_, Utils.Get(fixedRates_, i, 0.0), Utils.Get(spreads_, i, 0.0), refStart, refEnd, exCouponDate); // in this case you can set a pricer // straight away because it only provides computation - not data CPICouponPricer pricer = new CPICouponPricer(); coup.setPricer(pricer); leg.Add(coup); } else { // cap/floorlet Utils.QL_FAIL("caps/floors on CPI coupons not implemented."); } } } } // in CPI legs you always have a notional flow of some sort Date pDate = paymentCalendar_.adjust(schedule_.date(n), paymentAdjustment_); Date fixingDate = pDate - observationLag_; CashFlow xnl = new CPICashFlow (Utils.Get(notionals_, n, 0.0), index_, new Date(), // is fake, i.e. you do not have one baseCPI_, fixingDate, pDate, subtractInflationNominal_, observationInterpolation_, index_.frequency()); leg.Add(xnl); return(leg); }
// Index interface // The forecastTodaysFixing parameter (required by the Index interface) is currently ignored. public override double fixing(Date fixingDate, bool forecastTodaysFixing = false) { Date today = Settings.Instance.evaluationDate(); Date todayMinusLag = today - availabilityLag_; KeyValuePair <Date, Date> limm = Utils.inflationPeriod(todayMinusLag, frequency_); Date lastFix = limm.Key - 1; Date flatMustForecastOn = lastFix + 1; Date interpMustForecastOn = lastFix + 1 - new Period(frequency_); if (interpolated() && fixingDate >= interpMustForecastOn) { return(forecastFixing(fixingDate)); } if (!interpolated() && fixingDate >= flatMustForecastOn) { return(forecastFixing(fixingDate)); } // four cases with ratio() and interpolated() if (ratio()) { if (interpolated()) { // IS ratio, IS interpolated KeyValuePair <Date, Date> lim = Utils.inflationPeriod(fixingDate, frequency_); Date fixMinus1Y = new NullCalendar().advance(fixingDate, new Period(-1, TimeUnit.Years), BusinessDayConvention.ModifiedFollowing); KeyValuePair <Date, Date> limBef = Utils.inflationPeriod(fixMinus1Y, frequency_); double dp = lim.Value + 1 - lim.Key; double dpBef = limBef.Value + 1 - limBef.Key; double dl = fixingDate - lim.Key; // potentially does not work on 29th Feb double dlBef = fixMinus1Y - limBef.Key; // get the four relevant fixings // recall that they are stored flat for every day double?limFirstFix = IndexManager.Instance.getHistory(name())[lim.Key]; Utils.QL_REQUIRE(limFirstFix != null, () => "Missing " + name() + " fixing for " + lim.Key); double?limSecondFix = IndexManager.Instance.getHistory(name())[lim.Value + 1]; Utils.QL_REQUIRE(limSecondFix != null, () => "Missing " + name() + " fixing for " + lim.Value + 1); double?limBefFirstFix = IndexManager.Instance.getHistory(name())[limBef.Key]; Utils.QL_REQUIRE(limBefFirstFix != null, () => "Missing " + name() + " fixing for " + limBef.Key); double?limBefSecondFix = IndexManager.Instance.getHistory(name())[limBef.Value + 1]; Utils.QL_REQUIRE(limBefSecondFix != null, () => "Missing " + name() + " fixing for " + limBef.Value + 1); double linearNow = limFirstFix.Value + (limSecondFix.Value - limFirstFix.Value) * dl / dp; double linearBef = limBefFirstFix.Value + (limBefSecondFix.Value - limBefFirstFix.Value) * dlBef / dpBef; double wasYES = linearNow / linearBef - 1.0; return(wasYES); } else { // IS ratio, NOT interpolated double?pastFixing = IndexManager.Instance.getHistory(name())[fixingDate]; Utils.QL_REQUIRE(pastFixing != null, () => "Missing " + name() + " fixing for " + fixingDate); Date previousDate = fixingDate - new Period(1, TimeUnit.Years); double?previousFixing = IndexManager.Instance.getHistory(name())[previousDate]; Utils.QL_REQUIRE(previousFixing != null, () => "Missing " + name() + " fixing for " + previousDate); return(pastFixing.Value / previousFixing.Value - 1.0); } } else { // NOT ratio if (interpolated()) { // NOT ratio, IS interpolated KeyValuePair <Date, Date> lim = Utils.inflationPeriod(fixingDate, frequency_); double dp = lim.Value + 1 - lim.Key; double dl = fixingDate - lim.Key; double?limFirstFix = IndexManager.Instance.getHistory(name())[lim.Key]; Utils.QL_REQUIRE(limFirstFix != null, () => "Missing " + name() + " fixing for " + lim.Key); double?limSecondFix = IndexManager.Instance.getHistory(name())[lim.Value + 1]; Utils.QL_REQUIRE(limSecondFix != null, () => "Missing " + name() + " fixing for " + lim.Value + 1); double linearNow = limFirstFix.Value + (limSecondFix.Value - limFirstFix.Value) * dl / dp; return(linearNow); } else { // NOT ratio, NOT interpolated // so just flat double?pastFixing = IndexManager.Instance.getHistory(name())[fixingDate]; Utils.QL_REQUIRE(pastFixing != null, () => "Missing " + name() + " fixing for " + fixingDate); return(pastFixing.Value); } } }
//! utility method, calls indexFixing public double indexObservation(Date onDate) { return(indexFixing(onDate)); }