Ejemplo n.º 1
0
        public override IEngine <ConvertibleBond> GenerateEngine()
        {
            var optionInfo = TradeInfo.ConversionOption;
            var exercise   = optionInfo.Exercise.ToOptionExercise();
            IEngine <VanillaOption> optionEngine = null;

            if (exercise == OptionExercise.European)
            {
                //不该用MonteCarlo 直接判断 逻辑更合理
                if (optionInfo.MonteCarlo)
                {
                    optionEngine = new GenericMonteCarloEngine(optionInfo.ParallelDegree ?? 2, optionInfo.NSimulations ?? 50000);
                    return(new SimpleConvertibleBondEngine <GenericMonteCarloEngine>(optionEngine as GenericMonteCarloEngine));
                }
                else
                {
                    optionEngine = new AnalyticalVanillaEuropeanOptionEngine();
                    return(new SimpleConvertibleBondEngine <AnalyticalVanillaEuropeanOptionEngine>(optionEngine as AnalyticalVanillaEuropeanOptionEngine));
                }
            }
            else if (exercise == OptionExercise.American)
            {
                optionEngine = new BinomialTreeAmericanEngine(BinomialTreeType.CoxRossRubinstein, 100);
                return(new SimpleConvertibleBondEngine <BinomialTreeAmericanEngine>(optionEngine as BinomialTreeAmericanEngine));
            }
            else
            {
                throw new PricingBaseException("Conversion option exercise type should be European or American!");
            }
        }
Ejemplo n.º 2
0
        private void CommodityLookbackVanillaComparison(String ValuationDate = "2015-03-19", Double vol = 0.28, Double spot = 240, Double strike = 240,
                                                        Boolean isCall       = true, Boolean isFixed    = true)
        {
            var valuationDate = DateFromStr(ValuationDate);
            var maturityDate  = new Term("176D").Next(valuationDate);
            var calendar      = CalendarImpl.Get("chn");
            var obsDates      = new[] { new Date(2015, 4, 2), new Date(2015, 5, 4), new Date(2015, 6, 2), new Date(2015, 7, 2), new Date(2015, 8, 3), new Date(2015, 9, 2) };

            var option = new LookbackOption(
                valuationDate,
                maturityDate,
                OptionExercise.European,
                isCall ? OptionType.Call : OptionType.Put,
                isFixed ? StrikeStyle.Fixed : StrikeStyle.Floating,
                strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { maturityDate },
                obsDates,
                new Dictionary <Date, double>(),
                notional: 1
                );

            var vanilla = new VanillaOption(
                valuationDate,
                maturityDate,
                OptionExercise.European,
                isCall ? OptionType.Call : OptionType.Put,
                strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { maturityDate },
                obsDates,
                notional: 1
                );
            var market1 = TestMarket(referenceDate: ValuationDate, vol: vol, spot: spot);
            var market2 = TestMarket(referenceDate: ValuationDate, vol: vol * 0.8, spot: spot);

            var analyticalEngine = new AnalyticalLookbackOptionEngine();
            var vanillaEngine    = new AnalyticalVanillaEuropeanOptionEngine();
            var analyticalResult = analyticalEngine.Calculate(option, market1, PricingRequest.All);
            var vanillaResult    = vanillaEngine.Calculate(vanilla, market1, PricingRequest.All);
            var volResult        = analyticalEngine.Calculate(option, market2, PricingRequest.All);

            //Floating Lookback Option >= ATM vanilla
            //High volatility Floating >= Low volatility Floating
            Assert.AreEqual(analyticalResult.Pv >= vanillaResult.Pv, true);
            Assert.AreEqual(analyticalResult.Pv >= volResult.Pv, true);
        }
Ejemplo n.º 3
0
        public void TestConvertibleBond_BSPricer()
        {
            var convertibleBond = GeliCB(American: false);
            var optionEngine    = new AnalyticalVanillaEuropeanOptionEngine();
            var engine          = new SimpleConvertibleBondEngine <AnalyticalVanillaEuropeanOptionEngine>(optionEngine as AnalyticalVanillaEuropeanOptionEngine);
            var market          = TestMarket_Jin("2017-10-25", spot: 6.14);
            var result          = engine.Calculate(convertibleBond, market, PricingRequest.All);
            var optionPrem      = market.MktQuote.Value[convertibleBond.Bond.Id].Item2 - result.Pv;

            Assert.AreEqual(convertibleBond.ConversionRatio * 1.634147761, optionPrem, 1e-7);
        }
