/// <summary> /// Replaces the no exercise cashflows for the product at position <paramref name="key"/> with the cashflows based on /// an estimated optimal exercise policy. /// </summary> /// <param name="key">The position in <see cref="_allTrades"/> of the product to be updated.</param> private void ApplyEarlyExercise(int key) { // Get path-wise regressed values of post exercise products. var option = _allTrades[key] as IProductWithEarlyExercise; var exDates = option.GetExerciseDates(); var postExRegressedValues = new double[_numberOfPaths, exDates.Count]; for (var i = 0; i < exDates.Count; i++) { // perform regression on each exercise date var postExerciseProductInd = _postExerciseTrades[key][option.GetPostExProductAtDate(exDates[i])]; var fitted = PerformRegression(exDates[i], _simulatedCFs, _simulatedRegs, new List <int> { postExerciseProductInd }); postExRegressedValues.SetColumn(i, fitted); } // Iterate backwards // initially the stopping time on all paths is infinity (actually the year 3000) var optimalStop = new Date[_numberOfPaths]; var finalDate = new Date(3000, 1, 1); for (var i = 0; i < _numberOfPaths; i++) { optimalStop[i] = finalDate; } for (var exDateCount = exDates.Count - 1; exDateCount >= 0; exDateCount--) { var exDate = exDates[exDateCount]; // Optimal flows are underlying product up to the stopping time, then the post exercise product flows afterwards var pvOptimalCFs = Vector.Zeros(_numberOfPaths); for (var pathCount = 0; pathCount < _numberOfPaths; pathCount++) { if (optimalStop[pathCount] < finalDate) { var exProductInd = _postExerciseTrades[key][option.GetPostExProductAtDate(optimalStop[pathCount])]; foreach (var cf in _simulatedCFs.GetCFs(exProductInd, pathCount)) { if (cf.Date > optimalStop[pathCount]) { pvOptimalCFs[pathCount] += cf.Amount; } } } foreach (var cf in _simulatedCFs.GetCFs(key, pathCount)) { if (cf.Date > _valueDate && cf.Date <= optimalStop[pathCount]) { pvOptimalCFs[pathCount] += cf.Amount; } } } // update optimal stopping times var optimalCV = _simulatedRegs.FitCFs(exDate, pvOptimalCFs); for (var pathCount = 0; pathCount < _numberOfPaths; pathCount++) { if (option.IsLongOptionality(exDate) && optimalCV[pathCount] < postExRegressedValues[pathCount, exDateCount]) { optimalStop[pathCount] = exDate; } else if (!option.IsLongOptionality(exDate) && optimalCV[pathCount] > postExRegressedValues[pathCount, exDateCount]) { optimalStop[pathCount] = exDate; } } } // All stopping times have been found so now we can update the cashflows. // The cashflows are continuation flows up to the exercise date then cashflows from the // exercise product after that. var newCFs = new List <Cashflow> [_numberOfPaths]; for (var pathCount = 0; pathCount < _numberOfPaths; pathCount++) { newCFs[pathCount] = new List <Cashflow>(); var exProductInd = _postExerciseTrades[key][option.GetPostExProductAtDate(optimalStop[pathCount])]; foreach (var cf in _simulatedCFs.GetCFs(exProductInd, pathCount)) { if (cf.Date > optimalStop[pathCount]) { newCFs[pathCount].Add(cf); } } foreach (var cf in _simulatedCFs.GetCFs(key, pathCount)) { if (cf.Date > _valueDate && cf.Date <= optimalStop[pathCount]) { newCFs[pathCount].Add(cf); } } } _simulatedCFs.Update(key, newCFs); }
/// <summary> /// Replaces the no exercise cashflows for the product at position <paramref name="key"/> with the cashflows based on /// an estimated optimal exercise policy. /// </summary> /// <param name="key">The postion in <see cref="allTrades"/> of the product to be updated.</param> private void ApplyEarlyExercise(int key) { // Get pathwise regressed values of post exercise products. ProductWithEarlyExercise option = allTrades[key] as ProductWithEarlyExercise; List <Date> exDates = option.GetExerciseDates(); double[,] postExRegressedValues = new double[N, exDates.Count]; for (int i = 0; i < exDates.Count; i++) { // perform regression on each exercise date int postExerciseProductInd = postExerciseTrades[key][option.GetPostExProductAtDate(exDates[i])]; double[] fitted = PerformRegression(exDates[i], simulatedCFs, simulatedRegs, new List <int> { postExerciseProductInd }); postExRegressedValues.SetColumn(i, fitted); } // Iterate backwards // initially the stoppping time on all paths is infinity (actually the year 3000) Date[] optimalStop = new Date[N]; Date finalDate = new Date(3000, 1, 1); for (int i = 0; i < N; i++) { optimalStop[i] = finalDate; } for (int exDateCount = exDates.Count - 1; exDateCount >= 0; exDateCount--) { Date exDate = exDates[exDateCount]; // Optimal flows are underlying product up to the stopping time, then the post exercise product flows afterwards double[] pvOptimalCFs = Vector.Zeros(N); for (int pathCount = 0; pathCount < N; pathCount++) { if (optimalStop[pathCount] < finalDate) { int exProductInd = postExerciseTrades[key][option.GetPostExProductAtDate(optimalStop[pathCount])]; foreach (Cashflow cf in simulatedCFs.GetCFs(exProductInd, pathCount)) { if (cf.date > optimalStop[pathCount]) { pvOptimalCFs[pathCount] += cf.amount; } } } foreach (Cashflow cf in simulatedCFs.GetCFs(key, pathCount)) { if (cf.date > valueDate && cf.date <= optimalStop[pathCount]) { pvOptimalCFs[pathCount] += cf.amount; } } } // update optimal stopping times double[] optimalCV = simulatedRegs.FitCFs(exDate, pvOptimalCFs); for (int pathCount = 0; pathCount < N; pathCount++) { if (option.IsLongOptionality(exDate) && optimalCV[pathCount] < postExRegressedValues[pathCount, exDateCount]) { optimalStop[pathCount] = exDate; } else if (!option.IsLongOptionality(exDate) && optimalCV[pathCount] > postExRegressedValues[pathCount, exDateCount]) { optimalStop[pathCount] = exDate; } } } // All stopping times have been found so now we can update the cashflows. // The cashflows are continuation flows up to the exercise date then cashflows from the // exercise product after that. List <Cashflow>[] newCFs = new List <Cashflow> [N]; for (int pathCount = 0; pathCount < N; pathCount++) { newCFs[pathCount] = new List <Cashflow>(); int exProductInd = postExerciseTrades[key][option.GetPostExProductAtDate(optimalStop[pathCount])]; foreach (Cashflow cf in simulatedCFs.GetCFs(exProductInd, pathCount)) { if (cf.date > optimalStop[pathCount]) { newCFs[pathCount].Add(cf); } } foreach (Cashflow cf in simulatedCFs.GetCFs(key, pathCount)) { if (cf.date > valueDate && cf.date <= optimalStop[pathCount]) { newCFs[pathCount].Add(cf); } } } simulatedCFs.Update(key, newCFs); }