/// <summary> /// Initializes a new instance of the <see cref="CapFloorAssetQuote"/> class. /// </summary> /// <param name="priceableAsset">The priceable asset.</param> /// <param name="baseDate">The base date.</param> /// <param name="interpolation">The interpolation.</param> /// <param name="extrapolation">if set to <c>true</c> [extrapolation].</param> /// <param name="vols">The volatilities.</param> /// <param name="tolerance">The tolerance.</param> /// <param name="discountCurve">The discount rate curve.</param> /// <param name="forecastCurve">The forecast rate curve.</param> public CapFloorAssetQuote(PriceableCapRateAsset priceableAsset, IRateCurve discountCurve, IRateCurve forecastCurve, DateTime baseDate, InterpolationMethod interpolation, bool extrapolation, IDictionary <DateTime, Decimal> vols, double tolerance) { PriceableAsset = priceableAsset; PriceableAsset.DiscountCurve = discountCurve; PriceableAsset.ForecastCurve = forecastCurve; BaseDate = baseDate; Vols = vols; InterpolationMethod = interpolation; Extrapolation = extrapolation; Tolerance = tolerance; //This is the flat volatility. var premium = PriceableAsset.CalculatePremium(); if (premium != null) { Quote = (decimal)premium; } }
public static void UpdatePaymentsAmounts(ILogger logger, ICoreCache cache, String nameSpace, Swap swap, SwapLegParametersRange_Old leg1Parameters, SwapLegParametersRange_Old leg2Parameters, IRateCurve leg1DiscountCurve, IRateCurve leg2DiscountCurve, DateTime valuationDate, IBusinessCalendar paymentCalendar) { foreach (Payment payment in swap.additionalPayment) { // choose correct discount curve // IRateCurve discountCurve; if (payment.payerPartyReference.href == leg1Parameters.Payer) { discountCurve = leg1DiscountCurve; } else if (payment.payerPartyReference.href == leg2Parameters.Payer) { discountCurve = leg2DiscountCurve; } else { throw new NotImplementedException(); } if (paymentCalendar == null) { var containsPaymentDateAdjustments = AdjustableOrAdjustedDateHelper.Contains(payment.paymentDate, ItemsChoiceType.dateAdjustments, out var dateAdjustments); if (containsPaymentDateAdjustments && dateAdjustments != null) { paymentCalendar = BusinessCenterHelper.ToBusinessCalendar(cache, ((BusinessDayAdjustments)dateAdjustments). businessCenters, nameSpace); } } var date = AdjustedDateHelper.GetAdjustedDate(paymentCalendar, payment.paymentDate); if (date != null) { payment.discountFactor = (decimal)discountCurve.GetDiscountFactor(valuationDate, (DateTime)date); payment.discountFactorSpecified = true; payment.presentValueAmount = MoneyHelper.Mul(payment.paymentAmount, payment.discountFactor); } } }
public NewtonRaphsonSolverFunctions(IPriceableAssetController asset, IPriceableAssetController previousAsset, PricingStructureAlgorithmsHolder algorithmHolder, IRateCurve baseCurve, DateTime baseDate, SortedDictionary <DateTime, Pair <string, decimal> > items, double compoundingPeriod, IDictionary <DateTime, double> zeroRateSpreads, IDayCounter dayCounter, List <DateTime> assetDates) { _asset = asset; _baseCurve = baseCurve; _zeroRateSpreads = zeroRateSpreads; string currency = PropertyHelper.ExtractCurrency(baseCurve.GetPricingStructureId().Properties); _algorithm = algorithmHolder; _properties = new NamedValueSet(new Dictionary <string, object> { { CurveProp.PricingStructureType, "RateCurve" }, { CurveProp.Market, "DiscountCurveConstruction" }, { CurveProp.IndexTenor, "0M" }, { CurveProp.Currency1, currency }, { "Index", "XXX-XXX" }, { "Algorithm", "FastLinearZero" }, { "BaseDate", baseDate }, }); _items = items; _compoundingPeriod = compoundingPeriod; _dayCounter = dayCounter; _assetDates = assetDates; if (previousAsset != null) { DateTime previousAssetMaturity = previousAsset.GetRiskMaturityDate(); DateTime assetMaturity = asset.GetRiskMaturityDate(); IEnumerable <KeyValuePair <DateTime, string> > points = from b in baseCurve.GetTermCurve().point where (DateTime)b.term.Items[0] > previousAssetMaturity && (DateTime)b.term.Items[0] < assetMaturity select new KeyValuePair <DateTime, string>((DateTime)b.term.Items[0], b.id); foreach (KeyValuePair <DateTime, string> point in points) { _extraPoints.Add(point.Key, point.Value); Pair <string, decimal> pair = new Pair <string, decimal>(point.Value, 0); items.Add(point.Key, pair); } } }
public static void UpdateFloatingRateDefinition(FloatingRateDefinition floatingRateDefinition, FloatingRateCalculation floatingRateCalculation, DayCountFraction dayCountFraction, CalculationPeriod calculationPeriod, IRateCurve forecastCurve) { var rateObservation = new RateObservation(); if (floatingRateDefinition.rateObservation != null) { if (floatingRateDefinition.rateObservation[0].adjustedFixingDateSpecified) { rateObservation.adjustedFixingDate = floatingRateDefinition.rateObservation[0].adjustedFixingDate; rateObservation.adjustedFixingDateSpecified = true; } } floatingRateDefinition.rateObservation = new[] { rateObservation }; rateObservation.forecastRate = GetForecastRate(calculationPeriod, forecastCurve, dayCountFraction); rateObservation.forecastRateSpecified = true; Decimal finalRate = rateObservation.forecastRate; // If spread specified - add it to the final rate. // if (floatingRateDefinition.spreadSpecified) { finalRate += floatingRateDefinition.spread; } // Apply rounding (if it's been specified) // if (null != floatingRateCalculation.finalRateRounding) { Rounding finalRateRounding = floatingRateCalculation.finalRateRounding; floatingRateDefinition.calculatedRate = RoundingHelper.Round(finalRate, finalRateRounding); } else { floatingRateDefinition.calculatedRate = finalRate; } floatingRateDefinition.calculatedRateSpecified = true; }
private static void UpdateCashflowsWithAmounts( ILogger logger, ICoreCache cache, String nameSpace, InterestRateStream stream, SwapLegParametersRange legParametersRange, ValuationRange valuationRange) { // Get a forecast curve // IRateCurve forecastCurve = null; if (!String.IsNullOrEmpty(legParametersRange.ForecastCurve)) { forecastCurve = CurveLoader.LoadInterestRateCurve(logger, cache, nameSpace, legParametersRange.ForecastCurve); } // Get a discount curve // var discountCurve = CurveLoader.LoadInterestRateCurve(logger, cache, nameSpace, legParametersRange.DiscountCurve); FixedAndFloatingRateStreamCashflowGenerator.UpdateCashflowsAmounts(stream, forecastCurve, discountCurve, valuationRange.ValuationDate); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="referenceCurve">The reference curve.</param> /// <param name="baseDate">The base date.</param> /// <param name="termCurve">The term Curve with pre-existing points. This will not work if there are no points.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <returns></returns> public static TermPoint[] Bootstrap(IList <IPriceableRateSpreadAssetController> priceableAssets, IRateCurve referenceCurve, DateTime baseDate, TermCurve termCurve, Double tolerance) { const double min = 0.000000001; const double max = 1; Dictionary <DateTime, Pair <string, decimal> > items = new Dictionary <DateTime, Pair <string, decimal> > (); // Add the elements (date : discount factor) to the list IDictionary <DateTime, double> dfs = new Dictionary <DateTime, double>(); foreach (var point in termCurve.point) { dfs.Add((DateTime)point.term.Items[0], (double)point.mid); items.Add((DateTime)point.term.Items[0], new Pair <string, decimal>(point.id, point.mid)); } var solver = new Brent(); foreach (var priceableAsset in priceableAssets) { var assetMaturityDate = priceableAsset.GetRiskMaturityDate(); if (dfs.ContainsKey(assetMaturityDate)) { continue; } //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. //So far this is only wrt Depos and Futures...This now should automatically extrapolate the required discount factor on a flat rate basis. dfs.Add(assetMaturityDate, (double)priceableAsset.CalculateDiscountFactorAtMaturity(referenceCurve)); var objectiveFunction = new RateSpreadAssetQuote(priceableAsset, referenceCurve, baseDate, termCurve.extrapolationPermitted, dfs, tolerance); // check accuracy so that solver is only called if outside the tolerance. if (!objectiveFunction.InitialValue()) { dfs[assetMaturityDate] = solver.Solve(objectiveFunction, tolerance, dfs[assetMaturityDate], min, max); } items.Add(assetMaturityDate, new Pair <string, decimal>(priceableAsset.Id, (decimal)dfs[assetMaturityDate])); } return(TermPointsFactory.Create(items)); }
// used in constructor private void Ini(string tenor, IRateCurve curve, BilinearInterpolator capletVolMatrix, double nominal) { stringTenor = tenor; rateCurve = curve; volMatrix = capletVolMatrix; N = nominal; // yf of longer cap SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(curve.RefDate(), 0, tenor, curve.GetSwapStyle().buildingBlockType); yf = y.scheduleLeg2.GetYFVect(Dc._Act_360); capSchedule = y.scheduleLeg2; int toRemove = yf.Length - 1; yf = yf.Where((val, inx) => inx != toRemove).ToArray(); // T all tenor needed. They are more than input Date refDate = curve.RefDate(); List <Date> ToDate = y.scheduleLeg2.toDates.ToList(); ToDate.RemoveAt(ToDate.Count - 1); // remove last element T = (from c in ToDate select refDate.YF_365(c)).ToArray(); // df- getting relevant dates Date[] dfDate = y.scheduleLeg2.payDates; int Ncaplet = yf.Length; // number of caplets df = new double[Ncaplet]; // fwd rate fwd = new double[Ncaplet]; Date[] fwdDate = y.scheduleLeg2.fromDates; for (int i = 0; i < Ncaplet; i++) // Note the loop start from 1 { // first discount factor is on first payment date of caplet (first caplet skipped) df[i] = curve.Df(dfDate[i + 1]); fwd[i] = curve.Fwd(fwdDate[i + 1]); } }
/// <summary> /// Set discount from a yield curve ID /// </summary> /// <param name="rateCurve"></param> /// <returns></returns> public string SetDiscountFactors(IRateCurve rateCurve) { const int length = 123; string temp; try { var discount = new double[length]; DateTime today = DateTime.Now; for (int i = 0; i < length; i++) { discount[i] = rateCurve.GetDiscountFactor(today, today.AddMonths(i * 3)); } _usd.CurDiscount = discount; _usd.DiscountStatus = "User Defined"; temp = String.Format("Discount factors were set."); } catch (Exception e) { temp = e.ToString(); } return(temp); }
public static double FwdBasis(Date StartDate, string SwapTenor, IRateCurve Curve1, IRateCurve Curve2) { SwapStyle S1 = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(StartDate, 0.0, SwapTenor, Curve1.GetSwapStyle().buildingBlockType); SwapStyle S2 = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(StartDate, 0.0, SwapTenor, Curve2.GetSwapStyle().buildingBlockType); double[] yfFloatLeg1 = S1.scheduleLeg2.GetYFVect(S1.swapLeg2.DayCount); // using LINQ syntax double[] dfFloatLeg1 = (from d in S1.scheduleLeg2.payDates select Curve1.Df(d)).ToArray <double>(); double[] fwdFloatLeg1 = (from d in S1.scheduleLeg2.fromDates select Curve1.Fwd(d)).ToArray <double>(); double[] yfFloatLeg2 = S2.scheduleLeg2.GetYFVect(S2.swapLeg2.DayCount); // using LINQ syntax double[] dfFloatLeg2 = (from d in S2.scheduleLeg2.payDates select Curve2.Df(d)).ToArray <double>(); double[] fwdFloatLeg2 = (from d in S2.scheduleLeg2.fromDates select Curve2.Fwd(d)).ToArray <double>(); return(SpreadBasisFormula(yfFloatLeg1, dfFloatLeg1, fwdFloatLeg1, yfFloatLeg2, dfFloatLeg2, fwdFloatLeg2)); }
/// <summary> /// Calculates the specified model data. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="discountCurve">The discount curve.</param> /// <param name="forecastCurve">The forward curve.</param> /// <param name="volCurve">The volatility surface. /// and discount curves when called with ForecastRateCurve.</param> /// <param name="curveToPerturb">The curve to perturb: the discount curve, the forecast curve or both.</param> /// <returns></returns> public IDictionary <string, double> CalculateRatePDH(DateTime valuationDate, IRateCurve discountCurve, IRateCurve forecastCurve, IVolatilitySurface volCurve, CurvePerturbation curveToPerturb) { var result = new Dictionary <string, double>(); AnalyticResults = new RateOptionAssetResults(); switch (ModelIdentifier) { case "CapAsset": AnalyticsModel = new RateOptionAssetAnalytic(); break; case "DiscountCapAsset": AnalyticsModel = new RateOptionAssetAnalytic(); break; } ForecastCurveName = forecastCurve.GetPricingStructureId().UniqueIdentifier; DiscountCurveName = discountCurve.GetPricingStructureId().UniqueIdentifier; VolatilityCurveName = volCurve.GetPricingStructureId().UniqueIdentifier; var analyticModelParameters = new RateOptionAssetParameters { IsPut = !IsCap, Notionals = Notionals }; //and the rest rates if (ResetRates != null) { analyticModelParameters.ForwardRates = ResetRates; } //2. Get the discount factors analyticModelParameters.ForecastDiscountFactors = GetDiscountFactors(forecastCurve, AdjustedPeriodDates.ToArray(), valuationDate); analyticModelParameters.PaymentDiscountFactors = GetDiscountFactors(discountCurve, AdjustedPeriodDates.ToArray(), valuationDate); //3. Get the respective year fractions analyticModelParameters.YearFractions = YearFractions; //4. set the expiry times. TimesToExpiry = GetTimesToExpiry(ExpiryDates, valuationDate); analyticModelParameters.TimesToExpiry = TimesToExpiry; //5. Get the vols analyticModelParameters.Volatilities = GetVolatilties(volCurve, TimesToExpiry, Strikes); //8. Get the Strikes analyticModelParameters.Strikes = Strikes; //9. Set the analytic input parameters and Calculate the respective metrics var analyticResults = AnalyticsModel.Calculate <IRateOptionAssetResults, RateOptionAssetResults>(analyticModelParameters, new[] { RateOptionMetrics.NPV }); AnalyticResults = analyticResults; var baseNPV = SumDoubleList(AnalyticResults.NPV, 0); //Now loop through the risk curves. if (curveToPerturb == CurvePerturbation.DiscountCurve) { var riskCurves = discountCurve.CreateCurveRiskSet(1); foreach (var curve in riskCurves) { var perturbedAsset = curve.GetPricingStructureId().Properties.GetValue <string>("PerturbedAsset"); analyticResults = RiskCalculationHelper((IRateCurve)curve, analyticModelParameters); result.Add("DiscountCurve:" + perturbedAsset, baseNPV - SumDoubleList(analyticResults.NPV, 0)); } } if (curveToPerturb == CurvePerturbation.ForecastCurve) { var riskCurves = forecastCurve.CreateCurveRiskSet(1); foreach (var curve in riskCurves) { var perturbedAsset = curve.GetPricingStructureId().Properties.GetValue <string>("PerturbedAsset"); analyticResults = ForecastRiskCalculationHelper((IRateCurve)curve, analyticModelParameters); result.Add("ForecastCurve:" + perturbedAsset, baseNPV - SumDoubleList(analyticResults.NPV, 0)); } } if (curveToPerturb == CurvePerturbation.Both) { var riskCurves1 = discountCurve.CreateCurveRiskSet(1); foreach (var curve in riskCurves1) { var perturbedAsset = curve.GetPricingStructureId().Properties.GetValue <string>("PerturbedAsset"); analyticResults = RiskCalculationHelper((IRateCurve)curve, analyticModelParameters); result.Add("DiscountCurve:" + perturbedAsset, baseNPV - SumDoubleList(analyticResults.NPV, 0)); } var riskCurves2 = forecastCurve.CreateCurveRiskSet(1); foreach (var curve in riskCurves2) { var perturbedAsset = curve.GetPricingStructureId().Properties.GetValue <string>("PerturbedAsset"); analyticResults = ForecastRiskCalculationHelper((IRateCurve)curve, analyticModelParameters); result.Add("ForecastCurve:" + perturbedAsset, baseNPV - SumDoubleList(analyticResults.NPV, 0)); } } return(result); }
/// <summary> /// Calculates the specified model data. /// </summary> /// <param name="modelData">The model data.</param> /// <returns></returns> public override BasicAssetValuation Calculate(IAssetControllerData modelData) { ModelData = modelData; switch (ModelIdentifier) { case "CapAsset": AnalyticsModel = new RateOptionAssetAnalytic(); break; case "DiscountCapAsset": AnalyticsModel = new RateOptionAssetAnalytic(); break; } var metrics = MetricsHelper.GetMetricsToEvaluate(Metrics, AnalyticsModel.Metrics); var metricsToEvaluate = metrics.ToArray(); var analyticModelParameters = new RateOptionAssetParameters(); AnalyticResults = new RateOptionAssetResults(); var marketEnvironment = modelData.MarketEnvironment; IRateCurve rateCurve = null; IRateCurve discountCurve = null; IVolatilitySurface volCurve = null; //1. instantiate curve if (marketEnvironment.GetType() == typeof(SwapLegEnvironment)) { rateCurve = ((ISwapLegEnvironment)marketEnvironment).GetForecastRateCurve(); ForecastCurveName = rateCurve.GetPricingStructureId().UniqueIdentifier; discountCurve = ((ISwapLegEnvironment)marketEnvironment).GetDiscountRateCurve(); DiscountCurveName = discountCurve.GetPricingStructureId().UniqueIdentifier; volCurve = ((ISwapLegEnvironment)marketEnvironment).GetVolatilitySurface(); VolatilityCurveName = volCurve.GetPricingStructureId().UniqueIdentifier; } //Cap logic. analyticModelParameters.IsPut = !IsCap; //1. Notionals analyticModelParameters.Notionals = Notionals; //and the rest rates if (ResetRates != null) { analyticModelParameters.ForwardRates = ResetRates; } //2. Get the discount factors analyticModelParameters.ForecastDiscountFactors = GetDiscountFactors(rateCurve, AdjustedPeriodDates.ToArray(), modelData.ValuationDate); analyticModelParameters.PaymentDiscountFactors = GetDiscountFactors(discountCurve, AdjustedPeriodDates.ToArray(), modelData.ValuationDate); //3. Get the respective year fractions analyticModelParameters.YearFractions = YearFractions; //4. set the expiry times. TimesToExpiry = GetTimesToExpiry(ExpiryDates, modelData.ValuationDate); analyticModelParameters.TimesToExpiry = TimesToExpiry; //5. Get the vols analyticModelParameters.Volatilities = GetVolatilties(volCurve, TimesToExpiry, Strikes); //8. Get the Strikes analyticModelParameters.Strikes = Strikes; ParRate = CalculateImpliedParRate(modelData.ValuationDate); analyticModelParameters.Rate = (double)ParRate; //9. Set the analytic input parameters and Calculate the respective metrics AnalyticResults = AnalyticsModel.Calculate <IRateOptionAssetResults, RateOptionAssetResults>(analyticModelParameters, metricsToEvaluate); //TODO change this method and return a table report of all greeks. return(GetValue(AnalyticResults)); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="baseZeroCurve">The base Zero Curve</param> /// <param name="algorithmHolder">The algorithmHolder</param> /// <returns></returns> public TermPoint[] Bootstrap(List <IPriceableRateAssetController> priceableAssets, IRateCurve baseZeroCurve, PricingStructureAlgorithmsHolder algorithmHolder) { var items = new SortedDictionary <DateTime, Pair <string, decimal> >(); DateTime baseDate = baseZeroCurve.GetBaseDate(); items.Add(baseDate, new Pair <string, decimal>(null, 1m)); bool firstTime = true; const double compoundingPeriod = 0.25; IPriceableRateAssetController previousAsset = null; IEnumerable <TermPoint> basePillars = baseZeroCurve.GetTermCurve().point; IDayCounter dayCounter = null; foreach (IPriceableRateAssetController priceableAsset in priceableAssets) { List <DateTime> assetDates; if (priceableAsset is PriceableSwapRateAsset swap) { dayCounter = DayCounterHelper.Parse(swap.DayCountFraction.Value); assetDates = swap.AdjustedPeriodDates; } else { PriceableDeposit deposit = priceableAsset as PriceableDeposit; if (deposit == null) { throw new ArgumentException( $"PriceableAsset must be a PriceableSwapRateAsset or PriceableDeposit, '{priceableAsset.GetType()}' is not implemented."); } dayCounter = DayCounterHelper.Parse(deposit.Deposit.dayCountFraction.Value); assetDates = new List <DateTime> { deposit.AdjustedStartDate, deposit.GetRiskMaturityDate() }; } DateTime maturityDate = priceableAsset.GetRiskMaturityDate(); if (items.Keys.Contains(maturityDate)) { throw new ArgumentException( $"Duplicate priceable asset on '{maturityDate:yyyy-MM-dd}'", nameof(priceableAssets)); } //The min and max values to use with the solver. const int xmin = -1; const int xmax = 1; var accuracy = 10 ^ -12; if (firstTime) { firstTime = false; // Solve to find the quarterly compounded zero rate spread var solverFunctions = new NewtonRaphsonSolverFunctions(priceableAsset, null, algorithmHolder, baseZeroCurve, baseDate, items, compoundingPeriod, ZeroRateSpreads, dayCounter, assetDates); var solver = new Newton(); var initialGuess = (double)priceableAsset.MarketQuote.value; //var solution = new CenteredFiniteDifferenceDerivative(); Func <double, double> f = solverFunctions.ShortEndTargetFunction; var derivativeOfTargetFunction = new NumericalDerivative().CreateDerivativeFunctionHandle(f, 1); double zeroRateSpread = solver.Solve(f, derivativeOfTargetFunction, accuracy, initialGuess, xmin, xmax); // add first point DateTime startDate = assetDates.First(); decimal df = (decimal)GetAdjustedDiscountFactor(baseDate, startDate, dayCounter, zeroRateSpread, baseZeroCurve); if (startDate != baseDate) { items.Add(startDate, new Pair <string, decimal>(null, df)); } ZeroRateSpreads.Add(maturityDate, zeroRateSpread); // add extra points IEnumerable <TermPoint> extraPoints = basePillars.Where(b => (DateTime)b.term.Items[0] > startDate && (DateTime)b.term.Items[0] < maturityDate); // Extrapolate the preceding extra points foreach (TermPoint extraPoint in extraPoints) { DateTime date = (DateTime)extraPoint.term.Items[0]; df = (decimal)GetAdjustedDiscountFactor(baseDate, date, dayCounter, zeroRateSpread, baseZeroCurve); items.Add(date, new Pair <string, decimal>(extraPoint.id, df)); } // add final point df = (decimal)GetAdjustedDiscountFactor(baseDate, maturityDate, dayCounter, zeroRateSpread, baseZeroCurve); items.Add(maturityDate, new Pair <string, decimal>(priceableAsset.Id, df)); } else { items.Add(maturityDate, new Pair <string, decimal>(priceableAsset.Id, 0)); ZeroRateSpreads.Add(maturityDate, (double)priceableAsset.MarketQuote.value); // Solve to find the quarterly compounded zero rate spread var solverFunctions = new NewtonRaphsonSolverFunctions(priceableAsset, previousAsset, algorithmHolder, baseZeroCurve, baseDate, items, compoundingPeriod, ZeroRateSpreads, dayCounter, assetDates); Func <double, double> f = solverFunctions.LongEndTargetFunction; var solver = new Newton(); var initialGuess = (double)priceableAsset.MarketQuote.value; var derivativeOfTargetFunction = new NumericalDerivative().CreateDerivativeFunctionHandle(f, 1); double zeroRateSpread = solver.Solve(f, derivativeOfTargetFunction, accuracy, initialGuess, xmin, xmax); // Update discount factor value decimal df = (decimal)GetAdjustedDiscountFactor(baseDate, maturityDate, dayCounter, zeroRateSpread, baseZeroCurve); items[maturityDate].Second = df; ZeroRateSpreads[maturityDate] = zeroRateSpread; solverFunctions.UpdateDiscountFactors(baseDate); } previousAsset = priceableAsset; } // Extrapolate the following extra points IEnumerable <TermPoint> finalPoints = basePillars.Where(b => (DateTime)b.term.Items[0] > items.Last().Key); KeyValuePair <DateTime, double> zeroRateSpreadFinal = ZeroRateSpreads.Last(); foreach (TermPoint extraPoint in finalPoints) { DateTime date = (DateTime)extraPoint.term.Items[0]; decimal df = (decimal)GetAdjustedDiscountFactor(baseDate, date, dayCounter, zeroRateSpreadFinal.Value, baseZeroCurve); items.Add(date, new Pair <string, decimal>(extraPoint.id, df)); } return(TermPointsFactory.Create(items)); }
/// <summary> /// <remarks> /// Always: /// pay floating /// receive fixed /// </remarks> /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="valueDate"></param> /// <param name="effectiveDate"></param> /// <param name="terminationDate"></param> /// <param name="interpolationMethod"></param> /// <param name="margineAboveFloatingRate"></param> /// <param name="resetRate"></param> /// <param name="directionDateGenerationPayLeg"></param> /// <param name="cashFlowFrequencyPayLeg"></param> /// <param name="accrualMethodPayLeg"></param> /// <param name="holidaysPayLeg"></param> /// <param name="discountFactorCurvePayLeg"></param> /// <param name="directionDateGenerationRecLeg"></param> /// <param name="cashFlowFrequencyRecLeg"></param> /// <param name="accrualMethodRecLeg"></param> /// <param name="holidaysRecLeg"></param> /// <param name="discountFactorCurveRecLeg"></param> /// <returns></returns> public double GetSwapParRateWithoutCurves ( ILogger logger, ICoreCache cache, String nameSpace, DateTime valueDate, DateTime effectiveDate, DateTime terminationDate, string interpolationMethod, //1 is linear on forward rates => make sure that the right curve is provided ... double margineAboveFloatingRate, // use 0 initially double resetRate, int directionDateGenerationPayLeg, string cashFlowFrequencyPayLeg, string accrualMethodPayLeg, string holidaysPayLeg, IRateCurve discountFactorCurvePayLeg, int directionDateGenerationRecLeg, string cashFlowFrequencyRecLeg, string accrualMethodRecLeg, string holidaysRecLeg, IRateCurve discountFactorCurveRecLeg ) { const decimal dummyNotional = 1000000.0m; // received fixed leg // var recFixedCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, dummyNotional, directionDateGenerationRecLeg, cashFlowFrequencyRecLeg, accrualMethodRecLeg, holidaysRecLeg, discountFactorCurveRecLeg, true); recFixedCashflows.PayingFixedRate = false; // pay floating leg // var payFloatingCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, dummyNotional, directionDateGenerationPayLeg, cashFlowFrequencyPayLeg, accrualMethodPayLeg, holidaysPayLeg, discountFactorCurvePayLeg, false); payFloatingCashflows.PayingFixedRate = false; var objectiveFunction = new InterestRateSwapPricer { ReceiveLeg = recFixedCashflows, PayLeg = payFloatingCashflows }; var solver = new Brent { LowerBound = -100.0, UpperBound = 100.0 }; return(solver.Solve(objectiveFunction, Accuracy, Guess, Step)); }
/// <summary> /// Gets the discount factors. /// </summary> /// <param name="discountFactorCurve">The discount factor curve.</param> /// <param name="periodDates">The period dates.</param> /// <param name="valuationDate">The valuation date.</param> /// <returns></returns> public List <double> GetDiscountFactors(IRateCurve discountFactorCurve, DateTime[] periodDates, DateTime valuationDate) { return(periodDates.Select(periodDate => GetDiscountFactor(discountFactorCurve, periodDate, valuationDate)).ToList()); }
/// <summary> /// Initiates a new model. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="startDate">The start date of the coupon.</param> /// <param name="endDate">The end date of the coupon.</param> /// <param name="paymentDate">The payment date of the cash flow.</param> /// <param name="timeToIndex">The timeToIndex. Not necessarily the time to expiry. This is used for surface interpolation..</param> /// <param name="capStrike">The cap strike.</param> /// <param name="floorStrike">The floor strike.</param> /// <param name="reportingCurrencyFxCurve">THe fx curve. It must already be normalised.</param> /// <param name="discountCurve">The rate curve to use for discounting.</param> /// <param name="forecastCurve">The forecast curve.</param> /// <param name="indexVolSurface">The index volatility surface.</param> public RateOptionCouponAnalytic(DateTime valuationDate, DateTime startDate, DateTime endDate, DateTime paymentDate, decimal timeToIndex, decimal capStrike, decimal floorStrike, IFxCurve reportingCurrencyFxCurve, IRateCurve discountCurve, IRateCurve forecastCurve, IVolatilitySurface indexVolSurface) : this(valuationDate, startDate, endDate, paymentDate, timeToIndex, capStrike, reportingCurrencyFxCurve, discountCurve, forecastCurve, indexVolSurface) { IsCollar = true; CollarFloorStrike = floorStrike; CollarFloorVolatility = (decimal)indexVolSurface.GetValue((double)timeToIndex, (double)floorStrike); }
/// <summary> /// Calculates the specified model data. /// </summary> /// <param name="modelData">The model data.</param>//TODO the floating delta? /// <returns></returns> public override AssetValuation Calculate(IInstrumentControllerData modelData) { ModelData = modelData; AnalyticModelParameters = null; AnalyticsModel = new FxRateCashflowAnalytic(); CalculationResults = null; YearFractionToCashFlowPayment = Convert.ToDecimal(CDefaultDayCounter.YearFraction(ModelData.ValuationDate, PaymentDate)); //Make sure there are some bucket dates even if not set previously. if (BucketedDates.Length < 1) { UpdateBucketingInterval(ModelData.ValuationDate, PeriodHelper.Parse(CDefaultBucketingInterval)); } IsRealised = HasBeenRealised(ModelData.ValuationDate); //Add the extra metrics required var quotes = ModelData.AssetValuation.quote.ToList(); if (AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, FloatingCashflowMetrics.NPV.ToString()) == null) { var quote = QuotationHelper.Create(0.0m, FloatingCashflowMetrics.LocalCurrencyNPV.ToString(), "DecimalValue", ModelData.ValuationDate); quotes.Add(quote); } if (AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, FloatingCashflowMetrics.LocalCurrencyNPV.ToString()) == null) { var quote = QuotationHelper.Create(0.0m, FloatingCashflowMetrics.LocalCurrencyNPV.ToString(), "DecimalValue", ModelData.ValuationDate); quotes.Add(quote); } if (AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, InstrumentMetrics.RiskNPV.ToString()) == null) { var quote = QuotationHelper.Create(0.0m, InstrumentMetrics.NPV.ToString(), "DecimalValue", ModelData.ValuationDate); quotes.Add(quote); } if (AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, FloatingCashflowMetrics.LocalCurrencyExpectedValue.ToString()) == null) { var quote = QuotationHelper.Create(0.0m, FloatingCashflowMetrics.LocalCurrencyExpectedValue.ToString(), "DecimalValue", ModelData.ValuationDate); quotes.Add(quote); } //Check if risk calc are required. bool delta1PDH = AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, InstrumentMetrics.LocalCurrencyDelta1PDH.ToString()) != null || AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, InstrumentMetrics.Delta1PDH.ToString()) != null; //Check if risk calc are required. bool delta0PDH = AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, InstrumentMetrics.LocalCurrencyDelta0PDH.ToString()) != null || AssetValuationHelper.GetQuotationByMeasureType(ModelData.AssetValuation, InstrumentMetrics.Delta0PDH.ToString()) != null; ModelData.AssetValuation.quote = quotes.ToArray(); var metrics = ResolveModelMetrics(AnalyticsModel.Metrics); IFxCurve fxCurve = null; IRateCurve discountCurve = null; IFxCurve currencyCurve = null; var reportingCurrency = ModelData.ReportingCurrency == null ? PaymentCurrency.Value : ModelData.ReportingCurrency.Value; //Set the basic model. var analyticModelParameters = new FxRateCashflowParameters { Multiplier = Multiplier, ValuationDate = ModelData.ValuationDate, PaymentDate = PaymentDate, Currency = PaymentCurrency.Value, ReportingCurrency = reportingCurrency, NotionalAmount = PaymentAmount.amount, StartIndex = StartIndex, IsRealised = IsRealised, CurveYearFraction = YearFractionToCashFlowPayment, PeriodAsTimesPerYear = 0.25m, BucketingRate = 0.05m }; if (modelData.MarketEnvironment is ISwapLegEnvironment environment) { var marketEnvironment = environment; //The discount curve. discountCurve = marketEnvironment.GetDiscountRateCurve(); discountCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; analyticModelParameters.DiscountCurve = discountCurve; //Check if it is our of currency. if (ModelData.ReportingCurrency != null && ModelData.ReportingCurrency.Value != PaymentCurrency.Value) { fxCurve = marketEnvironment.GetReportingCurrencyFxCurve(); fxCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; analyticModelParameters.ReportingCurrencyFxCurve = fxCurve; } } else if (modelData.MarketEnvironment.GetType() == typeof(MarketEnvironment)) { var market = (MarketEnvironment)modelData.MarketEnvironment; discountCurve = (IRateCurve)market.SearchForPricingStructureType(DiscountCurveName); discountCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; analyticModelParameters.DiscountCurve = discountCurve; var currencyCurveName = MarketEnvironmentHelper.ResolveFxCurveNames(StartFxRate.quotedCurrencyPair.currency1.Value, StartFxRate.quotedCurrencyPair.currency2.Value); currencyCurve = (IFxCurve)market.SearchForPricingStructureType(currencyCurveName); currencyCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; if (delta1PDH) { var riskMarket = market.SearchForPerturbedPricingStructures(DiscountCurveName, "delta1PDH"); analyticModelParameters.Delta1PDHCurves = riskMarket; analyticModelParameters.Delta1PDHPerturbation = 10; } if (delta0PDH) { var riskMarket = market.SearchForPerturbedPricingStructures(DiscountCurveName, "delta0PDH");//TODO The fx deltas analyticModelParameters.Delta1PDHCurves = riskMarket; analyticModelParameters.Delta1PDHPerturbation = 10; } if (modelData.ReportingCurrency.Value != PaymentCurrency.Value) { string curveName = MarketEnvironmentHelper.ResolveFxCurveNames(PaymentCurrency.Value, modelData.ReportingCurrency.Value); fxCurve = (IFxCurve)market.SearchForPricingStructureType(curveName); fxCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; analyticModelParameters.ReportingCurrencyFxCurve = fxCurve; } if (HybridValuation) { var currency1RateCurve = (IRateCurve)market.SearchForPricingStructureType(Currency1DiscountCurveName); currency1RateCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; var currency2RateCurve = (IRateCurve)market.SearchForPricingStructureType(Currency2DiscountCurveName); currency2RateCurve.PricingStructureEvolutionType = PricingStructureEvolutionType; AnalyticsModel = new FxRateCashflowAnalytic(ModelData.ValuationDate, PaymentDate, currencyCurve, currency1RateCurve, currency2RateCurve, !InvertFxRate, IsSettlementInCurrency1, fxCurve); } } // store inputs and results from this run AnalyticModelParameters = analyticModelParameters; if (!HybridValuation) { AnalyticsModel = new FxRateCashflowAnalytic(ModelData.ValuationDate, PaymentDate, fxCurve, currencyCurve, discountCurve); } //TODO Fix this with a generic index curve. //AnalyticsModel = analyticsModel; CalculationResults = AnalyticsModel.Calculate <IFloatingCashflowResults, FloatingCashflowResults>(AnalyticModelParameters, metrics.ToArray()); CalculationPerformedIndicator = true; PaymentDiscountFactor = ((FxRateCashflowAnalytic)AnalyticsModel).PaymentDiscountFactor; ForecastAmount = MoneyHelper.GetAmount(CalculationResults.LocalCurrencyExpectedValue, PaymentAmount.currency); NPV = MoneyHelper.GetAmount(CalculationResults.LocalCurrencyNPV, PaymentAmount.currency); AssetValuation valuation = GetValue(CalculationResults, modelData.ValuationDate); valuation.id = Id; return(valuation); }
/// <summary> /// Creates a stream environment. /// </summary> /// <param name="baseDate"></param> /// <param name="discountCurve"></param> /// <param name="forecastCurve"></param> /// <param name="fxCurve"></param> /// <returns></returns> public static ISwapLegEnvironment CreateInterestRateStreamEnvironment(DateTime baseDate, IRateCurve discountCurve, IRateCurve forecastCurve, IFxCurve fxCurve) { var market = new SwapLegEnvironment(); market.AddPricingStructure(InterestRateStreamPSTypes.DiscountCurve.ToString(), discountCurve); market.AddPricingStructure(InterestRateStreamPSTypes.ForecastCurve.ToString(), forecastCurve); market.AddPricingStructure(InterestRateStreamPSTypes.ReportingCurrencyFxCurve.ToString(), fxCurve); return(market); }
/// <summary> /// Calculates the specified model data. /// </summary> /// <param name="modelData">The model data.</param> /// <returns></returns> public override BasicAssetValuation Calculate(IAssetControllerData modelData) { ModelData = modelData; AnalyticsModel = new InflationAssetAnalytic(); //DependencyCreator.Resolve<IModelAnalytic<ISimpleDualAssetParameters, RateMetrics>>("InflationAsset"); var metrics = MetricsHelper.GetMetricsToEvaluate(Metrics, AnalyticsModel.Metrics); // Determine if DFAM has been requested - if so thats all we evaluate - every other metric is ignored var bEvalDiscountFactorAtMaturity = false; if (metrics.Contains(RateMetrics.DiscountFactorAtMaturity)) { bEvalDiscountFactorAtMaturity = true; metrics.RemoveAll( metricItem => metricItem != RateMetrics.DiscountFactorAtMaturity); } ISimpleDualAssetParameters analyticModelParameters = new DualRateAssetParameters { YearFraction = YearFraction }; AnalyticResults = new RateAssetResults(); var metricsToEvaluate = metrics.ToArray(); var marketEnvironment = modelData.MarketEnvironment; IRateCurve curve = null; //1. instantiate curve if (marketEnvironment.GetType() == typeof(SimpleMarketEnvironment)) { curve = (IRateCurve)((ISimpleMarketEnvironment)marketEnvironment).GetPricingStructure(); CurveName = curve.GetPricingStructureId().UniqueIdentifier; } if (marketEnvironment.GetType() == typeof(SimpleRateMarketEnvironment)) { curve = ((ISimpleRateMarketEnvironment)marketEnvironment).GetRateCurve(); CurveName = curve.GetPricingStructureId().UniqueIdentifier; } if (marketEnvironment.GetType() == typeof(SwapLegEnvironment)) { curve = ((ISwapLegEnvironment)marketEnvironment).GetDiscountRateCurve(); CurveName = curve.GetPricingStructureId().UniqueIdentifier; } if (marketEnvironment.GetType() == typeof(MarketEnvironment)) { curve = (IRateCurve)modelData.MarketEnvironment.GetPricingStructure(CurveName); } //2. get start df = curve.getvalue(this._adjustedStartDate); analyticModelParameters.StartDiscountFactor = GetDiscountFactor(curve, AdjustedStartDate, modelData.ValuationDate); //3. Get the Rate analyticModelParameters.Rate = MarketQuoteHelper.NormalisePriceUnits(FixedRate, "DecimalRate").value; if (bEvalDiscountFactorAtMaturity) { //4. Set the anaytic input parameters and Calculate the respective metrics AnalyticResults = AnalyticsModel.Calculate <IRateAssetResults, RateAssetResults>(analyticModelParameters, metricsToEvaluate); EndDiscountFactor = DiscountFactorAtMaturity; } else { analyticModelParameters.NotionalAmount = Notional; //3. Get the end index discount factor analyticModelParameters.EndDiscountFactor = GetDiscountFactor(curve, GetRiskMaturityDate(), modelData.ValuationDate); //4. Get the payment discount factor analyticModelParameters.PaymentDiscountFactor = GetDiscountFactor(curve, GetRiskMaturityDate(), modelData.ValuationDate); //5. Set the anaytic input parameters and Calculate the respective metrics AnalyticResults = AnalyticsModel.Calculate <IRateAssetResults, RateAssetResults>(analyticModelParameters, metricsToEvaluate); } return(GetValue(AnalyticResults)); }
/// <summary> /// Initializes a new instance of the <see cref="PriceableSimpleOptionAsset"/> class. /// </summary> /// <param name="cache">The cache.</param> /// <param name="logger">The logger.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="baseDate">The base date.</param> /// <param name="expiryTenor">The expiry tenor.</param> /// <param name="underlyingAssetIdentifier">The underlying asset.</param> /// <param name="strike">The strike.</param> /// <param name="volatility">The volatility.</param> /// <param name="forecastCurve">The forecast rate curve.</param> /// <param name="discountCurve">The discount rate curve. Not used yet, as only the implied rate is caclulated.</param> /// <param name="fixingCalendar">The fixingCalendar.</param> /// <param name="rollCalendar">The rollCalendar.</param> public PriceableSimpleOptionAsset(ILogger logger, ICoreCache cache, string nameSpace, String underlyingAssetIdentifier, DateTime baseDate, Period expiryTenor, Decimal?strike, Decimal volatility, IRateCurve discountCurve, ICurve forecastCurve, IBusinessCalendar fixingCalendar, IBusinessCalendar rollCalendar) { UnderlyingAssetRef = underlyingAssetIdentifier; var expiryOffset = new Offset { period = expiryTenor.period, periodMultiplier = expiryTenor.periodMultiplier, periodSpecified = true, dayType = DayTypeEnum.Calendar, dayTypeSpecified = true }; var expiryDate = expiryOffset.Add(baseDate); var assetProperties = PriceableAssetFactory.BuildPropertiesForAssets(nameSpace, underlyingAssetIdentifier, expiryDate); var instrument = InstrumentDataHelper.GetInstrumentConfigurationData(cache, nameSpace, underlyingAssetIdentifier); var quotation = BasicQuotationHelper.CreateRate(0.05m); var quote = BasicAssetValuationHelper.Create(quotation); UnderlyingPriceableAsset = PriceableAssetFactory.Create(logger, cache, nameSpace, instrument, quote, assetProperties, fixingCalendar, rollCalendar); BaseDate = baseDate; ForwardIndex = UnderlyingPriceableAsset.CalculateImpliedQuote(forecastCurve); if (strike != null) { Strike = (Decimal)strike; } else { Strike = ForwardIndex; } DayCounter = new Actual365(); ExpiryDate = expiryDate; Volatility = volatility; TimeToExpiry = DayCounter.DayCount(BaseDate, ExpiryDate); }
/// <summary> /// Initiates a new model. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="paymentDate">The payment date of the cash flow.</param> /// <param name="reportingCurrencyFxCurve">THe fx curve. It must already be normalised.</param> /// <param name="indexCurve">The rate curve to use for calculating the forward index.</param> /// <param name="discountCurve">The rate curve to use for discounting.</param> public FxRateCashflowAnalytic(DateTime valuationDate, DateTime paymentDate, IFxCurve reportingCurrencyFxCurve, ICurve indexCurve, IRateCurve discountCurve) { ToReportingCurrencyRate = EvaluateReportingCurrencyFxRate(valuationDate, reportingCurrencyFxCurve); if (indexCurve != null) { FloatingIndex = (decimal)indexCurve.GetValue(new DateTimePoint1D(valuationDate, paymentDate)).Value; } if (discountCurve != null) { PaymentDiscountFactor = (decimal)discountCurve.GetDiscountFactor(valuationDate, paymentDate); } }
/// <summary> /// Initiates a new model. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="startDate">The start date of the coupon.</param> /// <param name="endDate">The end date of the coupon.</param> /// <param name="paymentDate">The payment date of the cash flow.</param> /// <param name="timeToIndex">The timeToIndex. Not necessarily the time to expiry. This is used for surface interpolation..</param> /// <param name="strike">The strike.</param> /// <param name="reportingCurrencyFxCurve">THe fx curve. It must already be normalised.</param> /// <param name="discountCurve">The rate curve to use for discounting.</param> /// <param name="forecastCurve">The forecast curve.</param> /// <param name="indexVolSurface">The index volatility surface.</param> public RateOptionCouponAnalytic(DateTime valuationDate, DateTime startDate, DateTime endDate, DateTime paymentDate, decimal timeToIndex, decimal strike, IFxCurve reportingCurrencyFxCurve, IRateCurve discountCurve, IRateCurve forecastCurve, IVolatilitySurface indexVolSurface) : base(valuationDate, startDate, endDate, paymentDate, reportingCurrencyFxCurve, discountCurve, forecastCurve) { Strike = strike; TimeToIndex = timeToIndex; Volatility = (decimal)indexVolSurface.GetValue((double)timeToIndex, (double)strike); }
/// <summary> /// This assumes that the rest dates are consistent with the curve. /// </summary> /// <param name="valuationDate"></param> /// <param name="paymentDate">The payment date. The same rest period is assumed as with the spot date.</param> /// <param name="indexCurve">The index curve should be already in the correct form for the fx.</param> /// <param name="currency2">Normally the foreign rate curve.</param> /// <param name="currency2PerCurrency1">The currency2PerCurrency1 flag. </param> /// <param name="currency1">Normally the domestic rate curve. </param> /// <param name="currency1Settlement">Does settlement occur in currency1. If not, then it must be currency2. </param> /// <param name="reportingCurrencyFxCurve">The reporting current fx curve from settlement currency to reporting currency. It must already be normalised.</param> public FxRateCashflowAnalytic(DateTime valuationDate, DateTime paymentDate, IFxCurve indexCurve, IRateCurve currency1, IRateCurve currency2, bool currency2PerCurrency1, bool currency1Settlement, IFxCurve reportingCurrencyFxCurve) { ToReportingCurrencyRate = EvaluateReportingCurrencyFxRate(valuationDate, reportingCurrencyFxCurve); var todayRate = indexCurve.GetForward(valuationDate, valuationDate); //TODO The spot rate may not be the same due to the carry effect, but the evolution works. var df1 = currency1.GetDiscountFactor(valuationDate, paymentDate); var df2 = currency2.GetDiscountFactor(valuationDate, paymentDate); var forward = df1 / df2; if (!currency2PerCurrency1) { forward = df2 / df1; } FloatingIndex = (decimal)(todayRate * forward); if (currency1Settlement) { PaymentDiscountFactor = (decimal)currency1.GetDiscountFactor(valuationDate, paymentDate); } else { PaymentDiscountFactor = (decimal)currency2.GetDiscountFactor(valuationDate, paymentDate); } }
/// <summary> /// Gets the discount factors. /// </summary> /// <param name="discountFactorCurve">The discount factor curve.</param> /// <param name="periodDates">The period dates.</param> /// <param name="valuationDate">The valuation date.</param> /// <returns></returns> public Decimal[] GetDiscountFactors(IRateCurve discountFactorCurve, IList <DateTime> periodDates, DateTime valuationDate) { return(periodDates.Select(periodDate => GetDiscountFactor(periodDate, valuationDate, discountFactorCurve)).ToArray()); }
/// <summary> /// This routine finds the average of the index and the volatility between PaymentStart and PaymentEnd. /// AveFrequency determines the daily averaging frequency /// e.g.AveFrequency = 1 finds average of daily values; /// AveFrequency = 7 finds average of weekly values etc. /// PaymentEnd is not included in the averaging calculation. /// It is assumed that PaymentStart and PaymentEnd have already been adjusted to be business days /// Each AverageDate is calculated by adding on the correct number of business days /// PaymentRateSet is the sum of the rates that have already been fixed in the period. /// This is added onto the sum of the forward rates and the average calculated by dividing /// the total sum by the number of averaging points in the period /// Holidays: Index Start is appropriate working day for the Average Date /// Index Set is two working days prior to this Index Start /// Index End is the appropriate working day following addition of the tenor /// </summary> /// <param name="valueDate"></param> /// <param name="discountCurve"></param> /// <param name="indexCurve"></param> /// <param name="paymentStart"></param> /// <param name="paymentEnd"></param> /// <param name="indexDaycount"></param> /// <param name="indexTenor"></param> /// <param name="indexCoupon"></param> /// <param name="paymentRateSet"></param> /// <param name="indexRateSet"></param> /// <param name="averagingFrequency"></param> /// <param name="averagePreset"></param> /// <param name="indexCity"></param> /// <param name="convention"></param> /// <param name="volatilityMargin"></param> /// <param name="indexVolatility"></param> /// <returns></returns> public static Double? GetAverageRate(DateTime valueDate, IRateCurve discountCurve, IRateCurve indexCurve, DateTime paymentStart, DateTime paymentEnd, int indexDaycount, int indexTenor, int indexCoupon, double paymentRateSet, double indexRateSet, int averagingFrequency, int averagePreset, long indexCity, int convention, double volatilityMargin, IVolatilitySurface indexVolatility) { long indexSet, indexStart, indexEnd; double sumRate = 0.0; double sumVol = 0.0; double firstVol = 0.0; var averageDate = paymentStart; int numAvePoints = 0; if (indexCurve is null) return null; //Do simple approximation i.e. divide the sum of the start and end values by two if (averagingFrequency <= 0) { DateTime Ave_Index_Start, Ave_Index_End; //Calculate the fixing date for the start date of the period long firstSet = AddWorkDays(PaymentStart, Ave_Preset, Index_City, CHoliday::PRECEEDING); //Calculate the fixing date for the end date of the period long lastSet = AddWorkDays(PaymentEnd, Ave_Preset, Index_City, CHoliday::PRECEEDING); if (valueDate >= lastSet) { IndexVolatility = 0.0; return Payment_Rateset / 2.0; //Both the start and the end rates have been fixed } double firstRate; if (valueDate < firstSet) { Index_Start = PaymentStart; Date Ave_Index_Start = Index_Start; Date Ave_Index_End = Ave_Index_Start.AddMonths(ConvertToMonths(Index_Tenor)); Index_End = GoodDay(Ave_Index_End.GetJulian(), Index_City, Convention); long Index_Tenor_Days = (long) (Index_End - Index_Start); long IndexExpiry = (long) (firstSet - Value_Date); firstRate = _GetIndex(Value_Date, firstSet, Index_Start, Index_End, Index_Tenor, Index_Daycount, Index_Coupon, Index_Coupon, *pIndexCurve, Index_Rateset); // SAJ 25/9/96 Added Volatility margin to volatility to allow for bumping firstVol = GetVolatility(CapsVolName, SwaptVolName, IndexExpiry, Index_Tenor_Days, 0.0) + VolatilityMargin; // SAJ 25/9/96 Added following lines for convexity effect double Weight, AdjForward; GetModifiedForward(Value_Date, PaymentEnd, firstSet, Index_Start, Index_End, Index_Tenor, Index_Coupon, Index_Daycount, *pIndexCurve, firstRate, firstVol, Weight, AdjForward); firstRate = Weight * firstRate + (1 - Weight) * AdjForward; // SAJ 25/9/96 End } else { firstRate = Payment_Rateset; firstVol = 0.0; } Index_Start = PaymentEnd; Ave_Index_Start = Index_Start; Ave_Index_End = Ave_Index_Start.AddMonths(ConvertToMonths(Index_Tenor)); Index_End = GoodDay(Ave_Index_End.GetJulian(), Index_City, Convention); long Index_Tenor_Days = (long) (Index_End - Index_Start); long IndexExpiry = (long) (lastSet - Value_Date); double lastRate = _GetIndex(Value_Date, lastSet, Index_Start, Index_End, Index_Tenor, Index_Daycount, Index_Coupon, Index_Coupon, *pIndexCurve, Index_Rateset); // SAJ 25/9/96 Added Volatility margin to volatility to allow for bumping double LastVol = GetVolatility(CapsVolName, SwaptVolName, IndexExpiry, Index_Tenor_Days, 0.0) + VolatilityMargin; // SAJ 25/9/96 Added following lines for convexity effect double Weight, AdjForward; GetModifiedForward(Value_Date, PaymentEnd, lastSet, Index_Start, Index_End, Index_Tenor, Index_Coupon, Index_Daycount, *pIndexCurve, lastRate, LastVol, Weight, AdjForward); lastRate = Weight * lastRate + (1 - Weight) * AdjForward; // SAJ 25/9/96 End IndexVolatility = (firstVol + LastVol) / 2.0 + VolatilityMargin; return (firstRate + lastRate) / 2.0; } //Check if already into the averaging loop or the period is historical if (valueDate > PaymentStart) { sumRate = Payment_Rateset; sumVol = 0.0; } //Begin the averaging loop while (averageDate < PaymentEnd) { //Calculate the index setting date Index_Set = AddWorkDays(AverageDate, Ave_Preset, Index_City, CHoliday::PRECEEDING); if (Value_Date < Index_Set) { Date Ave_Index_Start = AverageDate; Date Ave_Index_End = Ave_Index_Start.AddMonths(ConvertToMonths(Index_Tenor)); Index_End = GoodDay(Ave_Index_End.GetJulian(), Index_City, Convention); long Index_Tenor_Days = (long) (Index_End - AverageDate); long IndexExpiry = (long) (Index_Set - Value_Date); double NewRate = _GetIndex(Value_Date, Index_Set, AverageDate, Index_End, Index_Tenor, Index_Daycount, Index_Coupon, Index_Coupon, *pIndexCurve, Index_Rateset); // SAJ 25/9/96 Added Volatility margin to volatility to allow for bumping double newVol = GetVolatility(CapsVolName, SwaptVolName, IndexExpiry, Index_Tenor_Days, 0.0) + VolatilityMargin; // SAJ 25/9/96 Added following lines for convexity effect double weight, adjForward; GetModifiedForward(Value_Date, PaymentEnd, Index_Set, AverageDate, Index_End, Index_Tenor, Index_Coupon, Index_Daycount, *pIndexCurve, NewRate, newVol, weight, adjForward); NewRate = weight * NewRate + (1 - weight) * adjForward; // SAJ 25/9/96 End sumRate += NewRate; sumVol += (newVol * newVol); } numAvePoints++; // Increment average date by the averaging frequency // Here should make the convention Following otherwise will not get out of the end of the month // SAJ 25/9/96 Changed the following line to add AveFrequency days and then check good days // AverageDate = AddWorkDays(AverageDate, AveFrequency, Index_City, CHoliday::FOLLOWING); averageDate += AveFrequency; averageDate = GoodDay(AverageDate, Index_City, CHoliday::FOLLOWING); // Use following to prevent chattering // SAJ 25/9/96 End } IndexVolatility = Math.Sqrt(sumVol / numAvePoints) + volatilityMargin; return sumRate / numAvePoints; }
/// <summary> /// /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="valueDate"></param> /// <param name="effectiveDate"></param> /// <param name="terminationDate"></param> /// <param name="interpolationMethod"></param> /// <param name="margineAboveFloatingRate"></param> /// <param name="resetRate"></param> /// <param name="notional"></param> /// <param name="directionDateGenerationPayLeg"></param> /// <param name="cashFlowFrequencyPayLeg"></param> /// <param name="accrualMethodPayLeg"></param> /// <param name="holidaysPayLeg"></param> /// <param name="rateCurvePayLeg"></param> /// <param name="directionDateGenerationRecLeg"></param> /// <param name="cashFlowFrequencyRecLeg"></param> /// <param name="accrualMethodRecLeg"></param> /// <param name="holidaysRecLeg"></param> /// <param name="rateCurveRecLeg"></param> /// <param name="layout"> /// if 0 - cashflows displayed one under another, /// if 1 - cashflows displayed side by side. /// </param> /// <returns> /// Pay cashflows: /// /// /// /// Rec cashflows: /// /// /// </returns> public object[,] GetSwapCashflowsWithoutCurves ( ILogger logger, ICoreCache cache, String nameSpace, DateTime valueDate, DateTime effectiveDate, DateTime terminationDate, string interpolationMethod, //1 is linear on forward rates => make sure that the right curve is provided ... double margineAboveFloatingRate, // use 0 initially double resetRate, decimal notional, int directionDateGenerationPayLeg, string cashFlowFrequencyPayLeg, string accrualMethodPayLeg, string holidaysPayLeg, IRateCurve rateCurvePayLeg, int directionDateGenerationRecLeg, string cashFlowFrequencyRecLeg, string accrualMethodRecLeg, string holidaysRecLeg, IRateCurve rateCurveRecLeg, int layout ) { // received fixed leg // var recFixedCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, notional, directionDateGenerationRecLeg, cashFlowFrequencyRecLeg, accrualMethodRecLeg, holidaysRecLeg, rateCurvePayLeg, true); // pay floating leg // var payFloatingCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, notional, directionDateGenerationPayLeg, cashFlowFrequencyPayLeg, accrualMethodPayLeg, holidaysPayLeg, rateCurveRecLeg, false); var objectiveFunction = new InterestRateSwapPricer { ReceiveLeg = recFixedCashflows, PayLeg = payFloatingCashflows }; var solver = new Brent { LowerBound = -100.0, UpperBound = 100.0 }; solver.Solve(objectiveFunction, Accuracy, Guess, Step); // bool bothLegsHaveTheSameStructure = // directionDateGenerationPayLeg == directionDateGenerationRecLeg && // cashFlowFrequencyPayLeg == cashFlowFrequencyRecLeg && // holidaysPayLeg == holidaysRecLeg; // if 0 - cashflows displayed one under another, // if 1 - cashflows displayed side by side. var result = 1 == layout?Utilities.GetCashflowsSideBySideExcelRange(payFloatingCashflows.Coupons, recFixedCashflows.Coupons) : Utilities.GetCashflowsOneUnderAnotherExcelRange(payFloatingCashflows.Coupons, recFixedCashflows.Coupons); return(result); }
/// <summary> /// Initiates a new model. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="paymentDate">The payment date of the cash flow.</param> /// <param name="reportingCurrencyFxCurve">The fx curve. It must already be normalised.</param> /// <param name="discountCurve">The rate curve to use for discounting.</param> public CashflowAnalytic(DateTime valuationDate, DateTime paymentDate, IFxCurve reportingCurrencyFxCurve, IRateCurve discountCurve) { ToReportingCurrencyRate = EvaluateReportingCurrencyFxRate(valuationDate, reportingCurrencyFxCurve); PaymentDiscountFactor = EvaluateDiscountFactor(valuationDate, paymentDate, discountCurve); var paymentDiscountFactor = PaymentDiscountFactor; var days = (paymentDate - valuationDate).Days; if (days == 0) { days = 1; paymentDiscountFactor = EvaluateDiscountFactor(valuationDate, paymentDate.AddDays(1), discountCurve); } var time = days / 365.25; ContinuousRate = -(Decimal)(Math.Log((double)paymentDiscountFactor) / time); }
internal static double GetAdjustedDiscountFactor(DateTime baseDate, DateTime baseCurveDate, IDayCounter dayCounter, double zeroRateSpread, IRateCurve baseCurve) { const double compoundingPeriod = 0.25; // Convert to Zero Rate double yearFraction = dayCounter.YearFraction(baseDate, baseCurveDate); double df0 = baseCurve.GetDiscountFactor(baseCurveDate); double z0 = RateAnalytics.DiscountFactorToZeroRate(df0, yearFraction, compoundingPeriod); // Add the spread double z = z0 + zeroRateSpread; // Change back double discountFactor = RateAnalytics.ZeroRateToDiscountFactor(z, yearFraction, compoundingPeriod); return(discountFactor); }
/// <summary> /// Evaluating the discount factor rate. /// </summary> /// <returns>The discount factor</returns> protected decimal EvaluateDiscountFactor(DateTime valuationDate, DateTime date, IRateCurve discountCurve) { var result = 1.0m; if (discountCurve != null) { result = (decimal)discountCurve.GetDiscountFactor(valuationDate, date); } return(result); }
/// <summary> /// This assumes that the rest dates are consistent with the curve. /// </summary> /// <param name="valuationDate">The valuation date.</param> /// <param name="paymentDate">The payment date. The same rest period is assumed as with the spot date.</param> /// <param name="indexCurve">The index curve should be already in the correct form for the fx.</param> /// <param name="currency2">Normaly the foreign rate curve.</param> /// <param name="currency2PerCurrency1">The currency2PerCurrency1 flag. </param> /// <param name="currency1">Normally the domestic rate curve. </param> /// <param name="expiryTime">The expiry time. </param> /// <param name="timeToIndex">The time to reset or expiry. </param> /// <param name="indexVolSurface">The index volatility surface.</param> /// <param name="currency1Settlement">Is the currency1 the settlement currency? </param> /// <param name="strike">The strike. </param> /// <param name="reportingCurrencyFxCurve">The reporting current fx curve from settlement currency to reporting currency. It must already be normalised.</param> /// <param name="fxOptionType">The option type. </param> public FxOptionAnalytic(DateTime valuationDate, DateTime paymentDate, IFxCurve indexCurve, IRateCurve currency1, IRateCurve currency2, bool currency2PerCurrency1, bool currency1Settlement, decimal strike, decimal expiryTime, decimal timeToIndex, IVolatilitySurface indexVolSurface, FxOptionType fxOptionType, IFxCurve reportingCurrencyFxCurve) : base(valuationDate, paymentDate, indexCurve, currency1, currency2, currency2PerCurrency1, currency1Settlement, reportingCurrencyFxCurve) { OptionType = fxOptionType; Strikes = new List <decimal> { strike }; ExpiryTimes = new List <decimal> { expiryTime }; TimeToIndices = new List <decimal> { timeToIndex }; Volatilities = new List <decimal> { (decimal)indexVolSurface.GetValue((double)timeToIndex, (double)strike) }; }
/// <summary> /// /// </summary> /// <param name="referenceCurve"></param> /// <param name="isBaseCurve"></param> /// <param name="derivedCurveProperties"></param> /// <returns></returns> public IRateCurve GenerateRateCurve(IRateCurve referenceCurve, bool isBaseCurve, NamedValueSet derivedCurveProperties) { throw new NotImplementedException(); }