public override IPricingResult Calculate(BinaryOption trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); if (trade.BinaryOptionPayoffType == BinaryOptionPayoffType.CashOrNothing) { var factor = (double)BinaryOptionReplicationStrategy; var lowStrike = trade.Strike + Offset * (factor - 1.0) / 2.0; var highStrike = trade.Strike + Offset * (factor + 1.0) / 2.0; //if call, replicate by call spreads, //if put, replicate by put spreads var lowStrikeOption = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, lowStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional); var highStrikeOption = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, highStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional); var engine = new AnalyticalVanillaEuropeanOptionEngine(); var lowResult = engine.Calculate(lowStrikeOption, market, request); var highResult = engine.Calculate(highStrikeOption, market, request); var sign = trade.OptionType == OptionType.Call ? 1.0 : -1.0; factor = sign * trade.CashOrNothingAmount / Offset; //calc basic stuff if (result.IsRequested(PricingRequest.Pv)) { result.Pv = (lowResult.Pv - highResult.Pv) * factor; } if (AnalyticalOptionPricerUtil.isBasicPricing(result)) { result.Delta = (lowResult.Delta - highResult.Delta) * factor; result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First(); result.Gamma = (lowResult.Gamma - highResult.Gamma) * factor; result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100; result.Vega = (lowResult.Vega - highResult.Vega) * factor; result.Rho = (lowResult.Rho - highResult.Rho) * factor; result.Theta = (lowResult.Theta - highResult.Theta) * factor; } if (AnalyticalOptionPricerUtil.isHighOrderPricing(result)) { result.DDeltaDvol = (lowResult.DDeltaDvol - highResult.DDeltaDvol) * factor; result.DVegaDvol = (lowResult.DVegaDvol - highResult.DVegaDvol) * factor; result.DVegaDt = (lowResult.DVegaDt - highResult.DVegaDt) * factor; result.DDeltaDt = (lowResult.DDeltaDt - highResult.DDeltaDt) * factor; } } else if (trade.BinaryOptionPayoffType == BinaryOptionPayoffType.AssetOrNothing) { var binaryCfOption = new BinaryOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, trade.Strike, trade.UnderlyingProductType, BinaryOptionPayoffType.CashOrNothing, 1.0, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates); var binaryResult = Calculate(binaryCfOption, market, request); var vanillaOption = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, trade.Strike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional); var engine = new AnalyticalVanillaEuropeanOptionEngine(); var vanillaResult = engine.Calculate(vanillaOption, market, request); var sign = trade.OptionType == OptionType.Call ? 1.0 : -1.0; if (result.IsRequested(PricingRequest.Pv)) { result.Pv = sign * vanillaResult.Pv + trade.Strike * binaryResult.Pv; } if (AnalyticalOptionPricerUtil.isBasicPricing(result)) { result.Delta = sign * vanillaResult.Delta + trade.Strike * binaryResult.Delta; result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First(); result.Gamma = sign * vanillaResult.Gamma + trade.Strike * binaryResult.Gamma; result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100; result.Vega = sign * vanillaResult.Vega + trade.Strike * binaryResult.Vega; result.Rho = sign * vanillaResult.Rho + trade.Strike * binaryResult.Rho; result.Theta = sign * vanillaResult.Theta + trade.Strike * binaryResult.Theta; } if (AnalyticalOptionPricerUtil.isHighOrderPricing(result)) { result.DDeltaDvol = sign * vanillaResult.DDeltaDvol + trade.Strike * binaryResult.DDeltaDvol; result.DVegaDvol = sign * vanillaResult.DVegaDvol + trade.Strike * binaryResult.DVegaDvol; result.DVegaDt = sign * vanillaResult.DVegaDt + trade.Strike * binaryResult.DVegaDt; result.DDeltaDt = sign * vanillaResult.DDeltaDt + trade.Strike * binaryResult.DDeltaDt; } } return(result); }
public override IPricingResult Calculate(AsianOption trade, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); var exerciseDate = trade.ExerciseDates.Last(); var remainingObsDates = trade.ObservationDates.Where(x => x > market.ValuationDate).ToArray(); var n = trade.ObservationDates.Count(); var n2 = remainingObsDates.Count(); var m = n - n2; if (trade.Fixings.Count != m) { throw new PricingLibraryException("AsianOption: number of fixings does not match!"); } var fixingAverage = trade.Fixings.Any() ? trade.Fixings.Average(x => x.Value) : 0.0; if (!remainingObsDates.Any()) { //already fix on all observation days var cfs = trade.GetPayoff(new[] { fixingAverage }); result.Pv = cfs.Sum(x => x.PaymentAmount * market.DiscountCurve.Value.GetDf(market.ValuationDate, x.PaymentDate)); result.Delta = 0.0; result.DeltaCash = 0.0; result.Gamma = 0.0; result.GammaCash = 0.0; result.Vega = 0.0; result.Theta = 0.0; result.Rho = 0.0; return(result); } //TODO: do it properly var newSpot = market.SpotPrices.Value.Values.First(); var sigma = market.VolSurfaces.Value.Values.First().GetValue(exerciseDate, trade.Strike, newSpot); var newSigma = market.VolSurfaces.Value.Values.First().GetValue(exerciseDate, trade.Strike, newSpot); double newStrike; var factor = 1.0; if (remainingObsDates.Count() == 1) { newStrike = trade.ObservationDates.Count() * trade.Strike - (n - 1) * trade.Fixings.Average(x => x.Value); factor = 1.0 / n; } else { var T = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade); var T2 = AnalyticalOptionPricerUtil.timeToMaturityFraction(remainingObsDates[0], remainingObsDates.Last(), trade); var t1 = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, remainingObsDates[0], trade); var h = T2 / (n2 - 1); var S = market.SpotPrices.Value.Values.First(); var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate); var dividendRate = market.DividendCurves.Value.Values.First().ZeroRate(market.ValuationDate, exerciseDate); var b = riskFreeRate - dividendRate; var sigma2 = sigma * sigma; double eat, eat2; if (riskFreeRate.AlmostEqual(dividendRate)) { eat = market.SpotPrices.Value.Values.First(); eat2 = S * S * Math.Exp(sigma2 * t1) / n / n * ( (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h)) + 2.0 / (1 - Math.Exp(sigma2 * h)) * (n - (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h))) ); } else { var o = 2 * b + sigma2; eat = S / n2 * Math.Exp(b * t1) * (1 - Math.Exp(b * h * n2)) / (1 - Math.Exp(b * h)); eat2 = S * S * Math.Exp(o * t1) / n / n * ( (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h)) + 2.0 / (1 - Math.Exp((b + sigma2) * h)) * ((1 - Math.Exp(b * h * n)) / (1 - Math.Exp(b * h)) - (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h))) ); } newSpot = eat; newSigma = Math.Sqrt(Math.Log(eat2 / eat / eat) / T); newStrike = (n * trade.Strike - m * fixingAverage) / (n - m) - m / (n - m); factor = 1.0 * (n - m) / n; } var newTrade = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, newStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional, trade.SettlmentGap, trade.OptionPremiumPaymentDate, trade.OptionPremium); var newVol = market.VolSurfaces.Value.Values.First().BumpVolSurf(newSigma - sigma); var newMarket = market.UpdateCondition( new UpdateMktConditionPack <Dictionary <string, double> >(x => x.SpotPrices, new Dictionary <string, double> { { "", newSpot } }), new UpdateMktConditionPack <Dictionary <string, IVolSurface> >(x => x.VolSurfaces, new Dictionary <string, IVolSurface> { { "", newVol } }) ); var bsEngine = new AnalyticalVanillaEuropeanOptionEngine(); result = (PricingResult)bsEngine.Calculate(newTrade, newMarket, request); result.Pv *= factor; result.Delta *= factor; result.Gamma *= factor; result.Vega *= factor; result.Theta *= factor; result.Rho *= factor; return(result); }