Ejemplo n.º 4
0
        public void TestConvertibleBond_14BaoGangE_BSPricer_NoFailure()
        {
            var convertibleBond = BaoGangCB();
            var optionEngine    = new AnalyticalVanillaEuropeanOptionEngine();
            var engine          = new SimpleConvertibleBondEngine <AnalyticalVanillaEuropeanOptionEngine>(optionEngine as AnalyticalVanillaEuropeanOptionEngine);
            var market          = TestMarket_Jin("2017-10-24", spot: 58.6800, CBprice: 141.97);
            var result          = engine.Calculate(convertibleBond, market, PricingRequest.All);
            var optionPrem      = market.MktQuote.Value[convertibleBond.Bond.Id].Item2 - result.Pv;

            Assert.AreEqual(convertibleBond.ConversionRatio * 16.74444583, optionPrem, 1e-7);
        }
        private void ResetStrikeOptionParityCalc(String ValuationDate = "2017-12-20", Double vol = 0.28, Double spot = 2.0, Double strike = 1.03, Boolean isCall = true, Boolean isPercentage = true)
        {
            var valuationDate    = DateFromStr(ValuationDate);
            var strikefixingDate = valuationDate;
            var exerciseDate     = new Term("176D").Next(valuationDate);
            var calendar         = CalendarImpl.Get("chn");


            var option1 = new ResetStrikeOption(
                valuationDate,
                exerciseDate,
                OptionExercise.European,
                isCall ? OptionType.Call : OptionType.Put,
                isPercentage ? ResetStrikeType.PercentagePayoff : ResetStrikeType.NormalPayoff,
                strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { exerciseDate },
                new[] { exerciseDate },
                strikefixingDate
                );

            var option2 = new VanillaOption(
                valuationDate,
                exerciseDate,
                OptionExercise.European,
                isCall ? OptionType.Call : OptionType.Put,
                strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { exerciseDate },
                new[] { exerciseDate }
                );
            var market = TestMarket(referenceDate: ValuationDate, vol: vol, spot: spot);

            var engine        = new AnalyticalResetStrikeOptionEngine();
            var result        = engine.Calculate(option1, market, PricingRequest.All);
            var engineVanilla = new AnalyticalVanillaEuropeanOptionEngine();
            var resultVanilla = engineVanilla.Calculate(option2, market, PricingRequest.All);

            var result1 = (isPercentage) ? result.Pv * strike : result.Pv;

            Assert.AreEqual(result1, resultVanilla.Pv, 1e-8);
        }
Ejemplo n.º 6
0
        private void BsOptionTest(String expiryStr, String firstDayStr, Double strike = 7.24, Double spot = 6.14, Double thirdPartyPrice = 20.0, String valueDay = "2017-10-25")
        {
            Date expiry = DateFromStr(expiryStr);
            Date firstConversionDate = DateFromStr(firstDayStr);
            var  option      = CreateOption(strike: strike, expiry: expiry, firstConversionDate: firstConversionDate, American: false);
            var  engine      = new AnalyticalVanillaEuropeanOptionEngine();
            var  market      = TestMarket_Jin(valueDay, spot: spot);
            var  result      = engine.Calculate(option, market, PricingRequest.All);
            var  premiumPart = result.Pv * 100.0 / strike;

            Console.WriteLine("YieldChain premium: {0}, wind: {1}", premiumPart, thirdPartyPrice);
            var diff = Math.Abs(premiumPart - thirdPartyPrice) / thirdPartyPrice * 100;

            //Assert.AreEqual(premiumPart, expected);
            Assert.AreEqual(true, diff < 0.3);  // < 0.3%
        }
