/// <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> /// Simulate forward rates and corresponding zero rates on the /// interval [settleDate, tmax] /// step in [months] /// </summary> public LiborMarketModelPath SimulateForwardRates(DateTime maxDate, int step = 3) { #region Numeraire // Numeraire at time 0: N(0) = B(0, T[k]) var intialNumeraire = InitialDiscountFactor[NumeraireIndex]; #endregion Numeraire #region Time discertization // Initialize rates //t = linspace(0, length(model.T(end-1)), 100); // Use 3 Month time step var dates = Utilities.TenorStructure(SettleDate, maxDate, step); // Convert to continous time in units of [years] var t = Utilities.ConvertToDayCountFraction(SettleDate, dates); #endregion Time discertization #region Forward rate // Initialize forward rate with its at time t = 0 value; var forwaredRates = Matrix <double> .Build.Dense(NumRates, t.Length); forwaredRates.SetColumn(0, InitialForwardRate); // Propagate forward rates for (var j = 0; j < t.Length - 1; j++) { var dt = t[j + 1] - t[j]; var forwardrate = PropagteForwardRate(t[j], forwaredRates.Column(j), NumeraireIndex, dt); forwaredRates.SetColumn(j + 1, forwardrate); } #endregion Forward rate #region Numeraire adjusted discount factor // Initialize numeraire-adjusted-discount factor with its at time t = 0 value; // D[i] = B[i]/B[k], where B[k] is the numeraire , i = 0, ..., n = length(T)-1 // D[i]: 0 <= t <= min(T[i], T[k]) // numeraireAdjustedDiscountFactors var discountFactors = Matrix <double> .Build.Dense(T.Count, t.Length); discountFactors.SetColumn(0, InitialDiscountFactor.Divide(intialNumeraire)); // Numeraire-adjusted discount factors for (var j = 1; j < t.Length; j++) { // forward rate for time t[j] var forwardRate = forwaredRates.Column(j); var discountFactor = Vector <double> .Build.Dense(T.Count); for (var i = 0; i < discountFactor.Count; i++) { #region Check time // Discount factor is not defined if (t[j] > Math.Min(T[i], T[NumeraireIndex])) { discountFactor[i] = double.NaN; continue; } #endregion Check time #region Compute numeraire adjusted discount factors from forward rate if (i == NumeraireIndex) { discountFactor[i] = 1; } else if (i < NumeraireIndex) { var prod = 1.0; for (var k = i; k <= NumeraireIndex - 1; k++) { prod *= 1 + Alpha[k] * forwardRate[k]; } discountFactor[i] = prod; } else if (i > NumeraireIndex) { var prod = 1.0; for (var k = NumeraireIndex; k <= i - 1; k++) { prod *= 1 + Alpha[k] * forwardRate[k]; } discountFactor[i] = 1.0 / prod; } #endregion Compute numeraire adjusted discount factors from forward rate } discountFactors.SetColumn(j, discountFactor); } #endregion Numeraire adjusted discount factor #region Result return(new LiborMarketModelPath { SettleDate = SettleDate, Dates = dates, Tenors = Alpha, TenorStructure = Utilities.ConvertFromDayCountFraction(SettleDate, T.ToArray()), ForwardRates = forwaredRates, NumeraireAdjustedDiscountFactors = discountFactors, InitialNumeraire = intialNumeraire }); #endregion Result }