예제 #1
0
        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);
        }
예제 #2
0
        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);
        }