private double RepoCostRate() { var fundingCurve = _market.RiskfreeCurve.HasValue ? _market.RiskfreeCurve.Value : YieldCurve.GetConstRateCurve(_market.DiscountCurve.Value, 0.0); return(fundingCurve.GetCompoundedRate2(_market.ValuationDate, _bondFuture.UnderlyingMaturityDate) - 1.0); }
/// <summary> /// Determine the value of the caplet using the Black-Caplet-formula /// </summary> /// <returns></returns> public double Value(YieldCurve yieldCurve, double delta, Func <double, double> volatilityFunc) { // valuation date var valuationDate = yieldCurve.SettleDate; var T = Utilities.ConvertToDayCountFraction(valuationDate, FixingDate); Func <double, double> func = t => volatilityFunc(T - t) * volatilityFunc(T - t); var sigma = Math.Sqrt(1 / T * Integrate.OnClosedInterval(func, 0, T)); var tenor = Utilities.ConvertToDayCountFraction(FixingDate, ExpiryDate); var bond = yieldCurve.GetDiscountFactors(new [] { FixingDate, ExpiryDate }); var kappa = CapRate / (Tenor * Principal) + delta; var spotForwardRate = 1 / tenor * (bond[0] / bond[1] - 1); var logLK = Math.Log((spotForwardRate + delta) / (kappa)); var gamma = T * sigma * sigma; var dPlus = (logLK + 0.5 * gamma) / Math.Sqrt(gamma); var dMinus = (logLK - 0.5 * gamma) / Math.Sqrt(gamma); return(bond[1] * Principal * Tenor * (spotForwardRate * Normal.CDF(0, 1, dPlus) - kappa * Normal.CDF(0, 1, dMinus))); }
public static void AssertSensibleValue(YieldCurve value) { AssertSensibleValue(value.Curve); if (!value.Curve.IsVirtual) { var interestRate = value.GetInterestRate(value.Curve.XData[0]); AssertSensibleValue(interestRate); Assert.InRange(interestRate, -2, 2); var discountFactor = value.GetDiscountFactor(value.Curve.XData[0]); AssertSensibleValue(discountFactor); } }
private void visualizerButton_Click(object sender, RoutedEventArgs e) { YieldCurve yc = ((PricingRequestWithResult)requestsListBox.SelectedItem).Request.Ycs.get(); DiscountCurve dc = (DiscountCurve)yc; //IProcess hwp = new HullWhiteCalibrator().Calibrate(dc); IProcess rsp = RSCalibrator.Calibrate(dc); //var visualizerWindow1 = new ProcessVisualizer(yc, hwp); var visualizerWindow2 = new ProcessVisualizer(yc, rsp); visualizerWindow2.Show(); }
/// <summary> /// More general Constructor /// </summary> /// <param name="yieldCurve"></param> /// <param name="correlation"></param> /// <param name="volatility"></param> /// <param name="tenorStructure"></param> /// <param name="randomSeed"></param> public LiborMarketModel(YieldCurve yieldCurve, Matrix <double> correlation, Func <double, double>[] volatility, DateTime[] tenorStructure, int randomSeed = 42) { YieldCurve = yieldCurve; RandomGenerator = new MersenneTwister(randomSeed); Correlation = correlation; Volatility = volatility; SettleDate = yieldCurve.SettleDate; // Use continuous time in units of years for tenor structure T = Vector <double> .Build .DenseOfEnumerable(Utilities.ConvertToDayCountFraction(SettleDate, tenorStructure)); // Initial discount factors: T[i] :-> B(0, T[i]) i =0, ..., n = length(T)-1 InitialDiscountFactor = yieldCurve.GetDiscountFactors(tenorStructure); #region Tenors // tenors (day-count fraction) in units of [years] // Alpha[i] = T[i]-T[i+1], i = 0,...,n - 1 Alpha = Vector <double> .Build.DenseOfEnumerable(T.Skip(1)) - Vector <double> .Build.DenseOfEnumerable(T.Take(T.Count - 1)); // Choose terminal measure, can be an value between 0,..., n = length(T)-1 NumeraireIndex = T.Count - 1; #endregion Tenors #region Initial Forward rate NumRates = T.Count - 1; // B[i] var zeroBond0 = Vector <double> .Build .DenseOfEnumerable(InitialDiscountFactor.Take(NumRates)); // B[i+1] var zeroBond1 = Vector <double> .Build .DenseOfEnumerable(InitialDiscountFactor.Skip(1)); // Initial forward LIBOR rate // L[i] = L(0, T[i],T[i+1]) = 1/alpha[i] * (B[i]/B[i+1] - 1); i = 0,..., n - 1 // L[i](t) : 0 <= t <= T[i] InitialForwardRate = (zeroBond0.PointwiseDivide(zeroBond1).Subtract(1)).PointwiseDivide(Alpha); #endregion Initial Forward rate // Delta for smile Delta = Vector <double> .Build.Dense(NumRates); }
/// <summary> /// Standard constructor for Libor market model /// </summary> /// <param name="zeroCurve"></param> /// <param name="correlationBeta"></param> /// <param name="volatilityParamaters"></param> /// <param name="tenorStructure"></param> /// <param name="randomSeed"></param> public LiborMarketModel(YieldCurve zeroCurve, double correlationBeta, double[] volatilityParamaters, DateTime[] tenorStructure, int randomSeed = 42) : this(zeroCurve, null, null, tenorStructure, randomSeed) { #region Correlation Func <int, int, double> correlationFunction = (i, j) => Math.Exp(-correlationBeta * (Math.Abs(T[i] - T[j]))); // Build corellation matrix dW(t) * dW(t)^T = correlation * dt Correlation = Matrix <double> .Build .Dense(NumRates, NumRates) .MapIndexed((i, j, p) => correlationFunction(i, j)); #endregion Correlation #region Volatility // Check volatility parameters if (volatilityParamaters == null || volatilityParamaters.Count() != 4) { throw new ArgumentException("There are four volatility parameters expected"); } // Use the volatility term structure populaized by Riccardo Rebonato // sigma_i(t) = (a * tau + b) * Math.Exp(-c * tau) + d; with tau = T[i] - t // t is assumed to be in units of [years] Func <double, double> volatilityFunc = t => { var a = volatilityParamaters[0]; var b = volatilityParamaters[1]; var c = volatilityParamaters[2]; var d = volatilityParamaters[3]; return((a * t + b) * Math.Exp(-c * t) + d); }; // Vector of volatility functions, each corresponds to forward // LIBOR rate of the same index Volatility = new Func <double, double> [NumRates].Select(p => volatilityFunc) .ToArray(); #endregion Volatility }
public static Market CreateYieldCurveConfiguration(string curveId, QuotedAssetSet quotedAssetSet) { var market = new Market { id = curveId }; //Create the curve information. var curve = new YieldCurve { id = curveId }; //reate the valuation structure that contains qas. var curveValuation = new YieldCurveValuation { id = curveId, inputs = quotedAssetSet }; //Set the market. market.Items = new[] { (PricingStructure)curve }; market.Items1 = new[] { (PricingStructureValuation)curveValuation }; return(market); }
public void TestUsingDerivedTypes() { // tests control of the serialisation type // - type b (derived from a) is saved as b, loaded as b; // - type b (derived from a) is saved as a, loaded as a (but is type b). // (in this example a = PricingStructure, b = YieldCurve) using (Reference <ILogger> loggerRef = Reference <ILogger> .Create(new TraceLogger(true))) { using (ICoreClient client = new PrivateCore(loggerRef.Target)) { { YieldCurve dataA = new YieldCurve() { currency = new Currency() { Value = "USD" }, algorithm = "FastCubicSpline" }; // - save as derived type client.SaveObject(dataA, "TestA", null, TimeSpan.MaxValue); ICoreItem test1 = client.LoadItem <YieldCurve>("TestA"); Assert.IsNotNull(test1); Assert.AreEqual(typeof(YieldCurve).FullName, test1.DataTypeName); Assert.AreEqual(typeof(YieldCurve), test1.DataType); Assert.IsNotNull(test1.Data); Assert.AreEqual(typeof(YieldCurve), test1.Data.GetType()); // - save as base type client.SaveObject <PricingStructure>(dataA, "TestA", null, TimeSpan.MaxValue); ICoreItem test2 = client.LoadItem <PricingStructure>("TestA"); Assert.IsNotNull(test2); Assert.AreEqual(typeof(PricingStructure).FullName, test2.DataTypeName); Assert.AreEqual(typeof(PricingStructure), test2.DataType); Assert.IsNotNull(test2.Data); Assert.AreEqual(typeof(YieldCurve), test2.Data.GetType()); } { FxCurve dataB = new FxCurve() { quotedCurrencyPair = new QuotedCurrencyPair() { currency1 = new Currency { Value = "USD" }, currency2 = new Currency { Value = "JPY" }, quoteBasis = QuoteBasisEnum.Currency2PerCurrency1 } }; // - save as derived type client.SaveObject(dataB, "TestB", null, TimeSpan.MaxValue); ICoreItem test1 = client.LoadItem <FxCurve>("TestB"); Assert.IsNotNull(test1); Assert.AreEqual(typeof(FxCurve).FullName, test1.DataTypeName); Assert.AreEqual(typeof(FxCurve), test1.DataType); Assert.IsNotNull(test1.Data); Assert.AreEqual(typeof(FxCurve), test1.Data.GetType()); // - save as base type client.SaveObject <PricingStructure>(dataB, "TestB", null, TimeSpan.MaxValue); ICoreItem test2 = client.LoadItem <PricingStructure>("TestB"); Assert.IsNotNull(test2); Assert.AreEqual(typeof(PricingStructure).FullName, test2.DataTypeName); Assert.AreEqual(typeof(PricingStructure), test2.DataType); Assert.IsNotNull(test2.Data); Assert.AreEqual(typeof(FxCurve), test2.Data.GetType()); } { // load a collection of the base type and verify specific types List <ICoreItem> items = client.LoadItems <PricingStructure>(Expr.ALL); Assert.AreEqual(2, items.Count); Dictionary <string, PricingStructure> index = new Dictionary <string, PricingStructure>(); foreach (ICoreItem item in items) { index[item.Name] = (PricingStructure)item.Data; } Assert.AreEqual(typeof(YieldCurve), index["TestA"].GetType()); Assert.AreEqual(typeof(FxCurve), index["TestB"].GetType()); } } } }
/// <summary> /// Determine the value of the caplet using the Black-Caplet-formula /// </summary> /// <returns></returns> public double Value(YieldCurve yieldCurve, double delta, Func <double, double> volatilityFunction) { return(Caplets.Sum(caplet => caplet.Value(yieldCurve, delta, volatilityFunction))); }
/// <summary> /// Test cap pricing function /// </summary> private static void TestCapPricing(string resultFile) { #region Cap // 1 EUR var principal = 1; // Consider a ten-year semi-annual European swaption (10y x 5y), exercisable on each // reset date, starting on 1-October-2020 var valuationDate = new DateTime(2015, 10, 1); // Exercise date of the option = start date of swap var startDate = valuationDate.AddYears(2); // Strike (fixed interest rate payed by fixed leg) var capRate = 0.045; // Tenor of the underlying swap in units of [months] // = floating leg pays 6M-Libor var tenor = 6; const int numberOfCaplets = 10; var cap = new Cap(startDate, tenor, numberOfCaplets, capRate, principal); #endregion Cap #region Initialize LIBOR market model #region Initial yield curve // Sample points of curve in units of [years] var curveTimes = new[] { 1, 2, 3, 4, 5, 7, 10, 20 }; // annual interest rate in units of [1/year] var yields = new[] { 0.01, 0.018, 0.024, 0.029, 0.033, 0.034, 0.035, 0.034 }; var maturityDates = curveTimes.Select(y => valuationDate.AddYears(y)).ToArray(); var yieldCurve = new YieldCurve(valuationDate, maturityDates, yields); #endregion Initial yield curve #region Model parameters // Use the volatility term structure populaized by Riccardo Rebonato // sigma_i(t) = (a * tau + b) * Math.Exp(-c * tau) + d; with tau = T[i] - t // t is assumed to be in units of [years] var volatilityParamaters = new[] { 0.3, -0.02, 0.7, 0.14 }; // Instantaneous correlations between the Brownian motions // and hence the forward LIBOR rates // rho(i,j) = exp(-beta * |T[i] - T[j]|) const double beta = 0.08; #endregion Model parameters var seed = DateTime.Now.Millisecond; var liborMarketModel = new LiborMarketModel(yieldCurve, beta, volatilityParamaters, cap.TenorStructure, seed); #endregion Initialize LIBOR market model #region Pricing #region Cap rates const int nCapRates = 100; const double capRateMin = 0; const double capRateMax = 0.4; const double step = (capRateMax - capRateMin) / (nCapRates - 1); var capRates = new double[nCapRates]; for (var j = 0; j < capRates.Length; j++) { capRates[j] = capRateMin + step * j; } #endregion Cap rates #region Monte Carlo const int numberOfMonteCarloPaths = 100; var prices = new double[nCapRates]; for (var i = 0; i < numberOfMonteCarloPaths; i++) { // Simulate forward LIBOR rate paths using Monto carlo simulation up to the // exercise date of the swaption var paths = liborMarketModel.SimulateForwardRates(cap.MaturityDate); for (var j = 0; j < capRates.Length; j++) { cap.CapRate = capRates[j]; prices[j] += cap.DiscountedPayoff(paths) / numberOfMonteCarloPaths; } // Utilities.DrawTextProgressBar(i + 1, numberOfMonteCarloPaths, "Monte Carlo"); } #endregion Monte Carlo #region Black-Caplet formula // Use the volatility term structure populaized by Riccardo Rebonato // sigma_i(t) = (a * tau + b) * Math.Exp(-c * tau) + d; with tau = T[i] - t // t is assumed to be in units of [years] Func <double, double> volatilityFunction = t => { var a = volatilityParamaters[0]; var b = volatilityParamaters[1]; var c = volatilityParamaters[2]; var d = volatilityParamaters[3]; return((a * t + b) * Math.Exp(-c * t) + d); }; var blackPrices = new double[nCapRates]; for (var i = 0; i < capRates.Length; i++) { cap.CapRate = capRates[i]; blackPrices[i] = cap.Value(yieldCurve, 0, volatilityFunction); Utilities.DrawTextProgressBar(i + 1, capRates.Length, "Black-Caplet formula"); } #endregion Black-Caplet formula #endregion Pricing #region Export try { // create a writer and open the file var file = new StreamWriter(resultFile); for (var i = 0; i < capRates.Length; i++) { file.WriteLine("{0}\t{1}\t{2}", capRates[i], prices[i], blackPrices[i]); Utilities.DrawTextProgressBar(i + 1, capRates.Length, "Export results"); } file.Close(); } catch (Exception exception) { Console.WriteLine(exception.Message); } #endregion Export }
/// <summary> /// TODO: Get this code into MATLAB using the .NET interface /// Test swaption pricing /// </summary> private static void TestSwaptionPricing(string resultFile) { #region Swaption // 1 EUR var nominal = 1; // Consider a ten-year semi-annual European swaption (10y x 5y), exercisable on each // reset date, starting on 1-October-2020 var valuationDate = new DateTime(2015, 10, 1); // Exercise date of the option = start date of swap var exerciseDate = valuationDate.AddYears(2); // Maturity of the underlying swap var maturityDate = exerciseDate.AddYears(10); // Strike (fixed interest rate payed by fixed leg) var strike = 0.045; // Tenor of the underlying swap in units of [months] // = floating leg pays 6M-Libor var tenor = 6; var swaption = new Swaption(valuationDate, exerciseDate, maturityDate, tenor, strike, nominal); #endregion Swaption #region Initialize LIBOR market model #region Initial yield curve // Sample points of curve in units of [years] var curveTimes = new[] { 1, 2, 3, 4, 5, 7, 10, 20 }; // annual interest rate in units of [1/year] var yields = new[] { 0.01, 0.018, 0.024, 0.029, 0.033, 0.034, 0.035, 0.034 }; var maturityDates = curveTimes.Select(y => valuationDate.AddYears(y)).ToArray(); var yieldCurve = new YieldCurve(valuationDate, maturityDates, yields); #endregion Initial yield curve #region Model parameters // Use the volatility term structure populaized by Riccardo Rebonato // sigma_i(t) = (a * tau + b) * Math.Exp(-c * tau) + d; with tau = T[i] - t // t is assumed to be in units of [years] var volatiltyParameters = new[] { 0.3, -0.02, 0.7, 0.14 }; // Instantaneous correlations between the Brownian motions // and hence the forward LIBOR rates // rho(i,j) = exp(-beta * |T[i] - T[j]|) const double beta = 0.08; #endregion Model parameters const int seed = 41; var liborMarketModel = new LiborMarketModel(yieldCurve, beta, volatiltyParameters, swaption.TenorStructure, seed); #endregion Initialize LIBOR market model #region Strikes const int nStrikes = 100; const double strikeMin = 0; const double strikeMax = 0.1; const double step = (strikeMax - strikeMin) / (nStrikes - 1); var strikes = new double[nStrikes]; for (var j = 0; j < strikes.Length; j++) { strikes[j] = strikeMin + step * j; } #endregion Strikes #region Pricing const int numberOfMonteCarloPaths = 100; const int numberOfMonteCarloRuns = 100; var prices = new double[numberOfMonteCarloRuns, nStrikes]; for (var k = 0; k < numberOfMonteCarloRuns; k++) { Utilities.DrawTextProgressBar(k + 1, numberOfMonteCarloRuns, "Monte Carlo run"); for (var i = 0; i < numberOfMonteCarloPaths; i++) { // Simulate forward LIBOR rate paths using Monto carlo simulation up to the // exercise date of the swaption var paths = liborMarketModel.SimulateForwardRates(swaption.ExerciseDate); for (var j = 0; j < strikes.Length; j++) { swaption.Strike = strikes[j]; prices[k, j] += swaption.DiscountedPayoff(paths) / numberOfMonteCarloPaths; } } } #endregion Pricing #region Export try { // create a writer and open the file var file = new StreamWriter(resultFile); for (var j = 0; j < strikes.Length; j++) { file.Write("{0}\t", strikes[j]); for (var k = 0; k < numberOfMonteCarloRuns; k++) { file.Write("{0}", prices[k, j]); file.Write(k < numberOfMonteCarloRuns - 1 ? "\t" : "\n"); } Utilities.DrawTextProgressBar(j + 1, strikes.Length, "Export results"); } file.Close(); } catch (Exception exception) { Console.WriteLine(exception.Message); } #endregion Export }
/// <summary> /// Export /// </summary> private static void TestLiborMarketModel(string fowardrateFile, string yieldCurveFile) { #region Swaption // 1 EUR var nominal = 1; // Consider a ten-year semi-annual European swaption (10y x 5y), exercisable on each // reset date, starting on 1-October-2020 var valuationDate = new DateTime(2015, 10, 1); // Exercise date of the option = start date of swap var exerciseDate = valuationDate.AddYears(2); // Maturity of the underlying swap var maturityDate = exerciseDate.AddYears(10); // Strike (fixed interest rate payed by fixed leg) var strike = 0.045; // Tenor of the underlying swap in units of [months] // = floating leg pays 6M-Libor var tenor = 6; var swaption = new Swaption(valuationDate, exerciseDate, maturityDate, tenor, strike, nominal); #endregion Swaption #region Initialize LIBOR market model #region Initial yield curve // Sample points of curve in units of [years] var curveTimes = new[] { 1, 2, 3, 4, 5, 7, 10, 20 }; // annual interest rate in units of [1/year] var yields = new[] { 0.01, 0.018, 0.024, 0.029, 0.033, 0.034, 0.035, 0.036 }; var maturityDates = curveTimes.Select(y => valuationDate.AddYears(y)).ToArray(); var yieldCurve = new YieldCurve(valuationDate, maturityDates, yields); #endregion Initial yield curve #region Model parameters // Use the volatility term structure populaized by Riccardo Rebonato // sigma_i(t) = (a * tau + b) * Math.Exp(-c * tau) + d; with tau = T[i] - t // t is assumed to be in units of [years] var volatiltyParameters = new[] { 0.3, -0.02, 0.7, 0.14 }; // Instantaneous correlations between the Brownian motions // and hence the forward LIBOR rates // rho(i,j) = exp(-beta * |T[i] - T[j]|) const double beta = 0.08; #endregion Model parameters const int seed = 41; var liborMarketModel = new LiborMarketModel(yieldCurve, beta, volatiltyParameters, swaption.TenorStructure, seed); #endregion Initialize LIBOR market model var paths = liborMarketModel.SimulateForwardRates(swaption.ExerciseDate, 1); liborMarketModel.YieldCurve.Export(Path.Combine(DataFolder, yieldCurveFile)); paths.Export(Path.Combine(DataFolder, fowardrateFile)); }
public Dictionary <string, Dictionary <string, RateRecord> > CalcEquation(string calcType) { var psDict = new Dictionary <string, Dictionary <string, RateRecord> >(); var fundingCurve = _market.RiskfreeCurve.HasValue ? _market.RiskfreeCurve.Value : YieldCurve.GetConstRateCurve(_market.DiscountCurve.Value, 0.0); var reinvestmentCurve = _market.DiscountCurve.HasValue ? _market.DiscountCurve.Value : YieldCurve.GetConstRateCurve(_market.RiskfreeCurve.Value, 0.0); var bonds = _bondFuture.Deliverables; var length = bonds.Length; var resultRateRecord = new Dictionary <string, double> [length]; for (var i = 0; i < length; ++i) { var resultDic = new Dictionary <string, double>(); _bond = bonds[i]; var tfBondId = _bondFuture.Id + "_" + _bond.Id; _cleanPriceMktFlg = IsCleandPrice(_bond.Id); resultDic["AiStart"] = _bond.GetAccruedInterest(_market.ValuationDate, _market, false); resultDic["AiEnd"] = _bond.GetAccruedInterest(_bondFuture.UnderlyingMaturityDate, _market, false); resultDic["ConversionFactor"] = _bondFuture.GetConversionFactor(_bond, _market); resultDic["fundingRate"] = fundingCurve.GetSpotRate(0.0); _cashflows = _bond.GetCashflows(_market, false).Where(x => x.PaymentDate > _market.ValuationDate && x.PaymentDate <= _bondFuture.UnderlyingMaturityDate).ToArray(); if (_cashflows.Any()) { resultDic["Coupon"] = _cashflows.Sum(x => x.PaymentAmount); resultDic["TimeWeightedCoupon"] = _cashflows.Sum(x => x.PaymentAmount * _bondFuture.DayCount.CalcDayCountFraction(x.PaymentDate, _bondFuture.UnderlyingMaturityDate)); resultDic["couponsAccruedByReinvestment"] = _cashflows.Sum(x => x.PaymentAmount * (reinvestmentCurve.GetCompoundedRate2(x.PaymentDate, _bondFuture.UnderlyingMaturityDate) - 1.0)); } else { resultDic["Coupon"] = 0.0; resultDic["TimeWeightedCoupon"] = 0.0; resultDic["couponsAccruedByReinvestment"] = 0.0; } //Note: what is this interest income for? resultDic["InterestIncome"] = resultDic["AiEnd"] - resultDic["AiStart"]; // * resultDic["ConversionFactor"]; resultDic["interestCostRate"] = RepoCostRate(); resultDic["dt"] = _bondFuture.DayCount.CalcDayCountFraction(_market.ValuationDate, _bondFuture.UnderlyingMaturityDate); var inputValues = new double[3]; double calcMin = 0.0; double calcMax = 0.0; int changIndex = 0; FunctionVariable.UnivariateFunction fcn = null; switch (calcType) { case "FromFuturesPriceAndBondPrice": inputValues[0] = FuturePrice(); inputValues[1] = double.NaN; inputValues[2] = double.NaN; calcMin = -500.0; calcMax = 500.0; changIndex = 2; fcn = new FunctionVariable.UnivariateFunction(resultDic, IrrEquation, inputValues); break; case "FromBondPriceAndIrr": inputValues[0] = double.NaN; inputValues[1] = double.NaN; fcn = GetCalcEquation(tfBondId, inputValues, resultDic); calcMin = 1.0; calcMax = 50000.0; changIndex = 0; //BrentZero2<IUnivariateFunction>.DoSolve(fcn, 0.0, 50000.0, 0); break; case "FromFuturesPriceAndIrr": inputValues[0] = FuturePrice(); inputValues[1] = double.NaN; fcn = GetCalcEquation(tfBondId, inputValues, resultDic); calcMin = 1.0; calcMax = 50000.0; changIndex = 1; //BrentZero2<IUnivariateFunction>.DoSolve(fcn, calcMin, calcMax, changIndex); break; } BrentZero2 <IUnivariateFunction> .DoSolve(fcn, calcMin, calcMax, changIndex); resultRateRecord[i] = resultDic; } var resultKeyList = new List <string>() { "FuturesPrice" , "BondDirtyPrice" , "BondCleanPrice" , "BondYieldToMaturity" , "ConversionFactor" , "AiStart" , "AiEnd" , "Coupon" , "InterestIncome" , "InterestCost" , "PnL" , "InvoicePrice" , "Margin" , "Spread" , "Irr" , "Basis" , "NetBasis" , "ModifiedDuration" , "TimeWeightedCoupon" }; foreach (var resultKey in resultKeyList) { psDict[resultKey] = resultRateRecord.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x[resultKey] })).ToDictionary(x => x.Item1, x => x.Item2); } return(psDict); }
public static Tuple <Date, double>[] Calibrate( string name, Date referenceDate, IMarketInstrument[] marketInstruments, BusinessDayConvention bda, IDayCount daycount, ICalendar calendar, Compound compound, Interpolation interpolation, YieldCurveTrait trait, CurrencyCode currency, IMarketCondition baseMarket = null, Expression <Func <IMarketCondition, object> >[] expression = null, double initialValue = double.NaN, double initialGuess = 0.05, //double xmin = -0.9999, double xmin = -0.5, double xmax = 1.0 ) { var accuracy = 1.0e-14; if (marketInstruments.Any(x => x.Instrument is CreditDefaultSwap) || trait == YieldCurveTrait.DiscountCurve) { initialValue = 1.0; initialGuess = 1.0; xmin = 1.0e-64; } var len = marketInstruments.Length; var points = marketInstruments.Select(x => Tuple.Create(x.Instrument.GetCalibrationDate(), initialGuess)).ToList(); var calibrationStartIndex = 0; if (!double.IsNaN(initialValue)) { points.Insert(0, Tuple.Create(referenceDate, initialValue)); calibrationStartIndex = 1; } if (interpolation == Interpolation.ForwardFlat) { //forward flat interpolation, the final instrument is not needed in calibration points = points.Take(len - 1).ToList(); points.Insert(0, Tuple.Create(referenceDate, 0.05)); calibrationStartIndex = 0; } else if (trait == YieldCurveTrait.ForwardCurve) { points.Insert(0, Tuple.Create(referenceDate, 0.05)); calibrationStartIndex = 1; } baseMarket = baseMarket ?? new MarketCondition(x => x.ValuationDate.Value = referenceDate); expression = expression ?? new Expression <Func <IMarketCondition, object> >[] { x => x.DiscountCurve, x => x.FixingCurve }; IYieldCurve calibratedCurve = new YieldCurve(name, referenceDate, points.ToArray(), bda, daycount, calendar, currency, compound, interpolation, trait, baseMarket); var finalInstrument = marketInstruments.Last(); var smooth = (finalInstrument.Instrument is InterestRateSwap); double preCalibrationValue = 0.0; if (smooth) { preCalibrationValue = finalInstrument.Instrument.ModelValue( baseMarket.UpdateCondition(expression.Select(ex => (IUpdateMktConditionPack) new UpdateMktConditionPack <IYieldCurve>(ex, calibratedCurve)).ToArray()), finalInstrument.CalibMethod); } while (true) { for (var i = 0; i < len; ++i) { var calibrateFunc = new CalibrateMarketInstrument(marketInstruments[i], calibratedCurve, baseMarket, i + calibrationStartIndex, expression); //Note: alternative brent solver gives same result, but slower convergence, //var calibrateFunc = new CalibrateMarketInstrument2(marketInstruments[i], calibratedCurve, baseMarket, i + calibrationStartIndex, expression); double finalR; try { finalR = BrentZero.Solve(calibrateFunc, xmin, xmax, accuracy); //finalR = BrentZero2<IUnivariateFunction>.DoSolve(calibrateFunc, xmin, xmax, 0.05, 0); } catch (Exception ex) { throw new PricingLibraryException(string.Format("Error when bootstrapping {0}th point", i)); } calibratedCurve = UpdateKeyRate(calibratedCurve, i + calibrationStartIndex, finalR); } if (!smooth) { break; } else { var postCalibrationValue = finalInstrument.Instrument.ModelValue( baseMarket.UpdateCondition(expression.Select(ex => (IUpdateMktConditionPack) new UpdateMktConditionPack <IYieldCurve>(ex, calibratedCurve)).ToArray()), finalInstrument.CalibMethod); if (Math.Abs(postCalibrationValue - preCalibrationValue) < 1e-12) { break; } preCalibrationValue = postCalibrationValue; } } //if initial value is provided for 0D, 不插0D if (!double.IsNaN(initialValue)) { return(calibratedCurve.KeyPoints.ToArray()); } //NEVER EVER insert points at the end, inset at MOST ONE point at the beginning return(new[] { Tuple.Create(referenceDate, calibratedCurve.KeyPoints[0].Item2) } // Insert 0D point to avoid interpolation jump at the beginning .Union(calibratedCurve.KeyPoints) .ToArray()); }
public void testBondCurve1() { var bondIds = new[] { "1", "2", "3", "4", "5" }; var maturitys = new[] { "2017-10-28", "2018-10-28", "2019-10-28", "2020-10-28", "2021-10-28" }; var coupons = new[] { 0.0367, 0.0378, 0.04, 0.039, 0.041 }; var yields = new[] { 0.04, 0.041, 0.0415, 0.0425, 0.044 }; var bondInfos = bondIds.Select((x, i) => new FixedRateBondInfo(bondIds[i]) { StartDate = "2016-10-28", MaturityDate = maturitys[i], Notional = 100.0, Currency = "CNY", FixedCoupon = coupons[i], Calendar = "chn_ib", PaymentFreq = "SemiAnnual", PaymentStub = "LongEnd", AccrualDC = "ActActIsma", DayCount = "ActActIsma", AccrualBD = "None", PaymentBD = "None", TradingMarket = "ChinaInterBank", Settlement = "+0D", ValuationParamters = new SimpleCfValuationParameters("Fr007", null, "Fr007") } ).ToArray(); var bonds = bondInfos.Select(x => new BondVf(x).GenerateInstrument()).ToArray(); var marketInstrumetns = bonds.Select((x, i) => new MarketInstrument(bonds[i], yields[i], MktInstrumentCalibMethod.Default)).ToArray(); var referenceDate = new Date(2017, 03, 23); var yieldCurve = new YieldCurve( "中债国债收收益率曲线", referenceDate, marketInstrumetns.ToArray(), BusinessDayConvention.ModifiedFollowing, new Act365(), CalendarImpl.Get("chn_ib"), CurrencyCode.CNY, Compound.Continuous, Interpolation.ExponentialSpline, YieldCurveTrait.DiscountCurve, null, null, null, maturitys.Select(x => x.ToDate()).ToArray()); var term = new Term("1D"); var targetSpotRates = new[] { 0.0395360864, 0.0405725835, 0.0410856649, 0.0420840373, 0.0436655798, }; Console.WriteLine("Fitting error is {0}", yieldCurve.fittingError); for (var i = 0; i < yieldCurve.KeyPoints.Length; ++i) { Console.WriteLine("{0},{1},{2},{3}", yieldCurve.KeyPoints[i].Item1, yieldCurve.GetDf(yieldCurve.KeyPoints[i].Item1), yieldCurve.GetSpotRate(yieldCurve.KeyPoints[i].Item1), yieldCurve.ZeroRate(referenceDate, yieldCurve.KeyPoints[i].Item1)); if (i > 3) { Assert.AreEqual(yieldCurve.GetSpotRate(yieldCurve.KeyPoints[i].Item1), targetSpotRates[i - 4], 1e-10); } } Console.WriteLine(); var baseMarket = new MarketCondition( x => x.ValuationDate.Value = referenceDate, x => x.DiscountCurve.Value = null, x => x.FixingCurve.Value = null, x => x.HistoricalIndexRates.Value = new Dictionary <IndexType, SortedDictionary <Date, double> >() ); var bondCfs = marketInstrumetns.Select(x => (x.Instrument as Bond).GetCashflows(baseMarket, true)).ToList(); var bondPricer = new BondYieldPricer(); for (var i = 0; i < bondCfs.Count; ++i) { var pv = bondCfs[i].Select(cf => cf.PaymentAmount * yieldCurve.GetDf(referenceDate, cf.PaymentDate)).Sum(); var x = marketInstrumetns[i].Instrument as Bond; var mktPrice = bondPricer.FullPriceFromYield(bondCfs[i], x.PaymentDayCount, x.PaymentFreq, x.StartDate, referenceDate, marketInstrumetns[i].TargetValue, x.BondTradeingMarket, x.IrregularPayment); Console.WriteLine("{0},{1},{2}", pv, mktPrice, pv - mktPrice); } }
/// <summary> /// Calibrate implied bs vol from spot premium of an european option /// </summary> /// <param name="premium"></param> /// <param name="isCall"></param> /// <param name="strike"></param> /// <param name="spot"></param> /// <param name="rate"></param> /// <param name="expiryDateStr"></param> /// <param name="valuationDateStr"></param> /// <param name="underlyingInstrumentType"></param> /// <param name="calendarStr"></param> /// <param name="dayCountStr"></param> /// <param name="commodityFuturesPreciseTimeMode"></param> /// <param name="hasNightMarket"></param> /// <returns>if succeed then return implied vol, if falied then return error message</returns> public static double xl_ImpliedVolFromPremium(double premium, bool isCall, double strike, double spot, double rate, string expiryDateStr, string valuationDateStr, string underlyingInstrumentType, string calendarStr, string dayCountStr, bool commodityFuturesPreciseTimeMode = false, bool hasNightMarket = false) { var bsEngine = new AnalyticalVanillaEuropeanOptionEngine(); var expiryDate = expiryDateStr.ToDate(); var valuationDate = valuationDateStr.ToDate(); var instrumentType = underlyingInstrumentType.ToInstrumentType(); var calendar = calendarStr.ToCalendarImpl(); var dayCount = dayCountStr.ToDayCountImpl(); var trade = new VanillaOption( valuationDate, expiryDate, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, strike, instrumentType, calendar, dayCount, CurrencyCode.CNY, CurrencyCode.CNY, new[] { expiryDate }, new[] { expiryDate }, notional: 1, hasNightMarket: hasNightMarket, commodityFuturesPreciseTimeMode: commodityFuturesPreciseTimeMode ); var curve = new YieldCurve( "riskFreeRate", valuationDate, new[] { Tuple.Create((ITerm) new Term("1D"), rate), Tuple.Create((ITerm) new Term("1Y"), rate) }, BusinessDayConvention.ModifiedFollowing, dayCount, calendar, CurrencyCode.CNY, Compound.Continuous, Interpolation.CubicHermiteMonotic, YieldCurveTrait.SpotCurve ); var volSurf = new VolSurfMktData("VolSurf", 0.1).ToImpliedVolSurface(valuationDate); var market = new MarketCondition( x => x.ValuationDate.Value = valuationDate, x => x.DiscountCurve.Value = curve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", curve } }, //not used by futures option x => x.FixingCurve.Value = curve, x => x.RiskfreeCurve.Value = curve, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", spot } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", volSurf } }); //not used by this calibration return(bsEngine.ImpliedVolFromPremium(targetPremium: premium, option: trade, market: market)); }
public static object BondEngineCalc(string bondId, string calcDate, PriceQuoteType priceQuote, double quote, PricingRequest request, FixedRateBondInfo fixedBond = null) { var bond = fixedBond ?? XlManager.GetTrade(bondId); if (bond == null) { return(string.Format("Cannot find bond {0}.", bondId)); } var vf = new BondVf((BondInfoBase)bond); var bondInstrument = vf.GenerateInstrument(); var valueDate = calcDate.ToDate(); var fixingCurve = new YieldCurve( "中债国债收收益率曲线", valueDate, new[] { new Tuple <Date, double>(valueDate, 0.0), new Tuple <Date, double>(new Term("10Y").Next(valueDate), 0.0) }, BusinessDayConvention.ModifiedFollowing, new Act365(), CalendarImpl.Get("Chn_ib"), CurrencyCode.CNY, Compound.Continuous, Interpolation.ForwardFlat, YieldCurveTrait.ForwardCurve ); var market = new MarketCondition( x => x.ValuationDate.Value = valueDate, x => x.FixingCurve.Value = fixingCurve, x => x.MktQuote.Value = new Dictionary <string, Tuple <PriceQuoteType, double> > { { bondId, Tuple.Create(priceQuote, quote) } }, x => x.HistoricalIndexRates.Value = HistoricalIndexRates ); if (bond is FloatingRateBondInfo) { var fixingTuple = bondInstrument.Coupon.GetPrimeCoupon(HistoricalIndexRates, fixingCurve, valueDate); var keyTenors = new string[fixingCurve.GetKeyTenors().Length]; fixingCurve.GetKeyTenors().CopyTo(keyTenors, 0); for (var i = 0; i < keyTenors.Length; ++i) { market = (MarketCondition)market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, market.FixingCurve.Value.BumpKeyRate(i, fixingTuple.Item2))); } if (request.Equals(PricingRequest.None)) { return(fixingTuple); } } var engine = vf.GenerateEngine(); var result = engine.Calculate(bondInstrument, market, request); if (!result.Succeeded) { return(string.Format("Failed to Calculate bond {0}:{1}", bondId, result.ErrorMessage)); } return(result); }
private GuidObject CurveBuiltFromDependents(DependentObject fatherNode, DependentObject[] childrenNodes) { IMarketCondition baseMarket; if (childrenNodes.Any(x => x is InstrumentCurveObject)) { var baseCurve = (CurveData)childrenNodes.First().Value; baseMarket = new MarketCondition(x => x.ValuationDate.Value = Market.ReferenceDate, x => x.HistoricalIndexRates.Value = Market.HistoricalIndexRates, x => x.DiscountCurve.Value = baseCurve.YieldCurve, x => x.FixingCurve.Value = baseCurve.YieldCurve, x => x.FgnDiscountCurve.Value = baseCurve.YieldCurve); } else { baseMarket = new MarketCondition(x => x.ValuationDate.Value = Market.ReferenceDate, x => x.HistoricalIndexRates.Value = Market.HistoricalIndexRates); } var rateDefinitions = childrenNodes.Where(x => x.Value is RateMktData).Select(x => (RateMktData)x.Value).ToArray(); var fxSpotDefinition = rateDefinitions.Where(x => x.InstrumentType.ToInstrumentType() == InstrumentType.FxSpot).ToArray(); if (fxSpotDefinition.Count() > 1) { throw new PricingBaseException("A yield curve cannot have more than 2 fx rates against its base curve's currency"); } if (fxSpotDefinition.Any()) { baseMarket = baseMarket.UpdateCondition( new UpdateMktConditionPack <FxSpot[]>(x => x.FxSpots, new[] { CreateFxSpot(fxSpotDefinition[0]) })); } var curveConvention = childrenNodes.Last().Value as CurveConvention; if (curveConvention == null) { Logger.ErrorFormat("Curve conventions are missing!"); return(null); } var isRegridded = rateDefinitions.All(x => x.IndexType != null && x.IndexType.ToIndexType() == IndexType.Regridded); if (isRegridded) { var yieldCurve = baseMarket.DiscountCurve.Value; var tempRateDefinitions = new List <RateMktData>(); foreach (var tenor in Definition.RegriddedTenors) { var date = new Term(tenor).Next(yieldCurve.ReferenceDate); if (date > yieldCurve.KeyPoints.Last().Item1) { date = yieldCurve.KeyPoints.Last().Item1; } tempRateDefinitions.Add(new RateMktData(date.ToString(), GetParRate(date, yieldCurve), "SwapParRate", "InterestRateSwap", Definition.Name)); } rateDefinitions = tempRateDefinitions.ToArray(); } YieldCurve instrumentCurve; //This branch is for bond pnl calculation if (rateDefinitions.All( x => x.InstrumentType.ToInstrumentType() == InstrumentType.Dummy || x.InstrumentType.ToInstrumentType() == InstrumentType.None)) { if (rateDefinitions.All(x => x.IsTerm())) { instrumentCurve = new YieldCurve( Definition.Name, Market.ReferenceDate, rateDefinitions.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(), curveConvention.BusinessDayConvention.ToBda(), curveConvention.DayCount.ToDayCountImpl(), curveConvention.Calendar.ToCalendarImpl(), curveConvention.Currency.ToCurrencyCode(), curveConvention.Compound.ToCompound(), curveConvention.Interpolation.ToInterpolation(), Definition.Trait.ToYieldCurveTrait(), baseMarket ); } else { instrumentCurve = new YieldCurve( Definition.Name, Market.ReferenceDate, rateDefinitions.Select(x => Tuple.Create(new Date(DateTime.Parse(x.Tenor)), x.Rate)).ToArray(), curveConvention.BusinessDayConvention.ToBda(), curveConvention.DayCount.ToDayCountImpl(), curveConvention.Calendar.ToCalendarImpl(), curveConvention.Currency.ToCurrencyCode(), curveConvention.Compound.ToCompound(), curveConvention.Interpolation.ToInterpolation(), Definition.Trait.ToYieldCurveTrait(), baseMarket ); } } else { var mktInstruments = new List <MarketInstrument>(); foreach (var rateDefinition in rateDefinitions) { MktInstrumentCalibMethod calibrationMethod; var instType = rateDefinition.InstrumentType.ToInstrumentType(); switch (instType) { case InstrumentType.InterestRateSwap: var swap = CreateIrsInstrument(rateDefinition, out calibrationMethod); mktInstruments.Add(new MarketInstrument(swap, rateDefinition.Rate, calibrationMethod)); break; case InstrumentType.Deposit: case InstrumentType.Repo: case InstrumentType.Ibor: var deposit = CreateDepositInstrument(rateDefinition, out calibrationMethod); mktInstruments.Add(new MarketInstrument(deposit, rateDefinition.Rate, calibrationMethod)); break; case InstrumentType.Dummy: case InstrumentType.None: var dummy = CreateDummyInstrument(rateDefinition); mktInstruments.Add(new MarketInstrument(dummy, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); break; case InstrumentType.CreditDefaultSwap: var cds = CreateCreditDefaultSwap(rateDefinition); mktInstruments.Add(new MarketInstrument(cds, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); break; case InstrumentType.CommodityForward: mktInstruments.Add(new MarketInstrument(CreateCommodityForward(rateDefinition), rateDefinition.Rate, MktInstrumentCalibMethod.Default)); break; case InstrumentType.CommoditySpot: //baseMarket = baseMarket.UpdateCondition(new UpdateMktConditionPack<double>(x => x.SpotPrices, rateDefinition.Rate)); baseMarket = baseMarket.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, double> >(x => x.SpotPrices, new Dictionary <string, double> { { "", rateDefinition.Rate } })); break; case InstrumentType.FxSpot: break; default: throw new PricingLibraryException("Unrecognized product type in calibrating curve."); } #region legacy code // if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.InterestRateSwap) //{ // var swap = CreateIrsInstrument(rateDefinition, out calibrationMethod); // mktInstruments.Add(new MarketInstrument(swap, rateDefinition.Rate, calibrationMethod)); //} //else if ( instType == InstrumentType.Deposit // || rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Repo // || rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Ibor) //{ // var deposit = CreateDepositInstrument(rateDefinition, out calibrationMethod); // mktInstruments.Add(new MarketInstrument(deposit, rateDefinition.Rate, calibrationMethod)); //} //else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Dummy || // rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.None) //{ // var dummy = CreateDummyInstrument(rateDefinition); // mktInstruments.Add(new MarketInstrument(dummy, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); //} //else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CreditDefaultSwap) //{ // var cds = CreateCreditDefaultSwap(rateDefinition); // mktInstruments.Add(new MarketInstrument(cds, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); //} //else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CommodityForward) //{ // mktInstruments.Add(new MarketInstrument(CreateCommodityForward(rateDefinition), rateDefinition.Rate, MktInstrumentCalibMethod.Default)); //} //else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CommoditySpot) //{ // //baseMarket = baseMarket.UpdateCondition(new UpdateMktConditionPack<double>(x => x.SpotPrices, rateDefinition.Rate)); // baseMarket = baseMarket.UpdateCondition(new UpdateMktConditionPack<Dictionary<string, double>>(x => x.SpotPrices, new Dictionary<string, double> { {"", rateDefinition.Rate } })); // } //else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.FxSpot) //{ //} //else //{ // throw new PricingLibraryException("Unrecognized product type in calibrating curve."); //} #endregion legacy code } var isSpcCurve = rateDefinitions.All(x => x.IndexType != null && x.IndexType.ToIndexType() == IndexType.Spc); var isConvenicenYield = rateDefinitions.All(x => x.IndexType != null && x.IndexType.ToIndexType() == IndexType.ConvenienceYield); Expression <Func <IMarketCondition, object> >[] expression = null; if (isSpcCurve) { expression = new Expression <Func <IMarketCondition, object> >[] { x => x.SurvivalProbabilityCurve } } ; if (isConvenicenYield) { expression = new Expression <Func <IMarketCondition, object> >[] { x => x.DividendCurves } } ; instrumentCurve = new YieldCurve( Definition.Name, Market.ReferenceDate, mktInstruments.ToArray(), curveConvention.BusinessDayConvention.ToBda(), curveConvention.DayCount.ToDayCountImpl(), curveConvention.Calendar.ToCalendarImpl(), curveConvention.Currency.ToCurrencyCode(), curveConvention.Compound.ToCompound(), curveConvention.Interpolation.ToInterpolation(), Definition.Trait.ToYieldCurveTrait(), baseMarket, expression, null ); } return(new CurveData(instrumentCurve)); }
public void BondForwardTest() { var bond = new Bond( "010000", new Date(2013, 2, 25), new Date(2015, 2, 25), 100, CurrencyCode.CNY, new FixedCoupon(0.0375), CalendarImpl.Get("chn_ib"), Frequency.SemiAnnual, Stub.LongEnd, new ActActIsma(), new Act365(), BusinessDayConvention.None, BusinessDayConvention.None, null, TradingMarket.ChinaInterBank ); var bondForward = new Forward <Bond>( new Date(2013, 5, 28), new Date(2013, 8, 28), 100.0, 98.57947065, bond, CurrencyCode.CNY ); var referenceDate = new Date(2013, 8, 23); var yieldCurve = new YieldCurve( "中债国债收收益率曲线", referenceDate, new[] { Tuple.Create((ITerm) new Term("1D"), 0.035), Tuple.Create((ITerm) new Term("1Y"), 0.035) }, BusinessDayConvention.ModifiedFollowing, new Act365(), CalendarImpl.Get("chn_ib"), CurrencyCode.CNY, Compound.Simple, Interpolation.CubicHermiteMonotic, YieldCurveTrait.SpotCurve ); var market = new MarketCondition ( x => x.ValuationDate.Value = referenceDate, x => x.MktQuote.Value = new Dictionary <string, Tuple <PriceQuoteType, double> > { { "010000", Tuple.Create(PriceQuoteType.Dirty, 99.71798177) } }, x => x.DiscountCurve.Value = yieldCurve, x => x.FixingCurve.Value = yieldCurve, x => x.RiskfreeCurve.Value = yieldCurve, x => x.UnderlyingDiscountCurve.Value = yieldCurve, x => x.HistoricalIndexRates.Value = new Dictionary <IndexType, SortedDictionary <Date, double> >() ); var bondengine = new BondEngine(); var zeroSpread = bondengine.Calculate(bond, market, PricingRequest.ZeroSpread).ZeroSpread; var engine = new ForwardEngine <Bond>(); var result = engine.Calculate(bondForward, market, PricingRequest.Pv); Assert.AreEqual(-0.68888788, result.Pv, 1e-8); }
public void UpdateCurve(YieldCurve curve) { this.YieldAsOxyPlotCurve = Utils.Plot(curve, 0.0, 30.0, 0.01).ToList(); OnPropertyChanged("YieldAsOxyPlotCurve"); }
public ProcessVisualizer(YieldCurve yc, IProcess process) { this.forwardRate = ((DiscountCurve)yc).ForwardRate; this.process = process; InitializeComponent(); }
private Dictionary <string, Dictionary <string, RateRecord> > CalcMktFuturePrice(BondFutures bondFuture, IMarketCondition market) { var psDict = new Dictionary <string, Dictionary <string, RateRecord> >(); var fundingCurve = market.RiskfreeCurve.HasValue ? market.RiskfreeCurve.Value : YieldCurve.GetConstRateCurve(market.DiscountCurve.Value, 0.0); var reinvestmentCurve = market.DiscountCurve.HasValue ? market.DiscountCurve.Value : YieldCurve.GetConstRateCurve(market.RiskfreeCurve.Value, 0.0); var bonds = bondFuture.Deliverables; var length = bonds.Length; var aiAtStart = bonds.Select(x => x.GetAccruedInterest(market.ValuationDate, market, false)).ToArray(); var aiAtEnd = bonds.Select(x => x.GetAccruedInterest(bondFuture.UnderlyingMaturityDate, market, false)).ToArray(); var cf = bonds.Select(x => bondFuture.GetConversionFactor(x, market)).ToArray(); var coupons = new double[length]; var timeWeightedCoupon = new double[length]; var couponsAccruedByReinvestment = new double[length]; for (var i = 0; i < length; ++i) { var bond = bonds[i]; var cashflows = bond.GetCashflows(market, false).Where(x => x.PaymentDate > market.ValuationDate && x.PaymentDate <= bondFuture.UnderlyingMaturityDate).ToArray(); if (cashflows.Any()) { coupons[i] = cashflows.Sum(x => x.PaymentAmount); timeWeightedCoupon[i] = cashflows.Sum(x => x.PaymentAmount * bondFuture.DayCount.CalcDayCountFraction(x.PaymentDate, bondFuture.UnderlyingMaturityDate)); couponsAccruedByReinvestment[i] = cashflows.Sum(x => x.PaymentAmount * (reinvestmentCurve.GetCompoundedRate2(x.PaymentDate, bondFuture.UnderlyingMaturityDate) - 1.0)); } else { coupons[i] = 0.0; timeWeightedCoupon[i] = 0.0; couponsAccruedByReinvestment[i] = 0.0; } } var interestIncome = bonds.Select((x, i) => aiAtEnd[i] - aiAtStart[i] + coupons[i] + couponsAccruedByReinvestment[i]).ToArray(); //var interestIncome = bonds.Select((x, i) => aiAtEnd[i] - aiAtStart[i] + coupons[i]).ToArray(); var dirtyPrice = new double[length]; var cleanPrice = new double[length]; var ytm = new double[length]; var modifiedDuration = new double[length]; var bondEngine = new BondEngine(); for (var i = 0; i < length; ++i) { var bResult = bondEngine.Calculate(bonds[i], market, PricingRequest.Ytm | PricingRequest.ModifiedDuration); dirtyPrice[i] = bResult.DirtyPrice; cleanPrice[i] = bResult.CleanPrice; ytm[i] = bResult.Ytm; } var interestCostRate = fundingCurve.GetCompoundedRate2(market.ValuationDate, bondFuture.UnderlyingMaturityDate) - 1.0; var interestCost = dirtyPrice.Select(x => x * interestCostRate).ToArray(); var futurePrice = new double[length]; var irr = new double[length]; var basis = new double[length]; var pnl = new double[length]; var netBasis = new double[length]; var invoicePrice = new double[length]; var margin = new double[length]; var spread = new double[length]; var fundingRate = fundingCurve.GetSpotRate(0.0); var compoundedRate = fundingCurve.GetCompoundedRate2(market.ValuationDate, bondFuture.UnderlyingMaturityDate); var bondPricesCompounedByFunding = bonds.Select((x, i) => dirtyPrice[i] * compoundedRate).ToArray(); for (var i = 0; i < bonds.Length; ++i) { futurePrice[i] = (bondPricesCompounedByFunding[i] - aiAtEnd[i] - coupons[i]) / cf[i]; var newMarket = market.UpdateCondition( new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, market.MktQuote.Value.UpdateKey(bondFuture.Id, Tuple.Create(PriceQuoteType.Dirty, futurePrice[i])))); var yieldPricer = new BondFuturesYieldPricer(bondFuture, newMarket); var tmpResult = yieldPricer.CalcEquation("FromFuturesPriceAndBondPrice"); invoicePrice[i] = tmpResult["InvoicePrice"][bonds[i].Id].Rate; margin[i] = tmpResult["Margin"][bonds[i].Id].Rate; basis[i] = tmpResult["Basis"][bonds[i].Id].Rate; pnl[i] = tmpResult["PnL"][bonds[i].Id].Rate; netBasis[i] = tmpResult["NetBasis"][bonds[i].Id].Rate; irr[i] = tmpResult["Irr"][bonds[i].Id].Rate; spread[i] = irr[i] - fundingRate; } psDict["FuturesPrice"] = futurePrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["BondDirtyPrice"] = dirtyPrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["BondCleanPrice"] = cleanPrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["BondYieldToMaturity"] = ytm.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["ConversionFactor"] = cf.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["AiStart"] = aiAtStart.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["AiEnd"] = aiAtEnd.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["Coupon"] = coupons.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["InterestIncome"] = interestIncome.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["InterestCost"] = interestCost.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["PnL"] = pnl.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["InvoicePrice"] = invoicePrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["Margin"] = margin.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["Spread"] = spread.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["Irr"] = irr.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["Basis"] = basis.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["NetBasis"] = netBasis.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["ModifiedDuration"] = modifiedDuration.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); psDict["TimeWeightedCoupon"] = timeWeightedCoupon.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord { Rate = x })).ToDictionary(x => x.Item1, x => x.Item2); return(psDict); }
/// <summary> /// for Option version only /// </summary> /// <param name="prebuiltMarket"></param> /// <param name="curveDate"></param> /// <param name="curveDefinition"></param> /// <returns></returns> public static YieldCurve BuildYieldCurve(PrebuiltQdpMarket prebuiltMarket, Date curveDate, InstrumentCurveDefinition curveDefinition) { IMarketCondition baseMarket; baseMarket = new MarketCondition(x => x.ValuationDate.Value = prebuiltMarket.ReferenceDate, x => x.HistoricalIndexRates.Value = prebuiltMarket.HistoricalIndexRates); YieldCurve instrumentCurve = null; if (curveDefinition.RateDefinitions.All( x => x.InstrumentType.ToInstrumentType() == InstrumentType.Dummy || x.InstrumentType.ToInstrumentType() == InstrumentType.None)) { if (curveDefinition.RateDefinitions.All(x => x.IsTerm())) { instrumentCurve = new YieldCurve( curveDefinition.Name, curveDate, curveDefinition.RateDefinitions.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(), curveDefinition.CurveConvention.BusinessDayConvention.ToBda(), curveDefinition.CurveConvention.DayCount.ToDayCountImpl(), curveDefinition.CurveConvention.Calendar.ToCalendarImpl(), curveDefinition.CurveConvention.Currency.ToCurrencyCode(), curveDefinition.CurveConvention.Compound.ToCompound(), curveDefinition.CurveConvention.Interpolation.ToInterpolation(), curveDefinition.Trait.ToYieldCurveTrait(), null, null, null, null, curveDefinition ); } else { instrumentCurve = new YieldCurve( curveDefinition.Name, curveDate, curveDefinition.RateDefinitions.Select(x => Tuple.Create(new Date(DateTime.Parse(x.Tenor)), x.Rate)).ToArray(), curveDefinition.CurveConvention.BusinessDayConvention.ToBda(), curveDefinition.CurveConvention.DayCount.ToDayCountImpl(), curveDefinition.CurveConvention.Calendar.ToCalendarImpl(), curveDefinition.CurveConvention.Currency.ToCurrencyCode(), curveDefinition.CurveConvention.Compound.ToCompound(), curveDefinition.CurveConvention.Interpolation.ToInterpolation(), curveDefinition.Trait.ToYieldCurveTrait(), null, null, null, null, curveDefinition ); } } else { var mktInstruments = new List <MarketInstrument>(); foreach (var rateDefinition in curveDefinition.RateDefinitions) { MktInstrumentCalibMethod calibrationMethod; if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.InterestRateSwap) { var swap = CurveBuildHelper.CreateIrsInstrument(curveDate, rateDefinition, out calibrationMethod); mktInstruments.Add(new MarketInstrument(swap, rateDefinition.Rate, calibrationMethod)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Deposit || rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Repo || rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Ibor) { var deposit = CurveBuildHelper.CreateDepositInstrument(curveDate, rateDefinition, out calibrationMethod); mktInstruments.Add(new MarketInstrument(deposit, rateDefinition.Rate, calibrationMethod)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.Dummy || rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.None) { var dummy = CurveBuildHelper.CreateDummyInstrument(curveDate, rateDefinition); mktInstruments.Add(new MarketInstrument(dummy, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CreditDefaultSwap) { var cds = CurveBuildHelper.CreateCreditDefaultSwap(curveDate, rateDefinition); mktInstruments.Add(new MarketInstrument(cds, rateDefinition.Rate, MktInstrumentCalibMethod.Default)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CommodityForward) { mktInstruments.Add(new MarketInstrument(CurveBuildHelper.CreateCommodityForward(curveDate, rateDefinition), rateDefinition.Rate, MktInstrumentCalibMethod.Default)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.CommoditySpot) { //baseMarket = baseMarket.UpdateCondition(new UpdateMktConditionPack<double>(x => x.SpotPrice, rateDefinition.Rate)); } else if (rateDefinition.InstrumentType.ToInstrumentType() == InstrumentType.FxSpot) { } else { throw new PricingLibraryException("Unrecognized product type in calibrating curve."); } } var isSpcCurve = curveDefinition.RateDefinitions.All(x => x.IndexType != null && x.IndexType.ToIndexType() == IndexType.Spc); var isConvenicenYield = curveDefinition.RateDefinitions.All(x => x.IndexType != null && x.IndexType.ToIndexType() == IndexType.ConvenienceYield); //Expression<Func<IMarketCondition, object>>[] expression = null; //if (isSpcCurve) expression = new Expression<Func<IMarketCondition, object>>[] { x => x.SurvivalProbabilityCurve }; //if (isConvenicenYield) expression = new Expression<Func<IMarketCondition, object>>[] { x => x.DividendCurve }; instrumentCurve = new YieldCurve( curveDefinition.Name, curveDate, mktInstruments.ToArray(), curveDefinition.CurveConvention.BusinessDayConvention.ToBda(), curveDefinition.CurveConvention.DayCount.ToDayCountImpl(), curveDefinition.CurveConvention.Calendar.ToCalendarImpl(), curveDefinition.CurveConvention.Currency.ToCurrencyCode(), curveDefinition.CurveConvention.Compound.ToCompound(), curveDefinition.CurveConvention.Interpolation.ToInterpolation(), curveDefinition.Trait.ToYieldCurveTrait(), baseMarket, null, null, null, null, curveDefinition); } return(instrumentCurve); }
public Index(double level, YieldCurve divCurve) { Level = level; DividendCurve = divCurve; }
public void BasicVanillaOptionTest() { var startDate = new Date(2014, 03, 18); var maturityDate = new Date(2015, 03, 18); var valueDate = new Date(2014, 03, 18); #region Prepare Market // build discount curve and dividend curve var fr007CurveName = "Fr007"; var fr007RateDefinition = new[] { new RateMktData("1D", 0.06, "Spot", "None", fr007CurveName), new RateMktData("5Y", 0.06, "Spot", "None", fr007CurveName), }; var dividendCurveName = "Dividend"; var dividendRateDefinition = new[] { new RateMktData("1D", 0.03, "Spot", "None", dividendCurveName), new RateMktData("5Y", 0.03, "Spot", "None", dividendCurveName), }; var discountCurve = new YieldCurve( name: fr007CurveName, referenceDate: valueDate, keyPoints: fr007RateDefinition.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(), bda: BusinessDayConvention.ModifiedFollowing, dayCount: new Act365(), calendar: CalendarImpl.Get("Chn"), currency: CurrencyCode.CNY, compound: Compound.Continuous, interpolation: Interpolation.CubicHermiteMonotic, trait: YieldCurveTrait.SpotCurve); var dividendCurve = new YieldCurve( name: dividendCurveName, referenceDate: valueDate, keyPoints: dividendRateDefinition.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(), bda: BusinessDayConvention.ModifiedFollowing, dayCount: new Act365(), calendar: CalendarImpl.Get("Chn"), currency: CurrencyCode.CNY, compound: Compound.Continuous, interpolation: Interpolation.CubicHermiteMonotic, trait: YieldCurveTrait.SpotCurve); // build vol surface var volSurfData = new VolSurfMktData("VolSurf", 0.25); var volSurface = volSurfData.ToImpliedVolSurface( valuationDate: valueDate, dc: "Act365"); // construct market var market = new MarketCondition( x => x.ValuationDate.Value = valueDate, x => x.DiscountCurve.Value = discountCurve, x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> { { "", dividendCurve } }, x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> { { "", volSurface } }, x => x.SpotPrices.Value = new Dictionary <string, double> { { "", 1.0 } } ); #endregion // construct a put option var put = new VanillaOption(startDate, maturityDate, OptionExercise.European, OptionType.Put, 1.0, InstrumentType.Stock, CalendarImpl.Get("chn"), new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, new[] { maturityDate }); var engine = new AnalyticalVanillaEuropeanOptionEngine(); var result = engine.Calculate(put, market, PricingRequest.All); }
public void TestSerialisingDerivedTypes() { // tests control of the serialisation type // - type b (derived from a) is saved as b, loaded as b; // - type b (derived from a) is saved as a, loaded as a (but is type b). // (in this example a = PricingStructure, b = YieldCurve) using (Reference <ILogger> loggerRef = Reference <ILogger> .Create(new TraceLogger(true))) { using (CoreServer server = new CoreServer(loggerRef, "UTT", NodeType.Router)) { // start server server.Start(); using (ICoreClient client = new CoreClientFactory(loggerRef).SetEnv("UTT").Create()) { { YieldCurve dataA = new YieldCurve { currency = new Currency { Value = "USD" }, algorithm = "FastCubicSpline" }; // - save as derived type client.SaveObject(dataA, "TestA", null, TimeSpan.MaxValue); ICoreItem test1 = client.LoadItem <YieldCurve>("TestA"); Assert.IsNotNull(test1); Assert.IsNotNull(test1.Text); Assert.AreEqual( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<yieldCurve xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.fpml.org/FpML-5/reporting\">\r\n <currency>USD</currency>\r\n <algorithm>FastCubicSpline</algorithm>\r\n</yieldCurve>", test1.Text); Assert.AreEqual(typeof(YieldCurve).FullName, test1.DataTypeName); Assert.AreEqual(typeof(YieldCurve), test1.DataType); Assert.IsNotNull(test1.Data); Assert.AreEqual(typeof(YieldCurve), test1.Data.GetType()); // - save as base type client.SaveObject <PricingStructure>(dataA, "TestA", null, TimeSpan.MaxValue); ICoreItem test2 = client.LoadItem <PricingStructure>("TestA"); Assert.IsNotNull(test2); Assert.IsNotNull(test2.Text); Assert.AreEqual( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<PricingStructure xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:q1=\"http://www.fpml.org/FpML-5/reporting\" xsi:type=\"q1:YieldCurve\">\r\n <q1:currency>USD</q1:currency>\r\n <q1:algorithm>FastCubicSpline</q1:algorithm>\r\n</PricingStructure>", test2.Text); Assert.AreEqual(typeof(PricingStructure).FullName, test2.DataTypeName); Assert.AreEqual(typeof(PricingStructure), test2.DataType); Assert.IsNotNull(test2.Data); Assert.AreEqual(typeof(YieldCurve), test2.Data.GetType()); } { FxCurve dataB = new FxCurve() { quotedCurrencyPair = new QuotedCurrencyPair() { currency1 = new Currency() { Value = "USD" }, currency2 = new Currency() { Value = "JPY" }, quoteBasis = QuoteBasisEnum.Currency2PerCurrency1 } }; // - save as derived type client.SaveObject(dataB, "TestB", null, TimeSpan.MaxValue); ICoreItem test1 = client.LoadItem <FxCurve>("TestB"); Assert.IsNotNull(test1); Assert.IsNotNull(test1.Text); Assert.AreEqual( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<fxCurve xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.fpml.org/FpML-5/reporting\">\r\n <quotedCurrencyPair>\r\n <currency1>USD</currency1>\r\n <currency2>JPY</currency2>\r\n </quotedCurrencyPair>\r\n</fxCurve>", test1.Text); Assert.AreEqual(typeof(FxCurve).FullName, test1.DataTypeName); Assert.AreEqual(typeof(FxCurve), test1.DataType); Assert.IsNotNull(test1.Data); Assert.AreEqual(typeof(FxCurve), test1.Data.GetType()); // - save as base type client.SaveObject <PricingStructure>(dataB, "TestB", null, TimeSpan.MaxValue); ICoreItem test2 = client.LoadItem <PricingStructure>("TestB"); Assert.IsNotNull(test2); Assert.IsNotNull(test2.Text); Assert.AreEqual( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<PricingStructure xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:q1=\"http://www.fpml.org/FpML-5/reporting\" xsi:type=\"q1:FxCurve\">\r\n <q1:quotedCurrencyPair>\r\n <q1:currency1>USD</q1:currency1>\r\n <q1:currency2>JPY</q1:currency2>\r\n </q1:quotedCurrencyPair>\r\n</PricingStructure>", test2.Text); Assert.AreEqual(typeof(PricingStructure).FullName, test2.DataTypeName); Assert.AreEqual(typeof(PricingStructure), test2.DataType); Assert.IsNotNull(test2.Data); Assert.AreEqual(typeof(FxCurve), test2.Data.GetType()); } { // load a collection of the base type and verify specific types List <ICoreItem> items = client.LoadItems <PricingStructure>(Expr.ALL); Assert.AreEqual(2, items.Count); Dictionary <string, PricingStructure> index = new Dictionary <string, PricingStructure>(); foreach (ICoreItem item in items) { index[item.Name] = (PricingStructure)item.Data; } Assert.AreEqual(typeof(YieldCurve), index["TestA"].GetType()); Assert.AreEqual(typeof(FxCurve), index["TestB"].GetType()); } } // shutdown server.Stop(); } } }
public CurveData(YieldCurve yieldCurve) { YieldCurve = yieldCurve; }