Ejemplo n.º 7
0
        public void TestVanillaEuropeanCallMc()
        {
            var startDate    = new Date(2014, 03, 18);
            var maturityDate = new Date(2015, 03, 18);
            var market       = TestMarket();

            var call = new VanillaOption(startDate,
                                         maturityDate,
                                         OptionExercise.European,
                                         OptionType.Call,
                                         1.0,
                                         InstrumentType.Stock,
                                         CalendarImpl.Get("chn"),
                                         new Act365(),
                                         CurrencyCode.CNY,
                                         CurrencyCode.CNY,
                                         new[] { maturityDate },
                                         new[] { maturityDate });

            var mcengine = new GenericMonteCarloEngine(2, 200000);
            var result   = mcengine.Calculate(call, market, PricingRequest.All);

            var analyticalResult = new AnalyticalVanillaEuropeanOptionEngine().Calculate(call, market, PricingRequest.All);

            Console.WriteLine("{0},{1}", analyticalResult.Pv, result.Pv);
            Console.WriteLine("{0},{1}", analyticalResult.Delta, result.Delta);
            Console.WriteLine("{0},{1}", analyticalResult.Gamma, result.Gamma);
            Console.WriteLine("{0},{1}", analyticalResult.Vega, result.Vega);
            Console.WriteLine("{0},{1}", analyticalResult.Rho, result.Rho);
            Console.WriteLine("{0},{1}", analyticalResult.Theta, result.Theta);
            Assert.AreEqual(analyticalResult.Pv, result.Pv, 0.002);
            Assert.AreEqual(analyticalResult.Delta, result.Delta, 0.02);
            Assert.AreEqual(analyticalResult.Gamma, result.Gamma, 0.05);
            Assert.AreEqual(analyticalResult.Theta, result.Theta, 1e-5);
            Assert.AreEqual(analyticalResult.Rho, result.Rho, 1e-6);
            Assert.AreEqual(analyticalResult.Vega, result.Vega, 1e-4);
        }
Ejemplo n.º 8
0
        private void SpreadVanillaCalc(string spreadType = "TwoAssetsSpread", string ValuationDate = "2017-12-26",
                                       double spot1      = 4500, double spot2 = 2500, double strike = 2000, double vol1 = 0.5, double vol2 = 0.5, double rho12 = 0.5)
        {
            var valuationDate = DateFromStr(ValuationDate);
            var maturityDate  = new Term("176D").Next(valuationDate);
            var calendar      = CalendarImpl.Get("chn");

            var asset1 = "asset1";
            var asset2 = "asset2";
            var asset3 = "asset3";
            var asset4 = "asset4";

            var option = new SpreadOption(
                startDate: valuationDate,
                maturityDate: maturityDate,
                exercise: OptionExercise.European,
                optionType: OptionType.Call,
                spreadType: ToSpreadType(spreadType),
                strike: strike,
                weights: new double[] { 1.0, 1.0, 1.0, 1.0 },
                underlyingInstrumentType: InstrumentType.EquityIndex,
                calendar: calendar,
                dayCount: new Act365(),
                payoffCcy: CurrencyCode.CNY,
                settlementCcy: CurrencyCode.CNY,
                exerciseDates: new[] { maturityDate },
                observationDates: new[] { maturityDate },
                underlyingTickers: new[] { asset1, asset2, asset3, asset4 }
                )
            {
                UnderlyingTickers = new string[] { asset1, asset2, asset3, asset4 }
            };

            var option1 = new VanillaOption(
                valuationDate,
                maturityDate,
                OptionExercise.European,
                OptionType.Call,
                2.0 * strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { maturityDate },
                new[] { maturityDate }
                );

            var option2 = new VanillaOption(
                valuationDate,
                maturityDate,
                OptionExercise.European,
                OptionType.Put,
                strike,
                InstrumentType.EquityIndex,
                calendar,
                new Act365(),
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { maturityDate },
                new[] { maturityDate }
                );

            var market = TestMarket(referenceDate: ValuationDate, vol1: vol1, vol2: vol2, vol3: 0.0, spot1: spot1, spot2: spot2, spot3: 0.0,
                                    asset1: asset1, asset2: asset2, asset3: asset3, asset4: asset4, rho12: rho12, rho23: 0.0, rho13: 0.0);
            var market1 = GetMarket(referenceDate: ValuationDate, vol: vol1, spot: spot1);
            var market2 = GetMarket(referenceDate: ValuationDate, vol: vol2, spot: spot2);

            var analyticalEngine  = new AnalyticalSpreadOptionKirkEngine();
            var analyticalEngine2 = new AnalyticalVanillaEuropeanOptionEngine();
            var result            = analyticalEngine.Calculate(option, market, PricingRequest.All);
            var result1           = analyticalEngine2.Calculate(option1, market1, PricingRequest.All);
            var result2           = analyticalEngine2.Calculate(option2, market2, PricingRequest.All);

            Assert.AreEqual(true, result1.Pv + result2.Pv - result.Pv > 0);
        }
