using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity; using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos.Options; using Qdp.Pricing.Base.Enums; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Base.Interfaces; using Qdp.Pricing.Library.Options.Products.Asian; using YLErp.BLL.Calculation.Engine; using YLErp.Modules.CalculationModule; using YLErp.QdpModule; namespace YLErp.Modules.CalcModules { /// /// 亚式期权计算测试 /// [TestClass] public class AisanOptionCalcTest : UnitTestBase { [TestMethod("亚式期权计算测试")] public void AisianOptionCalcTest1() { var param = new AsianOptionTradeParam { annualizedFactor = 1, averagingPeriodStartDate = new Qdp.Foundation.Implementations.Date(2022, 2, 28), buysell = "买入", callput = OptionType.Put, dividendRate = 0.03, dividends = null, endDate = new Qdp.Foundation.Implementations.Date(2022, 3, 28), exerciseDate = new Qdp.Foundation.Implementations.Date(2022, 3, 28), exerciseType = "European", fixings = "2022-02-28,17690.0;2022-03-01,17535.0;2022-03-02,17565.0;2022-03-03,17470.0;2022-03-04,17465.0;2022-03-07,17765.0;2022-03-08,17580.0;2022-03-09,17770.0;2022-03-10,18000.0;2022-03-11,17735.0;2022-03-14,17460.0;2022-03-15,16910.0", hasNightMarket = false, initialSpotPrice = 17375, isAnnualized = false, isForwardTrade = false, isMoneynessOption = false, notional = 50, observationDateStr = null, optionType = OptionType.Put, participationRate = 1, payoffType = "EnhancedArithmeticAverage", preciseTimeMode = false, principalRate = 0, riskFreeRate = 0.03, settlementDate = new Qdp.Foundation.Implementations.Date(2022, 3, 28), startDate = new Qdp.Foundation.Implementations.Date(2022, 2, 28), strike = 21610, strikeGearingFactor = 1, strikeStyle = "Fixed", timeToMaturityDays = double.NaN, tradeDate = new Qdp.Foundation.Implementations.Date(2022, 2, 28), tradeId = "11111", underlyingInstrumentType = ConsGlobal.InstrumentType.CommodityFutures, underlyingTickers = new[] { "ceshi_biaodi" }, volSurfaceNames = new[] { "ceshi_bodonglv" } }; var calcParam = new OptionCalcParam(param) { pricingRequest = PricingRequest.Pv | PricingRequest.Delta, calcScenario = Enums.CalcScenarioEnum.RealtimeRisk, spotPrices = new[] { 16910d } }; using var m = new MarketProxy(new DateTime(2022, 3, 15), 0.03); m.SetStockPrice("ceshi_biaodi", 16910d); var volatility = QdpVolHelper.GetDefaultVolatility(0.45); m.SetVolSurface("ceshi_bodonglv", volatility); var result = GetAsianOptionValue(m, calcParam, out var optionTrade1); Console.WriteLine($"{result.Pv} -- {result.Delta}"); m.SetStockPrice("ceshi_biaodi", 16900d); var result2 = GetAsianOptionValue(m, calcParam, out var optionTrade2); Console.WriteLine($"{result2.Pv} -- {result2.Delta}"); Assert.AreEqual(Math.Abs(result2.Pv - result.Pv), Math.Abs(result.Delta) * 10, 0.01); param.fixings = "2022-02-28,17690.0;2022-03-01,17535.0;2022-03-02,17565.0;2022-03-03,17470.0;2022-03-04,17465.0;2022-03-07,17765.0;2022-03-08,17580.0;2022-03-09,17770.0;2022-03-10,18000.0;2022-03-11,17735.0;2022-03-14,17460.0;2022-03-15,16900.0";// var result3 = GetAsianOptionValue(m, calcParam, out var optionTrade3); Console.WriteLine($"{result3.Pv} -- {result3.Delta}"); Assert.AreEqual(Math.Abs(result3.Pv - result.Pv), Math.Abs(result.Delta) * 10, 0.01); } public static IPricingResult GetAsianOptionValue(MarketProxy marketProxy , OptionCalcParam calcParam , out AsianOptionTrade optionTrade) { optionTrade = QdpTradeBuilder.GetAsianOptionTrade(calcParam.TradeParam); var parameters = new OptionValuationParameters(marketProxy.DiscountCurveName ?? MarketProxy.ConstantZeroCurve, MarketProxy.ConstantZeroCurve, calcParam.volSurfaceNames[0], calcParam.underlyingTickers[0]); var option = optionTrade.Instrument as AsianOption; var factory = OptionEngineFactory.GetEngineFactory("AsianOption"); var engine = factory.GetEngine(calcParam.engineName, option.Exercise, calcParam.TradeParam.payoffType, option, calcParam.TradeParam.strikeStyle); var pricingRequest = calcParam.pricingRequest; if (option.AsianType == AsianType.EnhancedArithmeticAverage) { pricingRequest = QdpPricingRequest.UnionBaiscGreeks(calcParam.pricingRequest); } return optionTrade.CalculateRisks(marketProxy.QdpMarket, pricingRequest, engine, parameters); } [TestMethod("亚式期权计算测试2")] public void AisianOptionCalcTest2() { var startDate = new DateTime(2019, 7, 22); var endDate = startDate.AddMonths(9); var observationDateStr = new StringBuilder(3000); for (var dt = startDate; dt <= endDate; dt = dt.AddDays(1)) { observationDateStr.Append(dt.ToString("yyyy-MM-dd")).Append(','); } observationDateStr.Remove(observationDateStr.Length - 1, 1); var param = new AsianOptionTradeParam { annualizedFactor = 1, averagingPeriodStartDate = startDate, buysell = "买入", callput = OptionType.Call, dividendRate = 0.05, dividends = null, endDate = endDate, exerciseDate = endDate, exerciseType = "European", fixings = "2019-07-22,100", hasNightMarket = false, initialSpotPrice = 100, isAnnualized = false, isForwardTrade = false, isMoneynessOption = false, notional = 1, observationDateStr = null,//observationDateStr.ToString(), optionType = OptionType.Call, participationRate = 1, payoffType = "ArithmeticAverage", preciseTimeMode = false, principalRate = 0, riskFreeRate = 0.1, settlementDate = null, startDate = startDate, strike = 100, strikeGearingFactor = 1, strikeStyle = "Fixed", timeToMaturityDays = double.NaN, tradeDate = startDate, tradeId = "11111", underlyingInstrumentType = ConsGlobal.InstrumentType.Stock, underlyingTickers = new[] { "ceshi_biaodi" }, volSurfaceNames = new[] { "ceshi_bodonglv" } }; var calcParam = new OptionCalcParam(param) { pricingRequest = PricingRequest.Pv, calcScenario = Enums.CalcScenarioEnum.RealtimeRisk, spotPrices = new[] { 100d } }; using var m = new MarketProxy(startDate, 0.1); m.SetStockPrice("ceshi_biaodi", 100d); var volatility = QdpVolHelper.GetDefaultVolatility(0.15); m.SetVolSurface("ceshi_bodonglv", volatility); var result = GetAsianOptionValue(m, calcParam, out var optionTrade1); Console.WriteLine($"{result.Pv}"); } //国信金阳:API是 9.53 [TestMethod("(国信金阳)亚式期权计算测试")] public void AisianOptionCalcTestGuoXin() { var startDate = new Qdp.Foundation.Implementations.Date(2022, 8, 31); var exerciseDate = new Qdp.Foundation.Implementations.Date(2022, 9, 30); var valueDate = new DateTime(2022, 9, 6); var td = new trade { BuySell = "买入", AnnualizeFactor = 1, OptionType = "看跌", ExerciseMode = "European", StartDate = startDate, TradeDate = startDate, ExerciseDate = exerciseDate, SettlementDate = exerciseDate, Notional = 1, InitialSpotPrice = 23190, Strike = 23380, NoRiskRate = 0, DividendRate = 0, IsAnnualized = false, IsMoneynessOption = null, UnderlyingCode = "LH2301", UnderlyingInstrumentType = ConsGlobal.InstrumentType.CommodityFutures, TradeType = "亚式期权", trade_asian_option = new trade_asian_option { AveragingPeriodStartDate = new DateTime(2022, 9, 1), StrikeType = "Fixed", PayoffType = "EnhancedArithmeticAverage", Fixings = "2022-09-01,23285.0;2022-09-02,23025;2022-09-05,23380.0", StrikeGearingFactor = 1, ObservationDates = null, } }; var creq = new OptionValueCalcRequest(0) { calcDeltaT1 = false, calcScenario = Enums.CalcScenarioEnum.RealtimeRisk, correlations = null, engineName = null, fixings = td.trade_asian_option.Fixings, isEodCalc = false, maturityShift = 0, preciseTimeMode = false, quadratureFastMode = false, pricingRequest = PricingRequest.Pv | PricingRequest.Delta, spotPrices = new[] { 23190d }, timeToMaturityDays = double.NaN, vols = new[] { 0.25 } }; void outputResult(TradeValueResult mr) { var dlots = mr.Delta * 312 / 16; var tdays = mr.PricingT * 244; Console.WriteLine($"{tdays} -- {mr.Pv} -- {mr.Delta} -- {dlots}"); } var resultA1 = OptionCalculatorV2.GetOptionValueResult(valueDate, td, creq, out _); outputResult(resultA1); creq.timeToMaturityDays = 18; var result = OptionCalculatorV2.GetOptionValueResult(valueDate, td, creq, out _); outputResult(result); Assert.AreEqual(resultA1.Delta, result.Delta, 1e-4); } } }