// 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 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)); } }
//! 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 }