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)); }