using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity; using Qdp.Pricing.Library.Options.Products.Autocall.Snowball; using YLErp.BLL.Calculation; using YLErp.BLL.Calculation.Engine; using YLErp.Modules.CalculationModule; using YLErp.Modules.TradeModule; using YLErp.QdpModule; namespace YLErp.Modules.CalcModules { /// /// 雪球期权计算测试 /// [TestClass] public class SnowballOptionCalcTest : UnitTestBase { [TestMethod("雪球期权-行权价和执行价近似相等时计算非常慢")] public void SnowballOptionCalcTest1() { var data = DeserializeFormData("TradeJson\\SnowballTrade1.txt"); Assert.IsTrue(data.trades != null && data.trades.Any()); var tdfull = data.trades.First(); var tdconv = TradeConverter.ConvertOptionTrade(tdfull); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); //为解决慢的问题,TradeRiskCalcUtil类加了优化处理方法:OptimizeSpotPrice var result = OptionCalculatorV2.GetOptionValueResult(new DateTime(2021, 5, 12), tdconv, new OptionValueCalcRequest(0.04) { spotPrices = new[] { 6512.0501 }, vols = new[] { 0.18 }, pricingRequest = QdpModule.QdpPricingRequest.BASIC_GREEKS }, out _); sw.Stop(); Console.WriteLine($"耗时{sw.ElapsedMilliseconds / 1000}秒,pv:{result.Pv}"); Assert.IsTrue(sw.ElapsedMilliseconds < 10 * 1000); } [TestMethod("雪球期权计算--海通认为算的不对")] public void SnowballOptionCalcTest2() { var json = ReadResourceFile("TradeJson\\SnowballTrade2.json"); var td = JsonHelper.Deserialize(json); Assert.IsNotNull(td); var result = OptionCalculatorV2.GetOptionValueResult(new DateTime(2021, 5, 28), td, new OptionValueCalcRequest(0) { spotPrices = new[] { 13660d }, vols = new[] { 0.254561403508772 } }, out _); Assert.IsTrue(Math.Abs(Math.Abs(result.Pv) - 213772.8) < 10); } [TestMethod("雪球期权计算--和Excel模板算的不一致")] public void SnowballOptionCalcTest3() { var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(new SnowballOptionTradeParam { annualizedFactor = 1, annualizedOptionPayoff = true, annualizedPremiumRate = null, barrierStatus = "", buysell = "Buy", callput = Qdp.Pricing.Base.Enums.OptionType.Put, coupon = 0.3149, couponDayCount = "Act365", couponPaymentDateStr = "2022-04-06,2022-05-05,2022-06-06,2022-07-04", dividendRate = 0.015, dividends = null, endDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4), exerciseDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4), exerciseType = null, hasNightMarket = false, initialSpotPrice = 100, isAnnualized = false, isFixedCoupon = false, isForwardTrade = false, isMoneynessOption = false, kiBarrier = 120, kiOptionType = Qdp.Pricing.Base.Enums.OptionType.CallSpread, koBarrier = 100, koBarrierAdjustStep = 0, koObservationDateStr = "2022-04-06,2022-05-05,2022-06-06,2022-07-04", koOptionType = Qdp.Pricing.Base.Enums.OptionType.Coupon, koRebate = 0.3149, koStrike = -1, notional = 1, observationDateStr = null, optionType = Qdp.Pricing.Base.Enums.OptionType.Put, participationRate = 1, preciseTimeMode = false, principalRate = 0, riskFreeRate = 0.015, settlementDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4), spreadStrikeAtKO = -1, spreadStrikeAtMaturity = 100, startDate = new Qdp.Foundation.Implementations.Date(2022, 3, 4), strike = 120, timeToMaturityDays = double.NaN, tradeDate = new Qdp.Foundation.Implementations.Date(2022, 3, 4), tradeId = "111111", underlyingInstrumentType = "Stock", underlyingTickers = new[] { "000001.sz" }, useOptionPayoffAtKO = false, useOptionPayoffAtMaturity = true, volSurfaceNames = new[] { "2222" } }, SnowBallOptionMode.SimpleSnowball); var option = optionTrade.Instrument as SimpleSnowball; var factory = OptionEngineFactory.GetEngineFactory("SnowBall"); var engine = factory.GetEngine(null, option.Exercise); var tenors = new string[] { "1D", "2M", "1Y" }; var strikes = new double[] { 0.95, 1.0, 1.05, }; var vols = new double[3, 3]; var singleVols = new List(); for (var i = 0; i < vols.GetLength(0); ++i) { for (var j = 0; j < vols.GetLength(1); ++j) { vols[i, j] = 0.2; singleVols.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.44 }); } } using var mp = new MarketProxy(new DateTime(2022, 3, 4), 0.015); mp.SetVolSurface("2222", new VolatilityImpl { VolTable = singleVols }); mp.SetStockPrice("000001.sz", 100); var _dividendCurveName = Guid.NewGuid().ToString(); var dividendCurve = CalculatorHelper.CreateConstantRiskFreeCurve(_dividendCurveName, 0.015); mp.SetYieldCurve(_dividendCurveName, dividendCurve); var pps = new OptionValuationParameters(_dividendCurveName, _dividendCurveName, "2222", "000001.sz"); var results = optionTrade.CalculateRisks(mp.QdpMarket, Qdp.Pricing.Base.Implementations.PricingRequest.Pv , engine, pps); Assert.IsTrue(Math.Abs(results.Pv) > 1); } } }