// return forward start swap as same building block used in building curve recalculated starting on custom StartDate, Tenor is the tenor of swap public double SwapFwd(Date StartDate, string Tenor) { // 1. Build the swap. Rate is not important I use 0.0 SwapStyle myS = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(StartDate, 0.0, Tenor, SwapType.buildingBlockType); return(ParRate(myS)); }
public static double CapBlack(string Tenor, double strike, double N, IRateCurve curve, BilinearInterpolator VolCapletMatrix) { Date refDate = curve.RefDate(); SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(refDate, 0, Tenor, curve.GetSwapStyle().buildingBlockType); double[] yf = y.scheduleLeg2.GetYFVect(Dc._Act_360); int toRemove = yf.Length - 1; yf = yf.Where((val, inx) => inx != toRemove).ToArray(); List <Date> ToDate = y.scheduleLeg2.toDates.ToList(); ToDate.RemoveAt(ToDate.Count - 1); // remove last element double[] 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 double[] df = new double[Ncaplet]; // fwd rate double[] 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]); } double[] sigma = (from t in T select VolCapletMatrix.Solve(t, strike)).ToArray(); return(CapBlack(T, yf, N, strike, sigma, df, fwd)); }
// calculate forward start swap public double SwapFwd(Date StartDate, string Tenor) { // 1. Build the swap. Rate is not important I use 0.0 SwapStyle myS = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(StartDate, 0.0, Tenor, SwapType.buildingBlockType); // 2. Calculate Par Rate // fixed leg data double[] yfFixLeg = myS.scheduleLeg1.GetYFVect(myS.swapLeg1.DayCount); // fixed is leg 1 // dfs array of fixed lag double[] dfDates = Date.GetSerialValue(myS.scheduleLeg1.payDates); // serial date of fixed lag (each dates we should find df) // Vector<double> k = PostProcessInterpo.Curve(new Vector<double>(dfDates, 0)); double[] dfFixLeg = PostProcessInterpo.Curve(dfDates); // get interpolated value (i.e. log df or log r or... // transform interpolated value back to discount factor for (int i = 0; i < yfFixLeg.Length; i ++) { dfFixLeg[i] = interpAdapter.FromInterpToDf(dfFixLeg[i], dfDates[i]); } // Interpolation Methods for Curve Construction PATRICK S. HAGAN & GRAEME WEST Applied Mathematical Finance,Vol. 13, No. 2, 89–129, June 2006 // Formula 2) page 4 double iniDf = interpAdapter.FromInterpToDf(PostProcessInterpo.Solve(StartDate.SerialValue), StartDate.SerialValue); return(Formula.ParRate(yfFixLeg, dfFixLeg, iniDf)); // Calculate par rate }
protected void PrePorcessData(RateSet rateSetMC, ISingleRateCurve DiscountingCurve) { this.refDate = rateSetMC.refDate; this.DCurve = DiscountingCurve; // my curve used in discounting FWDInterpolator = new Interpolation(); // Interpolator used in fwd this.mktRateSet = rateSetMC; // pass market rate set // Create Building block IEnumerable <BuildingBlock> BB = mktRateSet.GetArrayOfBB(); // Sort ascending end date BBArray = from c in BB orderby c.endDate.SerialValue ascending select c; // Only Given Swap from BBArray OnlyGivenSwap = (from c in BBArray where c.GetType().BaseType == typeof(SwapStyle) select(SwapStyle) c).ToArray(); // validating underlying tenor: swap should be all vs the same tenor string UnderlyingTenor = ((SwapStyle)OnlyGivenSwap.First()).swapLeg2.UnderlyingRateTenor; // Getting the fixing fixing = (from c in BBArray where c.GetType().BaseType == typeof(OnePaymentStyle) where c.endDate == refDate.add_period(UnderlyingTenor) select c.rateValue).Single(); // From date of each fwd rate from longer swap(LS) // FromDatesSerial = Date.GetSerialValue(OnlyGivenSwap.Last().scheduleLeg2.fromDates); List <double> SerialDate = (from c in OnlyGivenSwap select c.scheduleLeg2.fromDates.Last().SerialValue).ToList <double>(); // adding reference date at beginning (this is important since I use the fixing) SerialDate.Insert(0, refDate.SerialValue); FromDatesSerial = SerialDate.ToArray(); // some data validation: swap should be all of same building block // the type of building block BuildingBlockType BBT = OnlyGivenSwap[0].buildingBlockType; // Are all them the same? bool IsSameSwapType = OnlyGivenSwap.All(s => s.buildingBlockType == BBT); if (IsSameSwapType) // if true { // it is swap type used as inputs (i.e. EurSwapVs6m, EurSwapVs3m, ...) SwapType = (SwapStyle) new BuildingBlockFactory().CreateEmptyBuildingBlock(BBT); } else { throw new ArgumentException("error in building blocktype"); // if not throw an exception } }
// NPV of swap public static double NPV(SwapStyle BB, IRateCurve c, bool PayOrRec) { #region FixLeg // fixed leg data double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1 // dfs array of fixed lag Date[] dfDates = BB.scheduleLeg1.payDates; // serial date of fixed lag (each dates we should find df) // # of fixed cash flows int n_fix = dfDates.Length; double NPV_fix = 0.0; // calculate df for (int i = 0; i < n_fix; i++) { NPV_fix += c.Df(dfDates[i]) * yfFixLeg[i] * BB.rateValue; // df*yf } #endregion #region FloatLeg // floating leg data double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount); // float is leg 2 // dfs array of fixed lag Date[] dfDatesFloat = BB.scheduleLeg2.payDates; // serial date of float leg (each dates we should find df) Date[] FromDateFloat = BB.scheduleLeg2.fromDates; // # of floating cash flows int n_float = dfDatesFloat.Length; double[] fwd = new double[n_float]; // fwd rates container // getting fwd rates for (int i = 0; i < n_float; i++) { fwd[i] = c.Fwd(FromDateFloat[i]); } double NPV_float = 0.0; // calculate df for (int i = 0; i < n_float; i++) { NPV_float += c.Df(dfDatesFloat[i]) * yfFloatLeg[i] * fwd[i]; // df*yf } #endregion if (!PayOrRec) { return(-NPV_fix + NPV_float); } // Receiver Swap return(NPV_fix - NPV_float); // NPV Payer Swap }
public VanillaSwap(IMultiRateCurve MultiCurve, double Rate, string SwapTenor, bool PayOrRec, double Nominal) { // Standard swap Type SwapType = MultiCurve.GetSwapStyle().GetType(); Date myRefDate = MultiCurve.RefDate(); // using reflection this.mySwap = (SwapStyle)Activator.CreateInstance(SwapType, myRefDate, Rate, SwapTenor); this.payOrRec = PayOrRec; this.multiCurve = MultiCurve; this.nominal = Nominal; }
private delegate double SwapRate(SwapStyle S); // used in function to calculate swap rate private double ParRate(SwapStyle S) { // floating leg data double[] yfFloatLeg = S.scheduleLeg2.GetYFVect(S.swapLeg2.DayCount); // floating leg is leg 2 double[] dfFloatLeg = (from c in S.scheduleLeg2.payDates select DCurve.Df(c)).ToArray(); double[] fwdFloatLeg = (from c in S.scheduleLeg2.fromDates select FWDInterpolator.Solve(c.SerialValue)).ToArray(); // fixed leg data double[] yfFixLeg = S.scheduleLeg1.GetYFVect(S.swapLeg1.DayCount); // fixed is leg 1 double[] dfFixLeg = (from c in S.scheduleLeg1.payDates select DCurve.Df(c)).ToArray(); // calculate par swap rate according to given data return(Formula.ParRateFormula(yfFloatLeg, dfFloatLeg, fwdFloatLeg, yfFixLeg, dfFixLeg)); }
public static double Swaption(double N, double K, string Start, string SwapTenor, bool isPayer, double sigma, IRateCurve Curve) { Date refDate = Curve.RefDate(); // curve ref date // false/true with fwd swap matrix Date startDate = refDate.add_period(Start, false); // swap start 2 business days after the expiry Date expDate = startDate.add_workdays(-2); // expiry of swaption Date today = refDate.add_workdays(-2); double T = today.YF_365(expDate); Period p = new Period(SwapTenor); // should be in year 1Y, 2Y (not 3m,...) SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(startDate, 0, SwapTenor, Curve.GetSwapStyle().buildingBlockType); double[] yf = y.scheduleLeg1.GetYFVect(Dc._30_360); double[] df = (from payDay in y.scheduleLeg1.payDates select Curve.Df(payDay)).ToArray(); return(Swaption(N, Curve.SwapFwd(startDate, SwapTenor), K, sigma, T, isPayer, yf, df)); }
// constructor public CapletMatrixVolBuilder(string[] Tenor, IRateCurve Curve, double[] strike, List <double[]> VolSilos) { #region preparing data // yf of longer cap SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(Curve.RefDate(), 0, Tenor.Last(), Curve.GetSwapStyle().buildingBlockType); double[] yf = y.scheduleLeg2.GetYFVect(Dc._Act_360); 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 double[] T = (from c in ToDate select refDate.YF_365(c)).ToArray(); // available T from input double[] Tquoted = new double[Tenor.Length]; for (int i = 0; i < Tquoted.Length; i++) { // calculate yf of each available T as it was a swap SwapStyle myS = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(Curve.RefDate(), 0, Tenor[i], Curve.GetSwapStyle().buildingBlockType); int L = myS.scheduleLeg2.toDates.Count() - 1; Date[] toDate = myS.scheduleLeg2.toDates; Tquoted[i] = refDate.YF_365(toDate[L - 1]); } // df- getting relevant dates Date[] dfDate = y.scheduleLeg2.payDates; int Ncaplet = yf.Length; // number of caplets double[] df = new double[Ncaplet]; // fwd rate double[] 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]); } #endregion Ini(T, df, fwd, yf, Tquoted, VolSilos, strike); }
// 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]); } }
public RateSet mktRateSet; // market starting data // constructor: RateSet rateSet are market data inputs public SingleCurveBuilder(RateSet rateSet) { // RefDate refDate = rateSet.refDate; PostProcessInterpo = new Interpolation(); // Post process interpolator interpAdapter = new DoInterpOn(); mktRateSet = rateSet; // Create Building block IEnumerable <BuildingBlock> BB = rateSet.GetArrayOfBB(); // Sort ascending end date BBArray = from c in BB orderby c.endDate.SerialValue ascending select c; // Only Given Swap from BBArray OnlyGivenSwap = (from c in BBArray where c.GetType().BaseType == typeof(SwapStyle) select(SwapStyle) c).ToArray(); // some data validation: swap should be all of same building block // the type of building block BuildingBlockType BBT = OnlyGivenSwap[0].buildingBlockType; // Are all them the same? bool IsSameSwapType = OnlyGivenSwap.All(s => s.buildingBlockType == BBT); if (IsSameSwapType) // if true { // it is swap type used as inputs (i.e. EurSwapVs6m, EurSwapVs3m, ...) SwapType = (SwapStyle) new BuildingBlockFactory().CreateEmptyBuildingBlock(BBT); } else { throw new ArgumentException("error in building blocktype"); // if not throw an exception } }
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)); }
// More on sensitivities calc public static void MoreOnSensitivities() { #region Inputs // Start input Date refDate = new Date(2010, 10, 11); // I populate market rates set: from file, from real time, ... RateSet mktRates = new RateSet(refDate); // Depos mktRates.Add(1.243e-2, "1m", BuildingBlockType.EURDEPO); mktRates.Add(1.435e-2, "3m", BuildingBlockType.EURDEPO); mktRates.Add(1.720e-2, "6m", BuildingBlockType.EURDEPO); // Swap Vs 6M mktRates.Add(1.869e-2, "1Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.316e-2, "2Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.544e-2, "3Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.745e-2, "4Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.915e-2, "5Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.057e-2, "6Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.175e-2, "7Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.273e-2, "8Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.362e-2, "9Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.442e-2, "10Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.589e-2, "12Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.750e-2, "15Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.835e-2, "20Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.787e-2, "25Y", BuildingBlockType.EURSWAP6M); #endregion end Inputs #region building curve List <ISingleRateCurve> Curves = new List <ISingleRateCurve>(); // initialised each class and add to list. You can add more curves // Setup (a) in Table 15.3 SingleCurveBuilderStandard <OnLogDf, LinearInterpolator> c2 = new SingleCurveBuilderStandard <OnLogDf, LinearInterpolator>(mktRates, OneDimensionInterpolation.Linear); Curves.Add(c2); // Setup (b) in Table 15.3 SingleCurveBuilderSmoothingFwd <OnLogDf, SimpleCubicInterpolator> c1 = new SingleCurveBuilderSmoothingFwd <OnLogDf, SimpleCubicInterpolator>(mktRates); Curves.Add(c1); string swapTenor = "11y"; // you can change it #endregion end building curve #region myFunction Func <SwapStyle, IRateCurve, double> NPV = (BB, c) => { #region FixLeg // fixed leg data double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1 // dfs array of fixed lag Date[] dfDates = BB.scheduleLeg1.payDates; // serial date of fixed lag (each dates we should find df) // # of fixed cash flows int n_fix = dfDates.Length; double NPV_fix = 0.0; // calculate df for (int i = 0; i < n_fix; i++) { NPV_fix += c.Df(dfDates[i]) * yfFixLeg[i] * BB.rateValue; // df*yf } // NPV_fix *= BB.rateValue; #endregion #region FloatLeg // fixed leg data double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount); // float is leg 2 // dfs array of fixed lag Date[] dfDatesFloat = BB.scheduleLeg2.payDates; // serial date of float lag (each dates we should find df) Date[] toDateFloat = BB.scheduleLeg2.toDates; // # of fixed cash flows int n_float = dfDatesFloat.Length; double[] fwd = new double[n_float]; fwd[0] = ((1 / c.Df(toDateFloat[0])) - 1) / refDate.YF(toDateFloat[0], Dc._Act_360);; for (int i = 1; i < n_float; i++) { double yf = toDateFloat[i - 1].YF(toDateFloat[i], Dc._Act_360); double df_ini = c.Df(toDateFloat[i - 1]); double df_end = c.Df(toDateFloat[i]); fwd[i] = ((df_ini / df_end) - 1) / yf; } double NPV_float = 0.0; // calculate df for (int i = 0; i < n_float; i++) { NPV_float += c.Df(dfDatesFloat[i]) * yfFloatLeg[i] * fwd[i]; // df*yf } #endregion return(NPV_fix - NPV_float); }; #endregion #region Print results foreach (ISingleRateCurve C in Curves) { double swapRate = C.SwapFwd(refDate, swapTenor); IRateCurve[] cs = C.ShiftedCurveArray(0.0001); IRateCurve csp = C.ParallelShift(0.0001); // initialise some variable used in sensitivities double sens = 0.0; double runSum = 0.0; // standard Console.WriteLine(C.ToString()); SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(refDate, swapRate, swapTenor, BuildingBlockType.EURSWAP6M); double iniMTM = NPV(y, C) * 100000000; Console.WriteLine("{0} swap ATM fwd: {1:f5}", swapTenor, swapRate); Console.WriteLine("Starting P&L {0:f}", iniMTM); int nOfRate = mktRates.Count; for (int i = 0; i < nOfRate; i++) { sens = NPV(y, cs[i]) * 100000000 - iniMTM; Console.WriteLine("{0} BPV: {1:f}", mktRates.Item(i).M.GetPeriodStringFormat(), sens); runSum += sens; } Console.WriteLine("Total: {0:f}", runSum); Console.WriteLine("Parallel Total: {0:f}", NPV(y, csp) * 100000000 - iniMTM); Console.WriteLine("Press a key to continue"); Console.ReadLine(); } #endregion }
// Prepare data to be used in Solve() protected override void PreProcessInputs() { /* * 1) Check if input data are ok (data validation): from date contained * 2) I choose the Longer Swap (LS) * 3) I get array of dates of payment of LS (pass it to data member) * 4) I get array of year fraction of LS (pass it to data member) */ // From date of each fwd rate from longer swap(LS) List <double> FromDatesSerial = Date.GetSerialValue(OnlyGivenSwap.Last().scheduleLeg2.fromDates).ToList <double>(); // validating underlying tenor: swap should be all vs the same tenor string UnderlyingTenor = ((SwapStyle)OnlyGivenSwap.First()).swapLeg2.UnderlyingRateTenor; foreach (SwapStyle b in OnlyGivenSwap) { // Check if contained if (!FromDatesSerial.Contains(((SwapStyle)b).scheduleLeg2.fromDates.Last().SerialValue)) { throw new ArgumentException("From date not contained"); } } DateDf = new SortedList <double, double>(); // Inizialize DateDF DateDf.Add(refDate.SerialValue, 1.0); // first discount factor // IEnumerable<KeyValuePair<double,double>> var f = from c in BBArray where c.GetType().BaseType == typeof(OnePaymentStyle) where c.endDate != refDate.add_period(UnderlyingTenor) let yf = refDate.YF(c.endDate, c.dayCount) // year fraction let df = Formula.DFsimple(yf, c.rateValue) // calculate discount factor select new KeyValuePair <double, double>(c.endDate.SerialValue, df); foreach (KeyValuePair <double, double> kpv in f) { DateDf.Add(kpv.Key, kpv.Value); } // Getting the fixing fixing = (from c in BBArray where c.GetType().BaseType == typeof(OnePaymentStyle) where c.endDate == refDate.add_period(UnderlyingTenor) select c.rateValue).Single(); // Inizialize some data member SwapStyle LongerSwap = OnlyGivenSwap.Last(); // Swap with longer maturity // Year Fraction of floating leg of longer swap. It is needed to calculate DF yfFloatLegLongerSwap = LongerSwap.scheduleLeg2.GetYFVect(LongerSwap.swapLeg2.DayCount); // floating leg is leg 2 // Dates on which I calculate Df DatesDfLongerSwap = Date.GetSerialValue(LongerSwap.scheduleLeg2.payDates); // number of fwd rate to find N = DatesDfLongerSwap.Length; // fwd rate of longer swap fwdGuessLongerSwap = new double[N]; fwdGuessLongerSwap[0] = fixing; // first is the fixing }
// sensitivities/DVO1. ATM swap has no sensitivities with respect to the discount curve public static void SensitivitiesParallel() { #region Inputs // Start input // Start input, reference date. Date refDate = (new Date(DateTime.Now)).mod_foll(); #region Eonia market data // I populate market rates set: from file, from real time, ... RateSet mktRates = new RateSet(refDate); mktRates.Add(0.447e-2, "1w", BuildingBlockType.EONIASWAP); mktRates.Add(0.583e-2, "2w", BuildingBlockType.EONIASWAP); mktRates.Add(0.627e-2, "3w", BuildingBlockType.EONIASWAP); mktRates.Add(0.635e-2, "1m", BuildingBlockType.EONIASWAP); mktRates.Add(0.675e-2, "2m", BuildingBlockType.EONIASWAP); mktRates.Add(0.705e-2, "3m", BuildingBlockType.EONIASWAP); mktRates.Add(0.734e-2, "4m", BuildingBlockType.EONIASWAP); mktRates.Add(0.758e-2, "5m", BuildingBlockType.EONIASWAP); mktRates.Add(0.780e-2, "6m", BuildingBlockType.EONIASWAP); mktRates.Add(0.798e-2, "7m", BuildingBlockType.EONIASWAP); mktRates.Add(0.816e-2, "8m", BuildingBlockType.EONIASWAP); mktRates.Add(0.834e-2, "9m", BuildingBlockType.EONIASWAP); mktRates.Add(0.849e-2, "10m", BuildingBlockType.EONIASWAP); mktRates.Add(0.864e-2, "11m", BuildingBlockType.EONIASWAP); mktRates.Add(0.878e-2, "1Y", BuildingBlockType.EONIASWAP); mktRates.Add(1.098e-2, "2Y", BuildingBlockType.EONIASWAP); mktRates.Add(1.36e-2, "3Y", BuildingBlockType.EONIASWAP); mktRates.Add(1.639e-2, "4Y", BuildingBlockType.EONIASWAP); mktRates.Add(1.9e-2, "5Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.122e-2, "6Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.308e-2, "7Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.467e-2, "8Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.599e-2, "9Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.715e-2, "10Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.818e-2, "11Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.908e-2, "12Y", BuildingBlockType.EONIASWAP); // From here interpolation is need mktRates.Add(3.093e-2, "15Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.173e-2, "20Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.114e-2, "25Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.001e-2, "30Y", BuildingBlockType.EONIASWAP); #endregion #region Swap Market Data // RateSet EUR 6m swap RateSet rs = new RateSet(refDate); rs.Add(1.16e-2, "6m", BuildingBlockType.EURDEPO); rs.Add(1.42e-2, "1y", BuildingBlockType.EURSWAP6M); rs.Add(1.635e-2, "2y", BuildingBlockType.EURSWAP6M); rs.Add(1.872e-2, "3y", BuildingBlockType.EURSWAP6M); rs.Add(2.131e-2, "4y", BuildingBlockType.EURSWAP6M); rs.Add(2.372e-2, "5y", BuildingBlockType.EURSWAP6M); rs.Add(2.574e-2, "6y", BuildingBlockType.EURSWAP6M); rs.Add(2.743e-2, "7y", BuildingBlockType.EURSWAP6M); rs.Add(2.886e-2, "8y", BuildingBlockType.EURSWAP6M); rs.Add(3.004e-2, "9y", BuildingBlockType.EURSWAP6M); rs.Add(3.107e-2, "10y", BuildingBlockType.EURSWAP6M); rs.Add(3.198e-2, "11y", BuildingBlockType.EURSWAP6M); rs.Add(3.278e-2, "12y", BuildingBlockType.EURSWAP6M); rs.Add(3.344e-2, "13y", BuildingBlockType.EURSWAP6M); rs.Add(3.398e-2, "14y", BuildingBlockType.EURSWAP6M); rs.Add(3.438e-2, "15y", BuildingBlockType.EURSWAP6M); rs.Add(3.467e-2, "16y", BuildingBlockType.EURSWAP6M); rs.Add(3.484e-2, "17y", BuildingBlockType.EURSWAP6M); rs.Add(3.494e-2, "18y", BuildingBlockType.EURSWAP6M); rs.Add(3.495e-2, "19y", BuildingBlockType.EURSWAP6M); rs.Add(3.491e-2, "20y", BuildingBlockType.EURSWAP6M); rs.Add(3.483e-2, "21y", BuildingBlockType.EURSWAP6M); rs.Add(3.471e-2, "22y", BuildingBlockType.EURSWAP6M); rs.Add(3.455e-2, "23y", BuildingBlockType.EURSWAP6M); rs.Add(3.436e-2, "24y", BuildingBlockType.EURSWAP6M); rs.Add(3.415e-2, "25y", BuildingBlockType.EURSWAP6M); rs.Add(3.391e-2, "26y", BuildingBlockType.EURSWAP6M); rs.Add(3.366e-2, "27y", BuildingBlockType.EURSWAP6M); rs.Add(3.340e-2, "28y", BuildingBlockType.EURSWAP6M); rs.Add(3.314e-2, "29y", BuildingBlockType.EURSWAP6M); rs.Add(3.29e-2, "30y", BuildingBlockType.EURSWAP6M); #endregion #endregion end Inputs #region building curve string swapTenor = "11y"; // you can change it // I build my multi curve, SingleCurveBuilderStandard <OnLogDf, SimpleCubicInterpolator> DCurve = new SingleCurveBuilderStandard <OnLogDf, SimpleCubicInterpolator>(mktRates, OneDimensionInterpolation.LogLinear); // discount curve MultiCurveBuilder <SimpleCubicInterpolator> C = new MultiCurveBuilder <SimpleCubicInterpolator>(rs, DCurve); // multi curve #endregion end building curve #region myFunction // my function to calculate Net Present Value of a Vanilla Swap (receiver swap) Func <SwapStyle, IRateCurve, double> NPV = (BB, c) => { #region FixLeg // fixed leg data double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1 // dfs array of fixed lag Date[] dfDates = BB.scheduleLeg1.payDates; // serial date of fixed lag (each dates we should find df) // # of fixed cash flows int n_fix = dfDates.Length; double NPV_fix = 0.0; // calculate df for (int i = 0; i < n_fix; i++) { NPV_fix += c.Df(dfDates[i]) * yfFixLeg[i] * BB.rateValue; // df*yf } // NPV_fix *= BB.rateValue; #endregion #region FloatLeg // fixed leg data double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount); // float is leg 2 // dfs array of fixed lag Date[] dfDatesFloat = BB.scheduleLeg2.payDates; // serial date of float lag (each dates we should find df) Date[] FromDateFloat = BB.scheduleLeg2.fromDates; // # of fixed cash flows int n_float = dfDatesFloat.Length; double[] fwd = new double[n_float]; // fwd rate container // getting fwd rates for (int i = 0; i < n_float; i++) { fwd[i] = c.Fwd(FromDateFloat[i]); } double NPV_float = 0.0; // calculate df for (int i = 0; i < n_float; i++) { NPV_float += c.Df(dfDatesFloat[i]) * yfFloatLeg[i] * fwd[i]; // df*yf } #endregion return(NPV_fix - NPV_float); // NPV }; #endregion #region Print results double atmSwap = C.SwapFwd(refDate, swapTenor); // At The Money swap (i.e. par rate) List <double> swapRateList = new List <double>(); // lists of swap to analyze swapRateList.Add(atmSwap); // it is ATM swapRateList.Add(atmSwap + 0.01); // it has positive mark to market (MtM). It is a receiver swap with a contract rate > than Atm) swapRateList.Add(atmSwap - 0.01); // it has negative MtM // iterate for each swap: // see how change the sign of sensitivities for discount curve and for forwarding curve changing contract rates Console.WriteLine("Executing parallel loop..."); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Parallel.ForEach(swapRateList, swapRate => { Console.WriteLine("Pricing Receiver Swap {0}, Atm Rate: {1:f6}, Contract Rate: {2:f6}", swapTenor, atmSwap, swapRate); IRateCurve[] cs = C.ShiftedCurvesArrayFwdCurve(0.0001); IRateCurve csp = C.ParallelShiftFwdCurve(0.0001); // initialise some variable used in sensitivities double sens = 0.0; double runSum = 0.0; // Standard swap SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(refDate, swapRate, swapTenor, BuildingBlockType.EURSWAP6M); double iniMTM = NPV(y, C) * 100000000; // initial mark to market for 100ml receiver contract Console.WriteLine("Starting Mark To Market {0:f}", iniMTM); Console.WriteLine("Sensitivities to Curve used for forward rate: "); int nOfRate = rs.Count; // iterate for market input for forwarding curve for (int i = 0; i < nOfRate; i++) { sens = NPV(y, cs[i]) * 100000000 - iniMTM; Console.WriteLine("{0} BPV: {1:f}", rs.Item(i).M.GetPeriodStringFormat(), sens); runSum += sens; } Console.WriteLine("Total: {0:f}", runSum); Console.WriteLine("\nParallel Shift Total: {0:f}", NPV(y, csp) * 100000000 - iniMTM); // parallel shift // reset some variable used in sensitivities sens = 0.0; runSum = 0.0; Console.WriteLine("Sensitivities to Discount Curve:"); // let's consider discounting curve IRateCurve[] DCrvs = C.ShiftedCurvesArrayDCurve(0.0001); // shifting each bucket IMultiRateCurve DCrvp = C.ParallelShiftDCurve(0.0001); // parallel shift nOfRate = mktRates.Count; // iterate for market input for discounting curve for (int i = 0; i < nOfRate; i++) { sens = NPV(y, DCrvs[i]) * 100000000 - iniMTM; Console.WriteLine("{0} BPV: {1:f}", mktRates.Item(i).M.GetPeriodStringFormat(), sens); runSum += sens; } Console.WriteLine("Total: {0:f}", runSum); Console.WriteLine("\nParallel Shift Total: {0:f}", NPV(y, DCrvp) * 100000000 - iniMTM); }); stopwatch.Stop(); Console.WriteLine("Parallel loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds); #endregion }
// Print on excel forward rate using different curve builder for 3m public static void CheckFwdRatesVs3m() { #region Inputs // Start input Date refDate = (new Date(DateTime.Now)).mod_foll(); // I populate market rates set: from file, from real time, ... RateSet mktRates = new RateSet(refDate); // Depos mktRates.Add(0.434e-2, "3m", BuildingBlockType.EURDEPO); // Swap Vs 3M mktRates.Add(0.813e-2, "1Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.096e-2, "2Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.322e-2, "3Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.529e-2, "4Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.709e-2, "5Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.862e-2, "6Y", BuildingBlockType.EURSWAP3M); mktRates.Add(1.991e-2, "7Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.101e-2, "8Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.197e-2, "9Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.285e-2, "10Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.443e-2, "12Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.614e-2, "15Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.711e-2, "20Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.671e-2, "25Y", BuildingBlockType.EURSWAP3M); mktRates.Add(2.589e-2, "30Y", BuildingBlockType.EURSWAP3M); #endregion end Inputs #region building curve SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator> C1 = new SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator>(mktRates); double firstFixing = 0.434e-2; SingleCurveBuilderSmoothingFwd <OnLogDf, SimpleCubicInterpolator> C2 = new SingleCurveBuilderSmoothingFwd <OnLogDf, SimpleCubicInterpolator>(mktRates, firstFixing); SingleCurveBuilderStandard <OnLogDf, LinearInterpolator> C3 = new SingleCurveBuilderStandard <OnLogDf, LinearInterpolator>(mktRates, OneDimensionInterpolation.Linear); #endregion end building curve List <IRateCurve> CurveList = new List <IRateCurve>(); // list containing curve List <string> CurveString = new List <string>(); // list containing labels // populate lists CurveList.Add(C1); CurveString.Add(C1.ToString()); CurveList.Add(C2); CurveString.Add(C2.ToString()); CurveList.Add(C3); CurveString.Add(C3.ToString()); #region printing output // I get the longer swap SwapStyle LS = (SwapStyle)mktRates.GetArrayOfBB().Last(); Dc dc = Dc._Act_360; Date[] FromDate = LS.scheduleLeg2.fromDates; Date[] ToDate = LS.scheduleLeg2.toDates; int N = FromDate.Length; List <Vector <double> > Fwds = new List <Vector <double> >(); double[] dt = new double[N]; for (int i = 0; i < N; i++) { dt[i] = FromDate[0].YF(ToDate[i], Dc._30_360); } foreach (IRateCurve myC in CurveList) { double[] fwd = new double[N]; for (int i = 0; i < N; i++) { double yf = FromDate[i].YF(ToDate[i], dc); double df_ini = myC.Df(FromDate[i]); double df_end = myC.Df(ToDate[i]); fwd[i] = ((df_ini / df_end) - 1) / yf; } Fwds.Add(new Vector <double>(fwd)); } ExcelMechanisms exl = new ExcelMechanisms(); exl.printInExcel(new Vector <double>(dt), CurveString, Fwds, "Fwd vs 3M", "time", "rate"); // .printInExcel<T> #endregion end printing output }
// Print on excel forward rate using different curve builder for OIS fwd 3m public static void CheckFwdRatesOIS3m() { #region Inputs // ref date Date refDate = (new Date(DateTime.Now)).mod_foll(); // I populate market rates set: from file, from real time, ... RateSet mktRates = new RateSet(refDate); mktRates.Add(2.338e-2, "1d", BuildingBlockType.EURDEPO); // mktRates.Add(2.272e-2, "1w", BuildingBlockType.EONIASWAP); // mktRates.Add(2.241e-2, "2w", BuildingBlockType.EONIASWAP); // mktRates.Add(2.16e-2, "3w", BuildingBlockType.EONIASWAP); // mktRates.Add(2.226e-2, "1m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.299e-2, "2m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.323e-2, "3m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.344e-2, "4m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.371e-2, "5m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.39e-2, "6m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.41e-2, "7m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.4316e-2, "8m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.449e-2, "9m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.466e-2, "10m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.48e-2, "11m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.529e-2, "15m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.565e-2, "18m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.603e-2, "21m", BuildingBlockType.EONIASWAP); // mktRates.Add(2.493e-2, "1Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.644e-2, "2Y", BuildingBlockType.EONIASWAP); mktRates.Add(2.849e-2, "3Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.08e-2, "4Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.292e-2, "5Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.471e-2, "6Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.621e-2, "7Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.748e-2, "8Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.86e-2, "9Y", BuildingBlockType.EONIASWAP); mktRates.Add(3.965e-2, "10Y", BuildingBlockType.EONIASWAP); mktRates.Add(4.064e-2, "11Y", BuildingBlockType.EONIASWAP); mktRates.Add(4.155e-2, "12Y", BuildingBlockType.EONIASWAP); // From here interpolation is need mktRates.Add(4.358e-2, "15Y", BuildingBlockType.EONIASWAP); mktRates.Add(4.48e-2, "20Y", BuildingBlockType.EONIASWAP); mktRates.Add(4.465e-2, "25Y", BuildingBlockType.EONIASWAP); mktRates.Add(4.415e-2, "30Y", BuildingBlockType.EONIASWAP); List <IRateCurve> CurveList = new List <IRateCurve>(); // list containing curve List <string> CurveString = new List <string>(); // list containing labels #endregion end Inputs #region building curve SingleCurveBuilderStandard <OnDf, LinearInterpolator> C1 = new SingleCurveBuilderStandard <OnDf, LinearInterpolator>(mktRates, OneDimensionInterpolation.Linear); SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator> C2 = new SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator>(mktRates); #endregion end building curve // populate lists CurveList.Add(C1); CurveString.Add(C1.ToString()); CurveList.Add(C2); CurveString.Add(C2.ToString()); #region printing output // I get the longer eonia swap available from the input data SwapStyle LS = (SwapStyle)mktRates.GetArrayOfBB().Last(); Schedule s = new Schedule(refDate, LS.endDate, "3m", Rule.Backward, LS.swapLeg1.SwapBusDayRollsAdj, "0d", LS.swapLeg1.SwapBusDayPayAdj); Dc dc = Dc._Act_360; Date[] FromDate = s.fromDates; Date[] ToDate = s.toDates; int N = FromDate.Length; List <Vector <double> > Fwds = new List <Vector <double> >(); double[] dt = new double[N]; for (int i = 0; i < N; i++) { dt[i] = FromDate[0].YF(ToDate[i], Dc._30_360); } foreach (IRateCurve myC in CurveList) { double[] fwd = new double[N]; for (int i = 0; i < N; i++) { double yf = FromDate[i].YF(ToDate[i], dc); double df_ini = myC.Df(FromDate[i]); double df_end = myC.Df(ToDate[i]); fwd[i] = ((df_ini / df_end) - 1) / yf; } Fwds.Add(new Vector <double>(fwd)); } ExcelMechanisms exl = new ExcelMechanisms(); exl.printInExcel(new Vector <double>(dt), CurveString, Fwds, "Fwd 3M", "time", "rate"); // .printInExcel<T> #endregion end printing output }
// Calculate sensitivities public static void Sensitivities() { #region Inputs // Start input Date refDate = new Date(2019, 2, 25); // I populate market rates set: from file, from real time, ... RateSet mktRates = new RateSet(refDate); // Depos mktRates.Add(1.243e-2, "1m", BuildingBlockType.EURDEPO); mktRates.Add(1.435e-2, "3m", BuildingBlockType.EURDEPO); mktRates.Add(1.720e-2, "6m", BuildingBlockType.EURDEPO); // Swap Vs 6M mktRates.Add(1.869e-2, "1Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.316e-2, "2Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.544e-2, "3Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.745e-2, "4Y", BuildingBlockType.EURSWAP6M); mktRates.Add(2.915e-2, "5Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.057e-2, "6Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.175e-2, "7Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.273e-2, "8Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.362e-2, "9Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.442e-2, "10Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.589e-2, "12Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.750e-2, "15Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.835e-2, "20Y", BuildingBlockType.EURSWAP6M); mktRates.Add(3.787e-2, "25Y", BuildingBlockType.EURSWAP6M); // I shift 1bp up 10y swap input rate int IndexShifted = 12; RateSet mktRates2 = mktRates.ShiftedRateSet(IndexShifted, 0.0001); // print out first and second market input rates for (int i = 0; i < mktRates.Count; i++) { Console.WriteLine("First: {0} {1} Second: {2} {3}", mktRates.Item(i).M.GetPeriodStringFormat(), mktRates.Item(i).V, mktRates2.Item(i).M.GetPeriodStringFormat(), mktRates2.Item(i).V); } #endregion end Inputs #region building curve // First curve: using markets rates SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator> c1 = new SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator>(mktRates); // Second curve: like c1 but 10Y input rate is shifted SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator> c2 = new SingleCurveBuilderInterpBestFit <OnLogDf, SimpleCubicInterpolator>(mktRates2); string swapTenor = "10y"; // you can change it #endregion end building curve #region myFunction Func <SwapStyle, IRateCurve, double> NPV = (BB, c) => { #region FixLeg // fixed leg data double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1 // dfs array of fixed lag Date[] dfDates = BB.scheduleLeg1.payDates; // serial date of fixed lag (each dates we should find df) // # of fixed cash flows int n_fix = dfDates.Length; double NPV_fix = 0.0; // calculate df for (int i = 0; i < n_fix; i++) { NPV_fix += c.Df(dfDates[i]) * yfFixLeg[i] * BB.rateValue; // df*yf } // NPV_fix *= BB.rateValue; #endregion #region FloatLeg // fixed leg data double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount); // float is leg 2 // dfs array of fixed lag Date[] dfDatesFloat = BB.scheduleLeg2.payDates; // serial date of float lag (each dates we should find df) Date[] toDateFloat = BB.scheduleLeg2.toDates; // # of fixed cash flows int n_float = dfDatesFloat.Length; double[] fwd = new double[n_float]; fwd[0] = ((1 / c.Df(toDateFloat[0])) - 1) / refDate.YF(toDateFloat[0], Dc._Act_360);; for (int i = 1; i < n_float; i++) { double yf = toDateFloat[i - 1].YF(toDateFloat[i], Dc._Act_360); double df_ini = c.Df(toDateFloat[i - 1]); double df_end = c.Df(toDateFloat[i]); fwd[i] = ((df_ini / df_end) - 1) / yf; } double NPV_float = 0.0; // calculate df for (int i = 0; i < n_float; i++) { NPV_float += c.Df(dfDatesFloat[i]) * yfFloatLeg[i] * fwd[i]; // df*yf } #endregion return(NPV_fix - NPV_float); }; #endregion #region Print results // test forward swap starting in ref date (it should be like simple spot swap) double swapRate = c1.SwapFwd(refDate, swapTenor); // I create the swap according to standard convention SwapStyle y = (SwapStyle) new BuildingBlockFactory().CreateBuildingBlock(refDate, swapRate, swapTenor, BuildingBlockType.EURSWAP6M); // initial NPV double iniMTM = NPV(y, c1) * 100000000; // print out Console.WriteLine("IRS to be priced tenor: {0}. IRS to be priced rate: {1:f5}", swapTenor, swapRate); Console.WriteLine("{0} swap ATM fwd according the starting curve: {1:f5}. Starting P&L {2:f}", swapTenor, swapRate, iniMTM); Console.WriteLine("Let's shift {0} rate from {1:f5} to {2:f5}", mktRates.Item(IndexShifted).M.GetPeriodStringFormat(), mktRates.Item(IndexShifted).V, mktRates2.Item(IndexShifted).V); // NPV after shift double endMTM = NPV(y, c2) * 100000000; Console.WriteLine("{0} swap ATM fwd after shifting: {1:f5}. P&L after shifting {2:f}", swapTenor, c2.SwapFwd(refDate, swapTenor), endMTM); Console.WriteLine("Press a key to continue"); Console.ReadLine(); #endregion }