Ejemplo n.º 9
0
        public void BasicVanillaOptionTest()
        {
            var startDate    = new Date(2014, 03, 18);
            var maturityDate = new Date(2015, 03, 18);
            var valueDate    = new Date(2014, 03, 18);

            #region Prepare Market
            // build discount curve and dividend curve
            var fr007CurveName      = "Fr007";
            var fr007RateDefinition = new[]
            {
                new RateMktData("1D", 0.06, "Spot", "None", fr007CurveName),
                new RateMktData("5Y", 0.06, "Spot", "None", fr007CurveName),
            };

            var dividendCurveName      = "Dividend";
            var dividendRateDefinition = new[]
            {
                new RateMktData("1D", 0.03, "Spot", "None", dividendCurveName),
                new RateMktData("5Y", 0.03, "Spot", "None", dividendCurveName),
            };

            var discountCurve = new YieldCurve(
                name: fr007CurveName,
                referenceDate: valueDate,
                keyPoints: fr007RateDefinition.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(),
                bda: BusinessDayConvention.ModifiedFollowing,
                dayCount: new Act365(),
                calendar: CalendarImpl.Get("Chn"),
                currency: CurrencyCode.CNY,
                compound: Compound.Continuous,
                interpolation: Interpolation.CubicHermiteMonotic,
                trait: YieldCurveTrait.SpotCurve);

            var dividendCurve = new YieldCurve(
                name: dividendCurveName,
                referenceDate: valueDate,
                keyPoints: dividendRateDefinition.Select(x => Tuple.Create((ITerm) new Term(x.Tenor), x.Rate)).ToArray(),
                bda: BusinessDayConvention.ModifiedFollowing,
                dayCount: new Act365(),
                calendar: CalendarImpl.Get("Chn"),
                currency: CurrencyCode.CNY,
                compound: Compound.Continuous,
                interpolation: Interpolation.CubicHermiteMonotic,
                trait: YieldCurveTrait.SpotCurve);


            // build vol surface
            var volSurfData = new VolSurfMktData("VolSurf", 0.25);
            var volSurface  = volSurfData.ToImpliedVolSurface(
                valuationDate: valueDate,
                dc: "Act365");

            // construct market
            var market = new MarketCondition(
                x => x.ValuationDate.Value  = valueDate,
                x => x.DiscountCurve.Value  = discountCurve,
                x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> {
                { "", dividendCurve }
            },
                x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> {
                { "", volSurface }
            },
                x => x.SpotPrices.Value = new Dictionary <string, double> {
                { "", 1.0 }
            }
                );

            #endregion

            // construct a put option
            var put = new VanillaOption(startDate,
                                        maturityDate,
                                        OptionExercise.European,
                                        OptionType.Put,
                                        1.0,
                                        InstrumentType.Stock,
                                        CalendarImpl.Get("chn"),
                                        new Act365(),
                                        CurrencyCode.CNY,
                                        CurrencyCode.CNY,
                                        new[] { maturityDate },
                                        new[] { maturityDate });

            var engine = new AnalyticalVanillaEuropeanOptionEngine();

            var result = engine.Calculate(put, market, PricingRequest.All);
        }
