protected override double CalcPv(IOption option, IMarketCondition market, double timeIncrement = 0.0) { var dayCount = market.DiscountCurve.Value.DayCount; var startDate = market.ValuationDate; var maturityDate = option.ExerciseDates.Last(); var t = dayCount.CalcDayCountFraction(market.ValuationDate, maturityDate) + timeIncrement; var bsProcess = new BlackScholesProcess( market.DiscountCurve.Value.ZeroRate(startDate, maturityDate), market.DividendCurves.Value.Values.First().ZeroRate(startDate, maturityDate), market.VolSurfaces.Value.Values.First().GetValue(maturityDate, option.Strike)); var pdeSolver = new SecondOrderPdeCrankNicolson( bsProcess.Drift, (t0, s) => 0.5 * Math.Pow(bsProcess.Diffusion(t0, s), 2.0), market.DiscountCurve.Value.GetSpotRate); double[] x; double[] xGrid; InitializeGrid(market.SpotPrices.Value.Values.First(), option.Strike, bsProcess.Diffusion(0, 0), t, out x, out xGrid); var dt = t / _steps; return(pdeSolver.Solve( Enumerable.Range(0, _steps + 1).Select(i => i * dt).ToArray(), xGrid, x, price => option.GetPayoff(new[] { price })[0].PaymentAmount )[0][_gridSize]); }
public double ReverseInduction() { var optionPrices = new double[_steps + 1][]; optionPrices[_steps] = new double[_steps + 1]; for (var j = 0; j < _steps + 1; ++j) { optionPrices[_steps][j] = _option.GetPayoff(new[] { _binomialTree.StateValue(_steps, j) }).Sum(x => x.PaymentAmount); } for (var i = _steps - 1; i >= 0; --i) { optionPrices[i] = new double[i + 1]; for (var j = 0; j <= i; ++j) { var pu = _binomialTree.Probability(i, j, BranchDirection.Up); var pd = _binomialTree.Probability(i, j, BranchDirection.Down); var dt = _binomialTree.Dt; var df = Math.Exp(-_binomialTree.Process.GetDiscountRate(0.0) * dt); var optionValue = df * (pu * optionPrices[i + 1][j + 1] + pd * optionPrices[i + 1][j]); if (_option.Exercise == OptionExercise.European) { optionPrices[i][j] = optionValue; } else { optionPrices[i][j] = ((i * dt) >= _tExStart && (i * dt) <= _tExEnd) ? Math.Max(_option.GetPayoff(new[] { _binomialTree.StateValue(i, j) }).Sum(x => x.PaymentAmount), optionValue) : optionValue; } } } return(optionPrices[0][0]); }
public double payOffaMaturite(IOption option, List <DataFeed> priceList) { return(option.GetPayoff(priceList.Last().PriceList)); }
//private double originalPv(IOption option, IMarketCondition market) { // var valueDate = market.ValuationDate; // var dayCount = market.DiscountCurve.Value.DayCount; // var tExStart = dayCount.CalcDayCountFraction(valueDate, option.ExerciseDates[0]); // var tExEnd = dayCount.CalcDayCountFraction(valueDate, option.ExerciseDates.Last()); // var binomialTree = BuildTree(market, tExEnd, option.Strike, market.SpotPrices.Value.Values.First(), _steps); // var treeEngine = new BinomialTreeWithNoDividend(binomialTree, option, _steps, tExStart, tExEnd); // return treeEngine.ReverseInduction(); //} private double BinomialDiscreteDividends( IOption option, IMarketCondition market, Date valueDate, IDayCount dayCount, double spotPrice, double r, double v, Tuple <Date, double>[] dividends, int steps, double tStart, double tEnd) { var dt = (tEnd - tStart) / steps; var df = Math.Exp(-r * dt); var u = Math.Exp(v * Math.Sqrt(dt)); var d = 1 / u; var a = Math.Exp(r * dt); var p = (a - d) / (u - d); var uu = u * u; if (dividends == null || dividends.Length == 0) { var binomialTree = BuildTree(market, tEnd, option.Strike, spotPrice, steps, vol: v, r: r); var treeEngine = new BinomialTreeWithNoDividend(binomialTree, option, steps, tStart, tEnd); return(treeEngine.ReverseInduction()); } var cashDividendDate = dividends.First().Item1; var cashDividendAmount = dividends.First().Item2; var tCashDividend = dayCount.CalcDayCountFraction(valueDate, cashDividendDate); var stepsBeforeDividend = Convert.ToInt16(Math.Floor(tCashDividend / (tEnd - tStart) * steps)); var stockPriceNodes = new List <double>(); var optionValueNodes = new List <double>(); var p0 = spotPrice * Math.Pow(d, stepsBeforeDividend); stockPriceNodes.Add(p0); foreach (int i in Enumerable.Range(1, stepsBeforeDividend)) { stockPriceNodes.Add(stockPriceNodes[i - 1] * uu); } //option value for the node time step just before dividend foreach (int i in Enumerable.Range(0, stepsBeforeDividend)) { var valueNotExercising = BinomialDiscreteDividends(option, market, valueDate, dayCount, spotPrice: stockPriceNodes[i] - cashDividendAmount, r: r, v: v, dividends: dividends.Skip(1).ToArray(), steps: steps - stepsBeforeDividend, tStart: tCashDividend, tEnd: tEnd); var exerciseValue = option.GetPayoff(new[] { stockPriceNodes[i] }).Sum(x => x.PaymentAmount); if (option.Exercise == OptionExercise.American) { optionValueNodes.Add(Math.Max(valueNotExercising, exerciseValue)); } else { optionValueNodes.Add(valueNotExercising); } } //option value before dividend , reverse induction, normal binomial foreach (int j in Enumerable.Range(0, stepsBeforeDividend - 1).Reverse()) { foreach (int i in Enumerable.Range(0, j)) { stockPriceNodes[i] = d * stockPriceNodes[i + 1]; var valueNotExercising = (p * optionValueNodes[i + 1] + (1 - p) * optionValueNodes[i]) * df; if (option.Exercise == OptionExercise.American) { var exerciseValue = option.GetPayoff(new[] { stockPriceNodes[i] }).Sum(x => x.PaymentAmount); optionValueNodes[i] = Math.Max(valueNotExercising, exerciseValue); } else { optionValueNodes[i] = valueNotExercising; } } } return(optionValueNodes[0]); }
/// <summary> /// 计算期权现值 /// </summary> /// <param name="option">期权</param> /// <param name="markets">市场</param> /// <returns>计算结果</returns> public override double[] CalcPvs(IOption option, IMarketCondition[] markets) { if (AnalyticalOptionPricerUtil.isForwardFuturesOption(option.UnderlyingProductType)) { //market = market.UpdateCondition(new UpdateMktConditionPack<Dictionary<string, IYieldCurve>>(m => m.DividendCurves, new Dictionary<string, IYieldCurve> { { "", market.DiscountCurve.Value} })); markets = markets.Select(x => x.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, IYieldCurve> >(m => m.DividendCurves, new Dictionary <string, IYieldCurve> { { "", x.DiscountCurve.Value } })) ).ToArray(); } var stochasticProcesses = CreateStochasticProcess1Ds(option, markets); var nProcess = stochasticProcesses.Length; var partitioner = Partitioner.Create(0, NumSimulations, NumSimulations / ParallelDegrees + 1); var partitionerPvs = Enumerable.Range(0, nProcess).Select(x => new List <double>()).ToArray(); var parallelOption = new ParallelOptions() { MaxDegreeOfParallelism = ParallelDegrees }; var size = option.ObservationDates.Length * 2 + 3; List <double>[] result = null; if (MonteCarloCollectPath) { result = new List <double> [NumSimulations + 1]; } Parallel.ForEach(partitioner, parallelOption, (range, loopState) => { var pvs = Enumerable.Range(0, nProcess).Select(x => new List <double>()).ToArray(); var random = new MersenneTwister(); for (var n = range.Item1; n < range.Item2; ++n) { var paths = PathGenerator.GeneratePath(stochasticProcesses, markets.Select(x => x.SpotPrices.Value.Values.First()).ToArray(), markets.Select(x => x.ValuationDate.Value).ToArray(), option.ObservationDates, option.Calendar, option.DayCount, random); for (var i = 0; i < nProcess; ++i) { pvs[i].Add( option.GetPayoff(paths[i]).Sum(cf => cf.PaymentAmount * markets[i].DiscountCurve.Value.GetDf(markets[i].ValuationDate.Value, cf.PaymentDate)) ); //pvs[i].Add(option.GetPayoff(paths[i]).Sum(cf => cf.PaymentAmount * market.DiscountCurve.Value.GetDf(market.ValuationDate.Value, cf.PaymentDate))); } //antithetic path for (var i = 0; i < nProcess; ++i) { pvs[i].Add(option.GetPayoff(paths[i + nProcess]).Sum(cf => cf.PaymentAmount * markets[i].DiscountCurve.Value.GetDf(markets[i].ValuationDate.Value, cf.PaymentDate))); //pvs[i].Add(option.GetPayoff(paths[i + nProcess]).Sum(cf => cf.PaymentAmount * market.DiscountCurve.Value.GetDf(market.ValuationDate.Value, cf.PaymentDate))); } if (MonteCarloCollectPath) { var originalPathPrices = from e in paths[0].ToList() orderby e.Key select e.Value; //original path price evolution //result[n].AddRange(prices.ToList()); result[n] = originalPathPrices.ToList(); //pv result[n].Add(pvs[0].First()); var antiPathPrices = from e in paths[1].ToList() orderby e.Key select e.Value; //antipath price evolution result[n].AddRange(antiPathPrices); //pv result[n].Add(pvs[0].Last()); //expected pv result[n].Add(pvs[0].Average()); } } lock (partitionerPvs) { for (var i = 0; i < nProcess; ++i) { partitionerPvs[i].Add(pvs[i].Average()); } } // }); if (MonteCarloCollectPath) { result[NumSimulations] = Enumerable.Repeat(0.0, 2 * (option.ObservationDates.Length + 1)).ToList(); result[NumSimulations].Add(partitionerPvs[0].Average()); var resultStr = result.Select(digits => string.Join(",", digits)).ToArray(); var folder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var filename = folder + "/MonteCarlo.csv"; File.WriteAllLines(filename, resultStr); } //return partitionerPvs[0].Average(); return(partitionerPvs.Select(x => x.Average()).ToArray()); }