using Qdp.Foundation.Implementations; using Qdp.Pricing.Base.Enums; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Base.Interfaces; using Qdp.Pricing.Library.Options.MonteCarlo; using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix; using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix.Numerical; using YLErp.Modules.CalculationModule; using YLErp.QdpModule; namespace YLErp.Modules.CalcModules { /// /// 凤凰期权计算测试 /// [TestClass] public class AutocalllOptionCalcTest : UnitTestBase { [TestMethod("看跌凤凰")] public void SnowballOptionCalcTest1() { var ValueDate = new Date(2019, 11, 26); var maturityDate = new Date(2020, 2, 24); const double SPOT = 3899; const double NOTIONAL = 1000000.0 / SPOT; var tradeId = Guid.NewGuid().ToString(); var tdParam = new AutocallOptionTradeParam { annualizedFactor = 1, annualizedOptionPayoff = false, barrierStatus = null, buysell = null, callput = OptionType.Put, coupon = 0.05, couponBarrier = 1.05, couponDayCount = "Act365", couponPayAtMaturity = false, dividendRate = 0.01, dividends = null, endDate = maturityDate, exerciseDate = maturityDate, exerciseType = "European", happenedObservations = null, hasNightMarket = false, //includeCouponAfterKI = true, initialSpotPrice = SPOT, isAnnualized = false, isFixedCoupon = false, isForwardTrade = false, isMoneynessOption = true, kiBarrier = 1.05, kiOptionType = "Call", koBarrier = 0.8, koObservationDateStr = "", notional = NOTIONAL, observationDateStr = "", participationRate = 1, preciseTimeMode = false, principalRate = 0, riskFreeRate = 0.05, settlementDate = maturityDate, strike = 1, startDate = ValueDate, timeToMaturityDays = double.NaN, tradeDate = ValueDate, tradeId = tradeId, underlyingInstrumentType = ConsGlobal.InstrumentType.Stock, underlyingTickers = new[] { "AAA9999" }, volSurfaceNames = new[] { tradeId } }; using var market = new MarketProxy(ValueDate, 0.05); market.SetStockPrice("AAA9999", SPOT); market.SetVolSurface(tradeId, 0.2); var val = TradeRiskCalcUtil.GetAutocallOptionValue(market, new OptionCalcParam(tdParam) { CalcDeltaT1 = false, calcScenario = Enums.CalcScenarioEnum.Pricing, engineName = null, pricingRequest = PricingRequest.Pv, quadratureFastMode = false, spotPrices = new[] { SPOT } }); //Assert.IsTrue(Math.Abs(val.Pv / -32652.810546875 - 1) < 0.01); Assert.AreEqual((-32785 / val.Pv) - 1, 0, 1e-3); } [TestMethod("看跌凤凰")] public void TestPhoenixPriceOfDownAndOut() { var ValueDate = new Date(2019, 11, 26); var maturityDate = new Date(2020, 2, 24); var Calendar = CalendarImpl.Get("chn"); IDayCount DayCount = new Bus252(); var InstrumentType = Qdp.Pricing.Base.Enums.InstrumentType.Stock; const double VOL = 0.2; const double SPOT = 3899; const double RISK_FREE_RATE = 0.05; const double DIVIDEND_RATE = 0.01; const double NOTIONAL = 1000000.0 / SPOT; var market = QdpTestHelper.CreateMarket(ValueDate, VOL, SPOT, RISK_FREE_RATE, DIVIDEND_RATE); var newEngine = new QuadAutoCallEngine(); var mcEngine = new GbmMonteCarloEngine(1000000, 1e-3, 1e-6, 1); var option2 = new AutoCall( startDate: ValueDate, maturityDate: maturityDate, koBarrier: 0.8, kiBarrier: 1.05, couponBarrier: 1.05, coupon: 0.05, couponPayAtMaturity: false, includeCouponAfterKI: true, optionParticipationRate: 1.0, koObsDates: QdpTestHelper.GenerateObservationDates(Calendar, ValueDate, maturityDate, new Term("1M"), BusinessDayConvention.Following), kiObsDates: null, observationDates: QdpTestHelper.GenerateObservationDates(Calendar, ValueDate, maturityDate), notional: NOTIONAL, initialSpotPrice: SPOT, underlyingType: InstrumentType, calendar: Calendar, dayCount: DayCount, payoffCcy: CurrencyCode.CNY, settlementCcy: CurrencyCode.CNY, exerciseDates: new Date[] { maturityDate }, exercise: OptionExercise.European, optionType: OptionType.Put, barrierType: BarrierType.DownAndOut, strike: 1.0, spreadStrike: 1.1, annualizedOptionPayoff: false, isMoneynessOption: true, kiOptionType: OptionType.Call); var json = Newtonsoft.Json.JsonConvert.SerializeObject(option2); var mcPv2 = mcEngine.Calculate(option2, market, PricingRequest.Pv).Pv; Assert.IsTrue(Math.Abs((mcPv2 / -32652.810546875) - 1) < 0.01); var newPv2 = newEngine.Calculate(option2, market, PricingRequest.Pv).Pv; Assert.AreEqual((-32737.653776411829 / newPv2) - 1, 0, 1e-3); } } }