Ejemplo n.º 10
0
        public void MoneynessDeltaTest()
        {
            var startDate    = new Date(2018, 03, 02);
            var maturityDate = new Date(2018, 04, 27);

            var call = new VanillaOption(startDate,
                                         maturityDate,
                                         OptionExercise.American,
                                         OptionType.Call,
                                         1.05,
                                         InstrumentType.Stock,
                                         CalendarImpl.Get("chn"),
                                         new Act365(),
                                         CurrencyCode.CNY,
                                         CurrencyCode.CNY,
                                         new[] { maturityDate },
                                         new[] { maturityDate },
                                         12,
                                         null,
                                         null,
                                         0,
                                         true,
                                         8000);

            #region construct market
            var historiclIndexRates = HistoricalDataLoadHelper.HistoricalIndexRates;
            var curveConvention     = new CurveConvention("fr007CurveConvention",
                                                          "CNY",
                                                          "ModifiedFollowing",
                                                          "Chn",
                                                          "Act365",
                                                          "Continuous",
                                                          "CubicHermiteMonotic");

            var fr007CurveName      = "Fr007";
            var fr007RateDefinition = new[]
            {
                new RateMktData("1D", 0.05, "Spot", "None", fr007CurveName),
                new RateMktData("5Y", 0.05, "Spot", "None", fr007CurveName),
            };

            var dividendCurveName      = "Dividend";
            var dividendRateDefinition = new[]
            {
                new RateMktData("1D", 0, "Spot", "None", dividendCurveName),
                new RateMktData("5Y", 0, "Spot", "None", dividendCurveName),
            };

            var curveDefinition = new[]
            {
                new InstrumentCurveDefinition(fr007CurveName, curveConvention, fr007RateDefinition, "SpotCurve"),
                new InstrumentCurveDefinition(dividendCurveName, curveConvention, dividendRateDefinition, "SpotCurve"),
            };

            var       volSurf    = new[] { new VolSurfMktData("VolSurf", 0.3), };
            var       marketInfo = new MarketInfo("tmpMarket", "2018-03-02", curveDefinition, historiclIndexRates, null, null, volSurf);
            QdpMarket qdpMarket;
            MarketFunctions.BuildMarket(marketInfo, out qdpMarket);

            var valuationDate = new Date(2018, 3, 2);

            //flat vol surface

            var surface1 = qdpMarket.GetData <VolSurfMktData>("VolSurf").ToImpliedVolSurface(valuationDate);
            // market with flat vol surface
            var market = new MarketCondition(
                x => x.ValuationDate.Value  = valuationDate,
                x => x.DiscountCurve.Value  = qdpMarket.GetData <CurveData>("Fr007").YieldCurve,
                x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> {
                { "", qdpMarket.GetData <CurveData>("Dividend").YieldCurve }
            },
                x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> {
                { "", surface1 }
            },
                x => x.SpotPrices.Value = new Dictionary <string, double> {
                { "", 8000 }
            }
                );

            //a real vol surface, same as stock 600000 of 2018-03-02 in OTC system
            var maturities = new Date[]
            {
                (new Term("1W")).Next(startDate),
                (new Term("2W")).Next(startDate),
                (new Term("1M")).Next(startDate)
            };

            var strikes = new double[]
            {
                0.9,
                0.95,
                1.0,
                1.05,
                1.1
            };

            var vols = new double[3, 5];
            for (var i = 0; i < vols.GetLength(0); ++i)
            {
                for (var j = 0; j < vols.GetLength(1); ++j)
                {
                    vols[i, j] = 0.3;
                }
            }

            vols[2, 2] = 0.4;


            var surface2 = new ImpliedVolSurface(valuationDate, maturities, strikes, vols, Interpolation2D.BiLinear);
            // market with flat vol surface
            var market2 = new MarketCondition(
                x => x.ValuationDate.Value  = valuationDate,
                x => x.DiscountCurve.Value  = qdpMarket.GetData <CurveData>("Fr007").YieldCurve,
                x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> {
                { "", qdpMarket.GetData <CurveData>("Dividend").YieldCurve }
            },
                x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> {
                { "", surface2 }
            },
                x => x.SpotPrices.Value = new Dictionary <string, double> {
                { "", 8000 }
            }
                );
            #endregion

            var engine = new AnalyticalVanillaEuropeanOptionEngine();

            //result of a flat vol surface of 0.3, which is the same as pricing result in OTC-926
            var result = engine.Calculate(call, market, PricingRequest.All);

            //result of real vol surface, which is the same as scenario analysis in OTC-926
            var result2 = engine.Calculate(call, market2, PricingRequest.All);
        }
