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]);
        }
Exemple #2
0
        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));
 }
Exemple #4
0
        //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());
        }