protected virtual void SetPricingVol(PricingResult result, IOption option, IMarketCondition market) { var vol = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: option.ExerciseDates.Last(), option: option, spot: market.SpotPrices.Value.Values.First()); result.PricingVol = vol; }
//Precise TimeValue Optiong Pricing Mode: // if nightMarket, // T0, <12:00, T = original T + 2/3 // T0, >12:00 && <15:00, T = original T + 1/3 // T0, >=15:00 && <21:00, T = original T // T0, >=21:00, T = original T (nightMarket) // if noNightMarket // T0, <12:00, T = orignal T + 1 // T0, >12:00 && <15:00, T = original T + 1/2 // T0, >= 15:00, T = original T /// <summary> /// 计算期权现值 /// </summary> /// <param name="option">期权</param> /// <param name="markets">市场</param> /// <returns>计算结果</returns> public virtual double[] CalcPvs(IOption option, IMarketCondition[] markets) { var timeIncrement = AnalyticalOptionPricerUtil.optionTimeToMaturityIncrement(option); return(markets.Select(x => { if (x.ValuationDate == option.ExerciseDates.Last()) { return CalcIntrinsicValue(option, x); } else { return CalcPv(option, x, timeIncrement); } }).ToArray()); }
private double DoCalcPv(IOption option, IMarketCondition market, double expiryDayRemainingLife = double.NaN, double timeIncrement = 0.0) { var valueDate = market.ValuationDate; var dayCount = market.DiscountCurve.Value.DayCount; var exerciseDates = option.ExerciseDates.Where(x => x >= market.ValuationDate).ToArray(); var tExStart = dayCount.CalcDayCountFraction(valueDate, exerciseDates[0]) + timeIncrement; var tExEnd = dayCount.CalcDayCountFraction(valueDate, exerciseDates.Last()) + timeIncrement; if (!double.IsNaN(expiryDayRemainingLife)) { tExEnd = expiryDayRemainingLife; } var spot = market.SpotPrices.Value.Values.First(); Tuple <Date, double>[] dividends = (option.Dividends != null)? option.Dividends.Select(x => new Tuple <Date, double>(x.Key, x.Value)).ToArray(): null; if (dividends != null) { Array.Sort(dividends, (o1, o2) => o1.Item1.CompareTo(o2.Item1)); } var sigma = AnalyticalOptionPricerUtil.pricingVol(volSurf: market.VolSurfaces.Value.Values.First(), exerciseDate: option.ExerciseDates.Last(), option: option, spot: spot); //Notional is been considered during simulation. var fa = BinomialDiscreteDividends(option, market, market.ValuationDate, dayCount: market.DiscountCurve.Value.DayCount, spotPrice: market.SpotPrices.Value.Values.First(), r: market.DiscountCurve.Value.ZeroRate(market.ValuationDate, option.ExerciseDates.Last()), v: sigma, dividends: dividends, steps: _steps, tStart: tExStart, tEnd: tExEnd); var option2 = option.Clone(OptionExercise.European); var bsmEngine = new AnalyticalVanillaEuropeanOptionEngine(); //if cash dividends, then annualize it to equivalent dividend yield //var diviFraction = dayCount.CalcDayCountFraction(option.StartDate, option.ExerciseDates.Last()); //var eqvDividendYield = (dividends ==null)? 0.0: dividends.Select(x => x.Item2).Sum() / spot / diviFraction; //var eqvDividendCurve = new YieldCurve( // "dividend", // valueDate, // new[] // { // Tuple.Create((ITerm)new Term("1D"), eqvDividendYield), // Tuple.Create((ITerm)new Term("1Y"), eqvDividendYield) // }, // BusinessDayConvention.ModifiedFollowing, // dayCount, // market.DividendCurves.Value.First().Value.Calendar, // CurrencyCode.CNY, // Compound.Continuous, // Interpolation.CubicHermiteMonotic, // YieldCurveTrait.SpotCurve // ); //var eqvMarket = market.UpdateDividendCurve(eqvDividendCurve, market.DividendCurves.Value.First().Key); var fbsm = bsmEngine.Calculate(option2, market, PricingRequest.Pv).Pv; var fe = BinomialDiscreteDividends(option2, market, market.ValuationDate, dayCount: market.DiscountCurve.Value.DayCount, spotPrice: spot, r: market.DiscountCurve.Value.ZeroRate(market.ValuationDate, option.ExerciseDates.Last()), v: sigma, dividends: dividends, steps: _steps, tStart: tExStart, tEnd: tExEnd); //control variate //fa + ( fbsm - fe) return(fa + (fbsm - fe)); }
/// <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()); }