Ejemplo n.º 11
0
        public void TestVanillaEuropeanOption()
        {
            var startDate    = new Date(2014, 03, 18);
            var maturityDate = new Date(2015, 03, 18);
            var market       = TestMarket();

            var call = new VanillaOption(startDate,
                                         maturityDate,
                                         OptionExercise.European,
                                         OptionType.Call,
                                         1.0,
                                         InstrumentType.Stock,
                                         CalendarImpl.Get("chn"),
                                         new Act365(),
                                         CurrencyCode.CNY,
                                         CurrencyCode.CNY,
                                         new[] { maturityDate },
                                         new[] { maturityDate });

            var callResults = new[]
            {
                0.11013078647539261,   //0.1101307865, //pv
                0.58659840197749225,   //0.579209648680634, //delta
                1.5026934848982876,    //1.50252233849235, //gamma
                -0.000158271113220379, //-0.000158271113220421, //theta
                4.69520215692007E-05,  //0.00004690554, //rho
                0.00375699094019481,   //0.00375690062860851 //vega
                0.25,                  // vol
            };

            var put = new VanillaOption(startDate,
                                        maturityDate,
                                        OptionExercise.European,
                                        OptionType.Put,
                                        1.0,
                                        InstrumentType.Stock,
                                        CalendarImpl.Get("chn"),
                                        new Act365(),
                                        CurrencyCode.CNY,
                                        CurrencyCode.CNY,
                                        new[] { maturityDate },
                                        new[] { maturityDate });
            var putResults = new[]
            {
                0.081449786511133465,    //0.0814497865, //pv
                -0.38384713157104261,    //-0.391235884868724, //delta
                1.5026934848963447,      //1.50252235237014, //gamma
                -8.3213704703308244E-05, //-0.000083213704702975, //theta
                -4.7177359254735321E-05, //-0.000047266234126, //rho
                0.00375699094019481,     //0.00375690062860852 //vega
                0.25,                    // vol
            };

            var engine          = new AnalyticalVanillaEuropeanOptionEngine();
            var result          = engine.Calculate(call, market, PricingRequest.All);
            var callCalcResults = new[]
            {
                result.Pv,
                result.Delta,
                result.Gamma,
                result.Theta,
                result.Rho,
                result.Vega,
                result.PricingVol
            };

            for (var i = 0; i < callCalcResults.Length; ++i)
            {
                Assert.AreEqual(callResults[i], callCalcResults[i], 1e-10);
            }

            result = engine.Calculate(put, market, PricingRequest.All);
            var putCalcResults = new[]
            {
                result.Pv,
                result.Delta,
                result.Gamma,
                result.Theta,
                result.Rho,
                result.Vega,
                result.PricingVol
            };

            for (var i = 0; i < callCalcResults.Length; ++i)
            {
                Assert.AreEqual(putResults[i], putCalcResults[i], 1e-10);
            }
        }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Calibrate implied bs vol from spot premium of an european option
        /// </summary>
        /// <param name="premium"></param>
        /// <param name="isCall"></param>
        /// <param name="strike"></param>
        /// <param name="spot"></param>
        /// <param name="rate"></param>
        /// <param name="expiryDateStr"></param>
        /// <param name="valuationDateStr"></param>
        /// <param name="underlyingInstrumentType"></param>
        /// <param name="calendarStr"></param>
        /// <param name="dayCountStr"></param>
        /// <param name="commodityFuturesPreciseTimeMode"></param>
        /// <param name="hasNightMarket"></param>
        /// <returns>if succeed then return implied vol, if falied then return error message</returns>
        public static double xl_ImpliedVolFromPremium(double premium, bool isCall, double strike, double spot, double rate,
                                                      string expiryDateStr, string valuationDateStr, string underlyingInstrumentType, string calendarStr, string dayCountStr,
                                                      bool commodityFuturesPreciseTimeMode = false,
                                                      bool hasNightMarket = false)
        {
            var bsEngine       = new AnalyticalVanillaEuropeanOptionEngine();
            var expiryDate     = expiryDateStr.ToDate();
            var valuationDate  = valuationDateStr.ToDate();
            var instrumentType = underlyingInstrumentType.ToInstrumentType();
            var calendar       = calendarStr.ToCalendarImpl();
            var dayCount       = dayCountStr.ToDayCountImpl();

            var trade = new VanillaOption(
                valuationDate,
                expiryDate,
                OptionExercise.European,
                isCall ? OptionType.Call : OptionType.Put,
                strike,
                instrumentType,
                calendar,
                dayCount,
                CurrencyCode.CNY,
                CurrencyCode.CNY,
                new[] { expiryDate },
                new[] { expiryDate },
                notional: 1,
                hasNightMarket: hasNightMarket,
                commodityFuturesPreciseTimeMode: commodityFuturesPreciseTimeMode
                );

            var curve = new YieldCurve(
                "riskFreeRate",
                valuationDate,
                new[]
            {
                Tuple.Create((ITerm) new Term("1D"), rate),
                Tuple.Create((ITerm) new Term("1Y"), rate)
            },
                BusinessDayConvention.ModifiedFollowing,
                dayCount,
                calendar,
                CurrencyCode.CNY,
                Compound.Continuous,
                Interpolation.CubicHermiteMonotic,
                YieldCurveTrait.SpotCurve
                );
            var volSurf = new VolSurfMktData("VolSurf", 0.1).ToImpliedVolSurface(valuationDate);
            var market  = new MarketCondition(
                x => x.ValuationDate.Value  = valuationDate,
                x => x.DiscountCurve.Value  = curve,
                x => x.DividendCurves.Value = new Dictionary <string, IYieldCurve> {
                { "", curve }
            },                                                                                          //not used by futures option
                x => x.FixingCurve.Value   = curve,
                x => x.RiskfreeCurve.Value = curve,
                x => x.SpotPrices.Value    = new Dictionary <string, double> {
                { "", spot }
            },
                x => x.VolSurfaces.Value = new Dictionary <string, IVolSurface> {
                { "", volSurf }
            });                                                                                         //not used by this calibration

            return(bsEngine.ImpliedVolFromPremium(targetPremium: premium, option: trade, market: market));
        }
