/*! \warning the forecastTodaysFixing parameter (required by * the Index interface) is currently ignored. */ public override double fixing(Date aFixingDate, bool forecastTodaysFixing = false) { if (!needsForecast(aFixingDate)) { KeyValuePair <Date, Date> lim = Utils.inflationPeriod(aFixingDate, frequency_); Utils.QL_REQUIRE(IndexManager.instance().getHistory(name()).value().ContainsKey(lim.Key), () => "Missing " + name() + " fixing for " + lim.Key); double pastFixing = IndexManager.instance().getHistory(name()).value()[lim.Key]; double theFixing = pastFixing; if (interpolated_) { // fixings stored on first day of every period if (aFixingDate == lim.Key) { // we don't actually need the next fixing theFixing = pastFixing; } else { Utils.QL_REQUIRE(IndexManager.instance().getHistory(name()).value().ContainsKey(lim.Value + 1), () => "Missing " + name() + " fixing for " + (lim.Value + 1)); double pastFixing2 = IndexManager.instance().getHistory(name()).value()[lim.Value + 1]; // now linearly interpolate double daysInPeriod = lim.Value + 1 - lim.Key; theFixing = pastFixing + (pastFixing2 - pastFixing) * (aFixingDate - lim.Key) / daysInPeriod; } } return(theFixing); } else { return(forecastFixing(aFixingDate)); } }
public void addFixings(Dictionary <Date, double> source, bool forceOverwrite) { ObservableValue <TimeSeries <double> > target = IndexManager.instance().getHistory(name()); foreach (Date d in source.Keys) { if (isValidFixingDate(d)) { if (!target.value().ContainsKey(d)) { target.value().Add(d, source[d]); } else if (forceOverwrite) { target.value()[d] = source[d]; } else if (Utils.close(target.value()[d], source[d])) { continue; } else { throw new ArgumentException("Duplicated fixing provided: " + d + ", " + source[d] + " while " + target.value()[d] + " value is already present"); } } else { throw new ArgumentException("Invalid fixing provided: " + d.DayOfWeek + " " + d + ", " + source[d]); } } IndexManager.instance().setHistory(name(), target); }
// Coupon interface public override double rate() { Utils.QL_REQUIRE(underlying_.pricer() != null, () => "pricer not set"); Date fixingDate = underlying_.fixingDate(); Date today = Settings.evaluationDate(); bool enforceTodaysHistoricFixings = Settings.enforcesTodaysHistoricFixings; double underlyingRate = underlying_.rate(); if (fixingDate < today || ((fixingDate == today) && enforceTodaysHistoricFixings)) { // must have been fixed return(underlyingRate + callCsi_ * callPayoff() + putCsi_ * putPayoff()); } if (fixingDate == today) { // might have been fixed double?pastFixing = IndexManager.instance().getHistory((underlying_.index()).name())[fixingDate]; if (pastFixing != null) { return(underlyingRate + callCsi_ * callPayoff() + putCsi_ * putPayoff()); } else { return(underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate()); } } return(underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate()); }
//@} //! \name Coupon interface //@{ public override double rate() { if (underlying_.pricer() == null) { throw new ApplicationException("pricer not set"); } Date fixingDate = underlying_.fixingDate(); Date today = Settings.evaluationDate(); bool enforceTodaysHistoricFixings = Settings.enforcesTodaysHistoricFixings; double underlyingRate = underlying_.rate(); if (fixingDate < today || ((fixingDate == today) && enforceTodaysHistoricFixings)) { // must have been fixed return(underlyingRate + callCsi_ * callPayoff() + putCsi_ * putPayoff()); } if (fixingDate == today) { // might have been fixed double pastFixing = IndexManager.instance().getHistory((underlying_.index()).name()).value()[fixingDate]; if (pastFixing != default(double)) { return(underlyingRate + callCsi_ * callPayoff() + putCsi_ * putPayoff()); } else { return(underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate()); } } return(underlyingRate + callCsi_ * callOptionRate() + putCsi_ * putOptionRate()); }
// Stores historical fixings from a TimeSeries // The dates in the TimeSeries must be the actual calendar dates of the fixings; no settlement days must be used. public void addFixings(TimeSeries <double?> source, bool forceOverwrite = false) { checkNativeFixingsAllowed(); TimeSeries <double?> target = IndexManager.instance().getHistory(name()); foreach (Date d in source.Keys) { if (isValidFixingDate(d)) { if (!target.ContainsKey(d)) { target.Add(d, source[d]); } else if (forceOverwrite) { target[d] = source[d]; } else if (Utils.close(target[d].GetValueOrDefault(), source[d].GetValueOrDefault())) { continue; } else { throw new ArgumentException("Duplicated fixing provided: " + d + ", " + source[d] + " while " + target[d] + " value is already present"); } } else { throw new ArgumentException("Invalid fixing provided: " + d.DayOfWeek + " " + d + ", " + source[d]); } } IndexManager.instance().setHistory(name(), target); }
public double fixing(Date aFixingDate, bool forecastTodaysFixing) { // Stored fixings are always non-interpolated. // If an interpolated fixing is required then // the availability lag + one inflation period // must have passsed to use historical fixings // (because you need the next one to interpolate). // The interpolation is calculated (linearly) on demand. Date today = Settings.evaluationDate(); Date todayMinusLag = today - availabilityLag_; KeyValuePair <Date, Date> lim = Utils.inflationPeriod(todayMinusLag, frequency_); Date historicalFixingKnown = lim.Key - 1; Date fixingDateNeeded = aFixingDate; if (interpolated_) { // need the next one too fixingDateNeeded = fixingDateNeeded + new Period(frequency_); } if (fixingDateNeeded <= historicalFixingKnown) { double?pastFixing = IndexManager.instance().getHistory(name()).value()[aFixingDate]; if (pastFixing == null) { throw new ApplicationException("Missing " + name() + " fixing for " + aFixingDate); } double theFixing = pastFixing.Value; if (interpolated_) { // fixings stored flat & for every day Date fixingDate2 = aFixingDate + new Period(frequency_); double pastFixing2 = IndexManager.instance().getHistory(name()).value()[fixingDate2]; if (pastFixing2 == null) { throw new ApplicationException("Missing " + name() + " fixing for " + fixingDate2); } // now linearly interpolate KeyValuePair <Date, Date> lim2 = Utils.inflationPeriod(aFixingDate, frequency_); double daysInPeriod = lim2.Value + 1 - lim2.Key; theFixing = pastFixing.Value + (pastFixing2 - pastFixing.Value) * (aFixingDate - lim2.Key) / daysInPeriod; } return(theFixing); } else { return(forecastFixing(aFixingDate)); } }
/*! An inflation index may return interpolated * values. These are linearly interpolated * values with act/act convention within a period. * Note that stored "fixings" are always flat (constant) * within a period and interpolated as needed. This * is because interpolation adds an addional availability * lag (because you always need the next period to * give the previous period's value) * and enables storage of the most recent uninterpolated value. */ public InflationIndex(string familyName, Region region, bool revised, bool interpolated, Frequency frequency, Period availabilitiyLag, Currency currency) { familyName_ = familyName; region_ = region; revised_ = revised; interpolated_ = interpolated; frequency_ = frequency; availabilityLag_ = availabilitiyLag; currency_ = currency; Settings.registerWith(update); IndexManager.instance().notifier(name()).registerWith(update); }
protected InterestRateIndex(string familyName, Period tenor, int fixingDays, Currency currency, Calendar fixingCalendar, DayCounter dayCounter) { familyName_ = familyName; tenor_ = tenor; fixingDays_ = fixingDays; currency_ = currency; dayCounter_ = dayCounter; fixingCalendar_ = fixingCalendar; tenor_.normalize(); string res = familyName_; if (tenor_ == new Period(1, TimeUnit.Days)) { if (fixingDays_ == 0) { res += "ON"; } else if (fixingDays_ == 1) { res += "TN"; } else if (fixingDays_ == 2) { res += "SN"; } else { res += tenor_.ToShortString(); } } else { res += tenor_.ToShortString(); } res = res + " " + dayCounter_.name(); name_ = res; Settings.registerWith(update); // recheck IndexManager.instance().notifier(name()).registerWith(update); }
protected InterestRateIndex(string familyName, Period tenor, int fixingDays, Currency currency, Calendar fixingCalendar, DayCounter dayCounter) { familyName_ = familyName; tenor_ = tenor; fixingDays_ = fixingDays; currency_ = currency; fixingCalendar_ = fixingCalendar; dayCounter_ = dayCounter; tenor_.Normalize(); Settings.registerWith(update); // recheck IndexManager.instance().notifier(name()).registerWith(update); }
bool needsForecast(Date fixingDate) { // Stored fixings are always non-interpolated. // If an interpolated fixing is required then // the availability lag + one inflation period // must have passed to use historical fixings // (because you need the next one to interpolate). // The interpolation is calculated (linearly) on demand. Date today = Settings.evaluationDate(); Date todayMinusLag = today - availabilityLag_; Date historicalFixingKnown = Utils.inflationPeriod(todayMinusLag, frequency_).Key - 1; Date latestNeededDate = fixingDate; if (interpolated_) // might need the next one too { KeyValuePair <Date, Date> p = Utils.inflationPeriod(fixingDate, frequency_); if (fixingDate > p.Key) { latestNeededDate = latestNeededDate + new Period(frequency_); } } if (latestNeededDate <= historicalFixingKnown) { // the fixing date is well before the availability lag, so // we know that fixings were provided. return(false); } else if (latestNeededDate > today) { // the fixing can't be available, no matter what's in the // time series return(true); } else { // we're not sure, but the fixing might be there so we // check. Todo: check which fixings are not possible, to // avoid using fixings in the future return(IndexManager.instance().getHistory(name()).value().ContainsKey(latestNeededDate)); } }
public override double fixing(Date fixingDate, bool forecastTodaysFixing) { if (!isValidFixingDate(fixingDate)) { throw new ArgumentException("Fixing date " + fixingDate + " is not valid"); } TimeSeries <double> fixings = IndexManager.instance().getHistory(name()).value(); if (fixings.ContainsKey(fixingDate)) { return(fixings[fixingDate]); } else { Date today = Settings.evaluationDate(); if (fixingDate < today || (fixingDate == today && !forecastTodaysFixing && Settings.enforcesTodaysHistoricFixings)) { // must have been fixed if (IndexManager.MissingPastFixingCallBack == null) { throw new ArgumentException("Missing " + name() + " fixing for " + fixingDate); } else { // try to load missing fixing from external source double fixing = IndexManager.MissingPastFixingCallBack(this, fixingDate); // add to history addFixing(fixingDate, fixing); return(fixing); } } if ((fixingDate == today) && !forecastTodaysFixing) { // might have been fixed but forecast since it does not exist // so fall through and forecast } // forecast return(forecastFixing(fixingDate)); } }
/*! \warning the forecastTodaysFixing parameter (required by * the Index interface) is currently ignored. */ public override double fixing(Date aFixingDate, bool forecastTodaysFixing = false) { if (!needsForecast(aFixingDate)) { KeyValuePair <Date, Date> lim = Utils.inflationPeriod(aFixingDate, frequency_); Utils.QL_REQUIRE(IndexManager.instance().getHistory(name()).ContainsKey(lim.Key), () => "Missing " + name() + " fixing for " + lim.Key); double?pastFixing = IndexManager.instance().getHistory(name())[lim.Key]; double?theFixing = pastFixing; if (interpolated_) { // fixings stored on first day of every period if (aFixingDate == lim.Key) { // we don't actually need the next fixing theFixing = pastFixing; } else { Utils.QL_REQUIRE(IndexManager.instance().getHistory(name()).ContainsKey(lim.Value + 1), () => "Missing " + name() + " fixing for " + (lim.Value + 1)); double?pastFixing2 = IndexManager.instance().getHistory(name())[lim.Value + 1]; // Use lagged period for interpolation KeyValuePair <Date, Date> reference_period_lim = Utils.inflationPeriod(aFixingDate + zeroInflationTermStructure().link.observationLag(), frequency_); // now linearly interpolate double daysInPeriod = reference_period_lim.Value + 1 - reference_period_lim.Key; theFixing = pastFixing + (pastFixing2 - pastFixing) * (aFixingDate - lim.Key) / daysInPeriod; } } return(theFixing.GetValueOrDefault()); } else { return(forecastFixing(aFixingDate)); } }
/*! \warning the forecastTodaysFixing parameter (required by * the Index interface) is currently ignored. */ public override double fixing(Date aFixingDate, bool forecastTodaysFixing) { if (!needsForecast(aFixingDate)) { if (!IndexManager.instance().getHistory(name()).value().ContainsKey(aFixingDate)) { throw new ApplicationException("Missing " + name() + " fixing for " + aFixingDate); } double pastFixing = IndexManager.instance().getHistory(name()).value()[aFixingDate]; double theFixing = pastFixing; if (interpolated_) { // fixings stored flat & for every day Date fixingDate2 = aFixingDate + new Period(frequency_); if (!IndexManager.instance().getHistory(name()).value().ContainsKey(fixingDate2)) { throw new ApplicationException("Missing " + name() + " fixing for " + fixingDate2); } double pastFixing2 = IndexManager.instance().getHistory(name()).value()[fixingDate2]; // now linearly interpolate KeyValuePair <Date, Date> lim2 = Utils.inflationPeriod(aFixingDate, frequency_); double daysInPeriod = lim2.Value + 1 - lim2.Key; theFixing = pastFixing + (pastFixing2 - pastFixing) * (aFixingDate - lim2.Key) / daysInPeriod; } return(theFixing); } else { return(forecastFixing(aFixingDate)); } }
// Returns the fixing TimeSeries public TimeSeries <double?> timeSeries() { return(IndexManager.instance().getHistory(name())); }
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()); }
// Clears all stored historical fixings public void clearFixings() { checkNativeFixingsAllowed(); IndexManager.instance().clearHistory(name()); }
public double fixing(Date fixingDate, bool forecastTodaysFixing) { Date today = Settings.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()).value()[lim.Key]; if (limFirstFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + lim.Key); } double limSecondFix = IndexManager.instance().getHistory(name()).value()[lim.Value + 1]; if (limSecondFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + lim.Value + 1); } double limBefFirstFix = IndexManager.instance().getHistory(name()).value()[limBef.Key]; if (limBefFirstFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + limBef.Key); } double limBefSecondFix = IndexManager.instance().getHistory(name()).value()[limBef.Value + 1]; if (limBefSecondFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + limBef.Value + 1); } double linearNow = limFirstFix + (limSecondFix - limFirstFix) * dl / dp; double linearBef = limBefFirstFix + (limBefSecondFix - limBefFirstFix) * dlBef / dpBef; double wasYES = linearNow / linearBef - 1.0; return(wasYES); } else { // IS ratio, NOT interpolated double pastFixing = IndexManager.instance().getHistory(name()).value()[fixingDate]; if (pastFixing == null) { throw new ApplicationException("Missing " + name() + " fixing for " + fixingDate); } Date previousDate = fixingDate - new Period(1, TimeUnit.Years); double previousFixing = IndexManager.instance().getHistory(name()).value()[previousDate]; if (previousFixing == null) { throw new ApplicationException("Missing " + name() + " fixing for " + previousDate); } return(pastFixing / previousFixing - 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()).value()[lim.Key]; if (limFirstFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + lim.Key); } double limSecondFix = IndexManager.instance().getHistory(name()).value()[lim.Value + 1]; if (limSecondFix == null) { throw new ApplicationException("Missing " + name() + " fixing for " + lim.Value + 1); } double linearNow = limFirstFix + (limSecondFix - limFirstFix) * dl / dp; return(linearNow); } else { // NOT ratio, NOT interpolated // so just flat double pastFixing = IndexManager.instance().getHistory(name()).value()[fixingDate]; if (pastFixing == null) { throw new ApplicationException("Missing " + name() + " fixing for " + fixingDate); } return(pastFixing); } } // QL_FAIL("YoYInflationIndex::fixing, should never get here"); }
//! 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 }
//! clears all stored historical fixings public void clearFixings() { IndexManager.instance().clearHistory(name()); }
//! returns the fixing TimeSeries public ObservableValue <TimeSeries <double> > timeSeries() { return(IndexManager.instance().getHistory(name())); }