Ejemplo n.º 14
0
        private static ConvertibleBondAnalytics computeAnalytics(IMarketCondition market, ConvertibleBond cb, double putRedemptionPrice)
        {
            //analytics part
            var cbSpot              = market.MktQuote.Value[cb.Bond.Id].Item2;
            var stockPrice          = market.SpotPrices.Value.Values.First();
            var conversionValue     = stockPrice * cb.ConversionRatio;
            var premiumToShareInPct = (cbSpot / conversionValue - 1) * 100; // in Pct
            var arbitragePL         = conversionValue - cbSpot;             //buy cb, sell stock
            var timeToMaturity      = (cb.UnderlyingMaturityDate - market.ValuationDate) / 365.0;

            //bond analytics
            var    bondengine         = new BondEngine();
            var    yieldToMaturity    = bondengine.Calculate(cb.Bond, market, PricingRequest.Ytm).Ytm * 100.0;
            var    bondFloor          = bondengine.Calculate(cb.Bond, market, PricingRequest.Pv).Pv;
            double premiumToBondInPct = (cbSpot / bondFloor - 1) * 100;  //in Pct

            //parity vs bond floor premium
            var parityFloorPremiumInPct = (conversionValue / bondFloor - 1) * 100.0;


            //option analytics
            var impliedOptionValue       = cbSpot - bondFloor;
            var impliedUnitOptionPremium = impliedOptionValue / cb.ConversionRatio;

            var option     = createOption(strike: cb.ConversionOption.Strike, expiry: cb.ConversionOption.UnderlyingMaturityDate, firstConversionDate: cb.ConversionOption.StartDate, American: false);
            var engine     = new AnalyticalVanillaEuropeanOptionEngine();
            var impliedVol = engine.ImpliedVol(option, market, impliedUnitOptionPremium);


            //Note: assume simple calc here:  putPrice 103, current price 109.69, then if we can put the bond now, returnOnPut = (103 - 109.69)/109.69
            var returnOnPut = (putRedemptionPrice / cbSpot - 1.0) * 100;

            //cb style based on  parity/ bond floor relationship
            //if parity is worth 20% more than bond floor, then stock like
            //if parity is worth -20% less than bond floor, then bond like
            //otherwise,  cb is in balance mode
            var cbStatus = ConvertibleBondStatus.Balance;

            if (parityFloorPremiumInPct > 20)
            {
                cbStatus = ConvertibleBondStatus.StockLike;
            }
            else if (parityFloorPremiumInPct < -20)
            {
                cbStatus = ConvertibleBondStatus.BondLike;
            }

            return(new ConvertibleBondAnalytics(
                       conversionValue: conversionValue,
                       premiumToShareInPct: premiumToShareInPct,
                       arbitragePL: arbitragePL,
                       timeToMaturity: timeToMaturity,
                       yieldToMaturity: yieldToMaturity,
                       bondFloor: bondFloor,
                       premiumToBondInPct: premiumToBondInPct,
                       parityFloorPremiumInPct: parityFloorPremiumInPct,
                       optionValue: impliedOptionValue,
                       impliedVol: impliedVol,
                       returnOnPut: returnOnPut,
                       cbStatus: cbStatus));
        }