using Qdp.Pricing.Base.Enums; using Qdp.Pricing.Base.Implementations; using YLErp.BLL.Calculation; using YLErp.BLL.Calculation.V2; using YLErp.BLL.Calculation.V2.Parameter; using YLErp.DBModels.Enums; using YLErp.Modules.CalculationModule; using YLErp.Modules.SkewMapVolModule; using YLErp.OldVersion; using YLErp.QdpModule; using YLErp.QdpModule.Constants; namespace YLErp.Modules.CalcModules { [TestClass] public class CalculationTest { [TestMethod] public void QuoteMaturityDateTest() { var maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 11, 15), "RB1911"); Assert.AreEqual(new DateTime(2019, 11, 15), maturity, "RB1911"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 12, 15), "RB1912"); Assert.AreEqual(new DateTime(2019, 12, 15), maturity, "RB1912"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 01, 15), "RB2001"); Assert.AreEqual(new DateTime(2020, 1, 15), maturity, "RB2001"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 02, 15), "RB2002"); Assert.AreEqual(new DateTime(2020, 2, 15), maturity, "RB2002"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 10, 20), "SC1911"); Assert.AreEqual(new DateTime(2019, 11, 20), maturity, "SC1911"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 11, 20), "SC1912"); Assert.AreEqual(new DateTime(2019, 12, 20), maturity, "SC1912"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 12, 20), "SC2001"); Assert.AreEqual(new DateTime(2020, 1, 20), maturity, "SC2001"); maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 1, 20), "SC2002"); Assert.AreEqual(new DateTime(2020, 2, 20), maturity, "SC2002"); } [TestMethod] public void CalendarTest() { var date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 15), 0); Assert.AreEqual(new DateTime(2018, 6, 15), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 15), 1); Assert.AreEqual(new DateTime(2018, 6, 19), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), 0); Assert.AreEqual(new DateTime(2018, 6, 19), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), 0); Assert.AreEqual(new DateTime(2018, 6, 19), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), 0); Assert.AreEqual(new DateTime(2018, 6, 19), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), 0); Assert.AreEqual(new DateTime(2018, 6, 19), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), 1); Assert.AreEqual(new DateTime(2018, 6, 20), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), 1); Assert.AreEqual(new DateTime(2018, 6, 20), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), 1); Assert.AreEqual(new DateTime(2018, 6, 20), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), 1); Assert.AreEqual(new DateTime(2018, 6, 20), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), -1); Assert.AreEqual(new DateTime(2018, 6, 15), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), -1); Assert.AreEqual(new DateTime(2018, 6, 15), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), -1); Assert.AreEqual(new DateTime(2018, 6, 15), date, ""); date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), -1); Assert.AreEqual(new DateTime(2018, 6, 15), date, ""); } [TestMethod] public void CalendarBLLTest() { var date20190705 = new DateTime(2019, 07, 05); var date20190706 = new DateTime(2019, 07, 06); var date20190707 = new DateTime(2019, 07, 07); var date20190708 = new DateTime(2019, 07, 08); #region IsHoliday Assert.IsFalse(QdpCalendarHelper.IsHoliday(date20190705)); Assert.IsTrue(QdpCalendarHelper.IsHoliday(date20190706)); Assert.IsTrue(QdpCalendarHelper.IsHoliday(date20190707)); Assert.IsFalse(QdpCalendarHelper.IsHoliday(date20190708)); #endregion #region GetWorkDayCount Assert.AreEqual(0, QdpCalendarHelper.GetWorkDayCount(date20190705, date20190705)); Assert.AreEqual(1, QdpCalendarHelper.GetWorkDayCount(date20190705, date20190708)); #endregion #region GetWorkingDay Assert.AreEqual(new DateTime(2019, 7, 10), QdpCalendarHelper.GetWorkingDay(date20190705, 3)); Assert.AreEqual(new DateTime(2019, 6, 28), QdpCalendarHelper.GetWorkingDay(date20190705, -5)); #endregion #region GetWrokingDatesBeforeDate var dates = QdpCalendarHelper.GetWorkingDatesBeforeDate(date20190708, 7); Assert.AreEqual(7, dates.Count); Assert.AreEqual(date20190708, dates[0]); Assert.AreEqual(new DateTime(2019, 6, 28), dates[6]); #endregion #region GetNonHolidayDaysBetween Assert.AreEqual(0, QdpCalendarHelper.GetNonHolidayDaysBetween(date20190705, date20190705)); Assert.AreEqual(1, QdpCalendarHelper.GetNonHolidayDaysBetween(date20190705, date20190708)); #endregion #region GetNonHoliday Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHoliday(date20190705)); Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHoliday(date20190706)); Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHoliday(date20190707)); #endregion #region GetNonHolidayBefore Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190705)); Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190706)); Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190707)); Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHolidayDefore(date20190708)); #endregion } [TestMethod] public void GetObservationDateStringTest() { var str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 23), "1W", BusinessDayConvention.None); Assert.AreEqual("2019-07-30,2019-08-06,2019-08-13,2019-08-20,2019-08-23", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 23), "11D", BusinessDayConvention.Following); Assert.AreEqual("2019-08-05,2019-08-14,2019-08-23", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 30), "1W", BusinessDayConvention.ModifiedFollowing); Assert.AreEqual("2019-07-30", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 31), "1W", BusinessDayConvention.ModifiedFollowing); Assert.AreEqual("2019-07-30,2019-07-31", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 6), "1W", BusinessDayConvention.ModifiedFollowing); Assert.AreEqual("2019-07-30,2019-08-06", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 7), "1W", BusinessDayConvention.ModifiedFollowing); Assert.AreEqual("2019-07-30,2019-08-06,2019-08-07", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "1D", BusinessDayConvention.Previous); Assert.AreEqual("2019-07-24,2019-07-25,2019-07-26,2019-07-29", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "2D", BusinessDayConvention.Previous); Assert.AreEqual("2019-07-25,2019-07-26,2019-07-29", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "3D", BusinessDayConvention.Previous); Assert.AreEqual("2019-07-26,2019-07-29", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 9, 11), new DateTime(2019, 12, 26), "1M", BusinessDayConvention.None); Assert.AreEqual("2019-10-11,2019-11-11,2019-12-11,2019-12-26", str); str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 9, 11), new DateTime(2019, 12, 26), "1M", BusinessDayConvention.None, true); Assert.AreEqual("2019-09-26,2019-10-26,2019-11-26,2019-12-26", str); } #region GetOptionValueResultTest /// /// 在Bus244情况下测试通过 /// [TestMethod] public void GetOptionValueResultTest() { PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); //var privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton)); //privateType.SetStaticField("_volConstructionType", VolConstructionType.Normal); //1. Normal mode, vol Surface NormalVolWithSurfaceTest(); //2. Normal mode, trade vol NormalVolWithTradeVolTest(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"true\"}"); //privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton)); //privateType.SetStaticField("_volConstructionType", VolConstructionType.SkewMap); PrepareGlobalSkewMap(); //3. SkewMap mode, vol surface SkewMapVolWithSurfaceTest(); //4. SkewMap mode, trade vol SkewMapVolWithTradeVolTest(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); //privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton)); //privateType.SetStaticField("_volConstructionType", VolConstructionType.Normal); } private underlying_manager CreateTestUnderlying() { return new underlying_manager() { UnderlyingInstrumentType = "CommodityFutures", UnderlyingCode = "RB1909", MaturityDate = new DateTime(2019, 9, 15) }; } private trade CreateTestTrade() { return new trade() { TradeType = "香草期权", Strike = 3050, OptionType = "看涨", ExerciseMode = "European", ExerciseDate = new DateTime(2019, 7, 12), UnderlyingCode = "RB1909", UnderlyingInstrumentType = "CommodityFutures", BuySell = "卖出", MaturityDate = new DateTime(2019, 7, 12), Notional = 1.0, TTMDays = 22 }; } private volatility CreateTestVolSurface() { return new volatility() { VolSurfaceMode = "MoneynessVol", InterpolationMethod = ConsVolMethod.BiLinear, Data = "[{\"Strike\":0.9,\"Expire\":\"1W\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"1W\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"1W\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"1W\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"1W\",\"Vol\":0.2066},{\"Strike\":0.9,\"Expire\":\"2W\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"2W\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"2W\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"2W\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"2W\",\"Vol\":0.2066},{\"Strike\":0.9,\"Expire\":\"1M\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"1M\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"1M\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"1M\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"1M\",\"Vol\":0.2066}]" }; } private void NormalVolWithSurfaceTest() { var underlying = CreateTestUnderlying(); var trade = CreateTestTrade(); var vol = CreateTestVolSurface(); var valueDateStr = "2019-06-13"; underlying.QuotationDate = DateTime.Parse(valueDateStr); trade.StartDate = DateTime.Parse(valueDateStr); var userId = Guid.NewGuid().ToString(); var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId); var initParam = new VolSurfaceInitParamsBuilder(userId) .SetUnderlying(underlying).SetVolatility(vol).SetValueDate(valueDateStr) .Build(underlying.UnderlyingCode); VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam); var discountCurveName = Guid.NewGuid().ToString(); var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04); marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve); var result = OptionCalculatorV1.GetOptionValueResult( userId, underlying, trade, new double[] { 3000.0 }, fixing: null, useTradeVolMode: false, preciseTimeMode: false, discountCurveName: discountCurveName); QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId); Assert.AreEqual(0.20726666666666666, result.Vol, 1E-8, "NormalVolWithSurfaceTest Vol"); Assert.AreEqual(-52.53732559515695, result.Pv, 1E-8, "NormalVolWithSurfaceTest Pv"); Assert.AreEqual(-0.40892373614411781, result.Delta, 1E-8, "NormalVolWithSurfaceTest Delta"); Assert.AreEqual(-0.0020790010069049458, result.Gamma, 1E-8, "NormalVolWithSurfaceTest Gamma"); Assert.AreEqual(-3.4837223134672968, result.Vega, 1E-8, "NormalVolWithSurfaceTest Vega"); Assert.AreEqual(0.00047367584343049884, result.Rho, 1E-8, "NormalVolWithSurfaceTest Rho"); Assert.AreEqual(1.6504286616814952, result.Theta, 1E-8, "NormalVolWithSurfaceTest Theta"); } private void NormalVolWithTradeVolTest() { var underlying = CreateTestUnderlying(); var trade = CreateTestTrade(); const double vol = 0.2075; var volTable = new List { new SingleVol { Strike = 1, Expire = "1D", Vol = vol }, new SingleVol { Strike = 1, Expire = "1Y", Vol = vol } }; var valueDateStr = "2019-06-13"; underlying.QuotationDate = DateTime.Parse(valueDateStr); trade.StartDate = DateTime.Parse(valueDateStr); var userId = Guid.NewGuid().ToString(); var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId); var initParam = new VolSurfaceInitParamsBuilder(userId) .SetUnderlying(underlying).SetValueDate(valueDateStr) .Build("MoneynessVol", volTable, trade.id.ToString()); VolSurfaceInitializerSingleton.GetInitializer(true).InitializeMarketProxy(initParam); var discountCurveName = Guid.NewGuid().ToString(); var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04); marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve); var result = OptionCalculatorV1.GetOptionValueResult( userId, underlying, trade, new double[] { 3000.0 }, fixing: null, useTradeVolMode: true, preciseTimeMode: false, discountCurveName: discountCurveName); QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId); Assert.AreEqual(0.2075, result.Vol, 1E-8, "NormalVolWithTradeVolTest Vol"); Assert.AreEqual(-52.618615629338535, result.Pv, 1E-8, "NormalVolWithTradeVolTest Pv"); Assert.AreEqual(-0.40598319079236944, result.Delta, 1E-8, "NormalVolWithTradeVolTest Delta"); Assert.AreEqual(-0.0020691189206445415, result.Gamma, 1E-8, "NormalVolWithTradeVolTest Gamma"); Assert.AreEqual(-3.483994693558401, result.Vega, 1E-8, "NormalVolWithTradeVolTest Vega"); Assert.AreEqual(0.00047440875331972165, result.Rho, 1E-8, "NormalVolWithTradeVolTest Rho"); Assert.AreEqual(1.6524160238749488, result.Theta, 1E-8, "NormalVolWithTradeVolTest Theta"); } private volatility CreateSkewMapBaseVolSurface() { return new volatility() { VolSurfaceMode = "MoneynessVol", InterpolationMethod = ConsVolMethod.BiLinear, Data = "[{\"Strike\":\"1.0000\",\"Expire\":\"1M\",\"Vol\":0.21},{\"Strike\":\"1.0000\",\"Expire\":\"3M\",\"Vol\":0.1937},{\"Strike\":\"1.0000\",\"Expire\":\"6M\",\"Vol\":0.1605},{\"Strike\":1,\"Expire\":\"AskVar\",\"Vol\":30},{\"Strike\":1,\"Expire\":\"BidVar\",\"Vol\":30}]" }; } private void PrepareGlobalSkewMap() { var data = File.ReadAllText("GlobalSkewMap.csv"); VolSkewMapInitializerSingleton.Instance.SetSkewMapData(data, isBuy: false); } private void SkewMapVolWithSurfaceTest() { var underlying = CreateTestUnderlying(); var trade = CreateTestTrade(); var vol = CreateSkewMapBaseVolSurface(); var valueDateStr = "2019-06-13"; underlying.QuotationDate = DateTime.Parse(valueDateStr); trade.StartDate = DateTime.Parse(valueDateStr); var userId = Guid.NewGuid().ToString(); var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId); var initParam = new VolSurfaceInitParamsBuilder(userId) .SetUnderlying(underlying).SetVolatility(vol).SetValueDate(valueDateStr) .Build(underlying.UnderlyingCode); VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam); var discountCurveName = Guid.NewGuid().ToString(); var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04); marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve); var result = OptionCalculatorV1.GetOptionValueResult( userId, underlying, trade, new double[] { 3000.0 }, fixing: null, useTradeVolMode: false, preciseTimeMode: false, discountCurveName: discountCurveName); QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId); Assert.AreEqual(0.27703706146327278, result.Vol, 1E-8, "SkewMapVolWithSurfaceTest Vol"); Assert.AreEqual(-77.05603142631152, result.Pv, 1E-8, "SkewMapVolWithSurfaceTest Pv"); Assert.AreEqual(-0.43601254203338158, result.Delta, 1E-8, "SkewMapVolWithSurfaceTest Delta"); Assert.AreEqual(-0.0015732894098619, result.Gamma, 1E-8, "SkewMapVolWithSurfaceTest Gamma"); Assert.AreEqual(-3.5368906374252163, result.Vega, 1E-8, "SkewMapVolWithSurfaceTest Vega"); Assert.AreEqual(0.000694736175923083, result.Rho, 1E-8, "SkewMapVolWithSurfaceTest Rho"); Assert.AreEqual(2.2395635945358663, result.Theta, 1E-8, "SkewMapVolWithSurfaceTest Theta"); } private void SkewMapVolWithTradeVolTest() { var underlying = CreateTestUnderlying(); var trade = CreateTestTrade(); const double vol = 0.2075; var volTable = new List { new SingleVol { Strike = 1, Expire = "1D", Vol = vol }, new SingleVol { Strike = 1, Expire = "1Y", Vol = vol } }; var valueDateStr = "2019-06-13"; underlying.QuotationDate = DateTime.Parse(valueDateStr); trade.StartDate = DateTime.Parse(valueDateStr); var userId = Guid.NewGuid().ToString(); var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId); var initParam = new VolSurfaceInitParamsBuilder(userId) .SetUnderlying(underlying).SetValueDate(valueDateStr) .Build("MoneynessVol", volTable, trade.id.ToString()); VolSurfaceInitializerSingleton.GetInitializer(true).InitializeMarketProxy(initParam); var discountCurveName = Guid.NewGuid().ToString(); var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04); marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve); var result = OptionCalculatorV1.GetOptionValueResult( userId, underlying, trade, new double[] { 3000.0 }, fixing: null, useTradeVolMode: true, preciseTimeMode: false, discountCurveName: discountCurveName); QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId); Assert.AreEqual(0.2075, result.Vol, 1E-8, "SkewMapVolWithSurfaceTest Vol"); Assert.AreEqual(-52.618615629338535, result.Pv, 1E-8, "SkewMapVolWithSurfaceTest Pv"); Assert.AreEqual(-0.40598319079236944, result.Delta, 1E-8, "SkewMapVolWithSurfaceTest Delta"); Assert.AreEqual(-0.0020691189206445415, result.Gamma, 1E-8, "SkewMapVolWithSurfaceTest Gamma"); Assert.AreEqual(-3.483994693558401, result.Vega, 1E-8, "SkewMapVolWithSurfaceTest Vega"); Assert.AreEqual(0.00047440875331972165, result.Rho, 1E-8, "SkewMapVolWithSurfaceTest Rho"); Assert.AreEqual(1.6524160238749488, result.Theta, 1E-8, "SkewMapVolWithSurfaceTest Theta"); } #endregion /// /// 商品期货交易手续费测试 /// [TestMethod] public void CommodityFuturesCommissionTest() { underlying_manager rb1910 = null, m1908 = null, ru1907 = null; using (var db = new YLContext()) { rb1910 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "RB1910"); m1908 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "M1908"); ru1907 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "RU1907"); } Assert.IsNotNull(rb1910, "rb1910 null"); Assert.IsNotNull(rb1910, "m1908 null"); Assert.IsNotNull(ru1907, "RU1907 null"); #region 按比例收取手续费 var trades = new List() { new ExchangeTrade() { id = 1, UnderlyingCode = "RB1910", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 4000, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 2, UnderlyingCode = "RB1910", TradeSide = "多头平仓", Notional = 800, TradeSinglePrice = 4100, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 3, UnderlyingCode = "RB1910", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 4200, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 4, UnderlyingCode = "RB1910", TradeSide = "多头平仓", Notional = 100, TradeSinglePrice = 4250, CommissionType = CommissionType.不收取 //这笔不会计算手续费 }, new ExchangeTrade() { id = 5, UnderlyingCode = "RB1910", TradeSide = "多头平仓", Notional = 1300, TradeSinglePrice = 4150, CommissionType = CommissionType.系统计算 } }; var commissions = CommissionCalcHelper.GetCommissionForTrade(rb1910, trades); Assert.AreEqual(4, commissions.Count, "RB1910 commissions count"); Assert.AreEqual(2000, commissions[1], 1e-8, "RB1910 trade 1 commission"); Assert.AreEqual(1640, commissions[2], 1e-8, "RB1910 trade 2 commission"); Assert.AreEqual(2100, commissions[3], 1e-8, "RB1910 trade 3 commission"); Assert.AreEqual(2697.5, commissions[5], 1e-8, "RB1910 trade 3 commission"); #endregion #region 按固定收取手续费 trades = new List() { new ExchangeTrade() { id = 1, UnderlyingCode = "M1908", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 2800, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 2, UnderlyingCode = "M1908", TradeSide = "多头平仓", Notional = 800, TradeSinglePrice = 2800, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 3, UnderlyingCode = "M1908", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 2800, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 4, UnderlyingCode = "M1908", TradeSide = "多头平仓", Notional = 100, TradeSinglePrice = 2800, CommissionType = CommissionType.不收取 //这笔不会计算手续费 }, new ExchangeTrade() { id = 5, UnderlyingCode = "M1908", TradeSide = "多头平仓", Notional = 1300, TradeSinglePrice = 2800, CommissionType = CommissionType.系统计算 } }; commissions = CommissionCalcHelper.GetCommissionForTrade(m1908, trades); Assert.AreEqual(4, commissions.Count, "M1908 commissions count"); Assert.AreEqual(150, commissions[1], 1e-8, "M1908 trade 1 commission"); Assert.AreEqual(120, commissions[2], 1e-8, "M1908 trade 2 commission"); Assert.AreEqual(150, commissions[3], 1e-8, "M1908 trade 3 commission"); Assert.AreEqual(195, commissions[5], 1e-8, "M1908 trade 3 commission"); #endregion #region 带有平今仓手续费规则 trades = new List() { new ExchangeTrade() { id = 1, UnderlyingCode = "RU1909", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 12000, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 2, UnderlyingCode = "RU1909", TradeSide = "多头平仓", Notional = 800, TradeSinglePrice = 11000, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 3, UnderlyingCode = "RU1909", TradeSide = "多头开仓", Notional = 1000, TradeSinglePrice = 11500, CommissionType = CommissionType.系统计算 }, new ExchangeTrade() { id = 4, UnderlyingCode = "RU1909", TradeSide = "多头平仓", Notional = 100, TradeSinglePrice = 13000, CommissionType = CommissionType.不收取 //这笔不会计算手续费 }, new ExchangeTrade() { id = 5, UnderlyingCode = "RU1909", TradeSide = "多头平仓", Notional = 1300, TradeSinglePrice = 12500, CommissionType = CommissionType.系统计算 } }; commissions = CommissionCalcHelper.GetCommissionForTrade(ru1907, trades); Assert.AreEqual(4, commissions.Count, "RU1909 commissions count"); Assert.AreEqual(540, commissions[1], 1e-8, "RU1909 trade 1 commission"); Assert.AreEqual(160, commissions[2], 1e-8, "RU1909 trade 2 commission"); Assert.AreEqual(517.5, commissions[3], 1e-8, "RU1909 trade 3 commission"); Assert.AreEqual(296.25, commissions[5], 1e-8, "RU1909 trade 3 commission"); #endregion } [TestMethod] public void CommodityFutureOptionMarginTest() { double premium = 45, amount = 3, strike = 4000, futureMarginRatio = 0.09; var optionType = "Call"; #region Call //InTheMoney double spotPrice = 4100; var benchmark = premium + spotPrice * amount * futureMarginRatio; var margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //AtTheMoney spotPrice = 4000; benchmark = premium + (spotPrice * amount * futureMarginRatio); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //OutTheMoney and Value < futureMargin spotPrice = 3900; benchmark = premium + (spotPrice * amount * futureMarginRatio) - ((strike - spotPrice) * amount * 0.5); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //OutTheMoney and Value > futureMargin spotPrice = 3500; benchmark = premium + (spotPrice * amount * futureMarginRatio * 0.5); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); #endregion #region Put optionType = "Put"; //InTheMoney spotPrice = 3900; benchmark = premium + (spotPrice * amount * futureMarginRatio); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //AtTheMoney spotPrice = 4000; benchmark = premium + (spotPrice * amount * futureMarginRatio); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //OutTheMoney and Value < futureMargin spotPrice = 4100; benchmark = premium + (spotPrice * amount * futureMarginRatio) - ((spotPrice - strike) * amount * 0.5); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); //OutTheMoney and Value > futureMargin spotPrice = 4500; benchmark = premium + (spotPrice * amount * futureMarginRatio * 0.5); margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType); Assert.AreEqual(benchmark, margin, double.Epsilon); #endregion } [TestMethod] public void ValueVanillaOptionWithVolSettingTest() { var valueDate = new DateTime(2019, 4, 4); var underlyingTicker = "RB00"; 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); TradeValueResult result = null; using (var mp = new MarketProxy(valueDate, 0.035)) { var tradeParam = new VanillaOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", strike = 2900.0, startDate = valueDate, endDate = new DateTime(2019, 05, 06), optionType = OptionType.Call,// "Call", exerciseType = "European", initialSpotPrice = 2900.0, notional = 100.0, volSurfaceNames = new[] { underlyingTicker + "_VolSurface" }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2019, 05, 06), dividendRate = 0, timeToMaturityDays = 18, participationRate = 1.0, principalRate = 0.0, isAnnualized = false, annualizedFactor = 1.0, preciseTimeMode = false, }; mp.SetVolSurface(tradeParam.volSurfaceNames[0], new VolatilityImpl { VolTable = singleVols }); result = TradeRiskCalcUtil.GetVanillaOptionValue(mp, new OptionCalcParam(tradeParam) { spotPrices = new[] { 2900.0 } }); } //var initParam = new VolSurfaceInitParamsBuilder() // .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); //new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); //计算 //result = OptionCalculator.ValueVanillaOptionTrade( // marketProxy: marketProxy, // valueDate: valueDate + "", // underlyingTicker: underlyingTicker, // underlyingInstrumentType: "CommodityFutures", // strike: 2900.0, // startDate: valueDate + "", // endDate: "2019-05-06", // optionType: "Call", // exerciseType: "European", // spotPrice: 2900.0, // notional: 100.0, // volSurfaceName: underlyingTicker + "_VolSurface", // riskFreeRate: 0.035, // modelName: null, // tradeType: "Buy", // exerciseDate: "2019-05-06", // dividendRate: 0, // timeToMaturityDays: 18, // ignoreSkewMap: true, // participationRate: 1.0, // principalRate: 0.0, // isAnnualized: false, // annualizeFactor: 1.0); Assert.AreEqual(6267.6490467250824, result.Pv, 1E-8, ""); Assert.AreEqual(50.9516973058509, result.Delta, 1E-8, ""); Assert.AreEqual(0.25249779355362989, result.Gamma, 1E-8, ""); Assert.AreEqual(313.305398649345, result.Vega, 1E-8, ""); Assert.AreEqual(-175.67364449584602, result.Theta, 1E-8, ""); //Assert.AreEqual(-0.04623504985065665, result.Rho, 1E-8, ""); } [TestMethod] public void ValueVanillaOptionWithVolSettingTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "香草期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900, Notional = 100 }; var parameter = new VanillaOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900 } }, OverrideTTM = 18, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(6267.6490467250824, result.Pv, 1E-8, ""); Assert.AreEqual(50.95295979454022, result.Delta, 1E-8, ""); Assert.AreEqual(0.25249779355362989, result.Gamma, 1E-8, ""); Assert.AreEqual(313.305398649345, result.Vega, 1E-8, ""); Assert.AreEqual(-175.67364449584602, result.Theta, 1E-8, ""); Assert.AreEqual(-0.04623504985065665, result.Rho, 1E-8, ""); } /// /// 在期权定价时调整定价日 /// private DateTime AdjustQuotationDate(DateTime quotationDate, string tradeType) { // 对凤凰雪球不做报价日调整 if (tradeType == "雪球期权" || tradeType == "凤凰期权") { return quotationDate; } //为了暂时修复一个QDP计算方式与客户需求不匹配的情况 //在非精确模式下,QDP不包括交易日当天的时间价值,但根据报价需求,需要将交易日当天的时间价值计算在内, //所以要将交易日向前移动一天。未来QDP支持传递TTM来计算时,可以直接在TTM上加1,而不用移动交易日 //注意:当前这个临时修改必须在波动率插值之前调用,这样才能正确设置波动率日期 var calendar = CalendarImpl.Get("chn"); return calendar.PrevBizDay(quotationDate).DateTime; } [TestMethod] public void ValueBarrierOptionTest() { var valueDate = new DateTime(2019, 04, 04); var underlyingTicker = "RB00"; TradeValueResult result; if (valueDate != valuedateBLL.ValueDate.Date) { valueDate = AdjustQuotationDate(valueDate, "障碍期权"); } var tradeId = Guid.NewGuid().ToString(); using (var mp = new MarketProxy(valueDate, 0.035)) { var vols = QdpVolHelper.GetDefaultVolatility(0.2); mp.SetVolSurface(tradeId, vols); var tdParam = new BarrierOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", strike = 2900.0, startDate = valueDate, endDate = new DateTime(2024, 2, 5), optionType = OptionType.Call, exerciseType = "European", barrierType = "UpAndOut", barrierPrice = 3000.0, upperBarrierPrice = 0.0, isDiscrete = true, initialSpotPrice = 2900.0, rebate = 20.0, notional = 100.0, volSurfaceNames = new[] { tradeId }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2019, 05, 06), rebateType = "AtHit", observationDateStr = "2019-04-09,2019-04-16,2019-04-23,2019-04-29,2019-05-06", dividendRate = 0.0, barrierShift = 0.0, participationRate = 1.0, principalRate = 0.0, isAnnualized = false, annualizedFactor = 1.0, rebateAnnualizedAtKO = false, rebateDayCount = "", timeToMaturityDays = 19 }; result = TradeRiskCalcUtil.GetBarrierOptionValue(mp, new OptionCalcParam(tdParam) { spotPrices = new[] { tdParam.initialSpotPrice }, quadratureFastMode = true }); } Assert.AreEqual(1439.9127764086413, result.Pv, 1E-8, ""); Assert.AreEqual(5.1646784276044855, result.Delta, 1E-8, ""); Assert.AreEqual(-0.016520966710231733, result.Gamma, 1E-8, ""); Assert.AreEqual(-17.501027350181175, result.Vega, 1E-8, ""); Assert.AreEqual(10.403561845246486, result.Theta, 1E-8, ""); Assert.AreEqual(0.12190782245161244, result.Rho, 1E-8, ""); } [TestMethod] public void ValueBarrierOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "障碍期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_barrier_option = new trade_barrier_option() { BarrierType = "上升敲出", BarrierPrice = 3000.0, BarrierShift = 0.0, Discrete = "离散", Rebate = 20.0, KnockInOutStatus = "Monitoring" } }; var parameter = new BarrierOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(1353.9894515364406, result.Pv, 1E-8, ""); Assert.AreEqual(5.6636792255631008, result.Delta, 1E-8, ""); Assert.AreEqual(-0.0058651176004786976, result.Gamma, 1E-8, ""); Assert.AreEqual(-2.900013280566327, result.Vega, 1E-8, ""); Assert.AreEqual(4.7292177906094821, result.Theta, 1E-8, ""); Assert.AreEqual(-0.0035508358797642359, result.Rho, 1E-8, ""); //双障碍 trade = new trade() { TradeType = "障碍期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 130.0, Notional = 100, trade_barrier_option = new trade_barrier_option() { BarrierType = "DoubleTouchOut", BarrierPrice = 100.0, UpperBarrierPrice = 144.0, BarrierShift = 0.0, Discrete = "离散", Rebate = 20.0, KnockInOutStatus = "Monitoring" } }; parameter = new BarrierOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 120.0 } }, RiskFreeRate = 0.035 }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(31.52299607431015, result.Pv, 1E-8, ""); Assert.AreEqual(8.7249908156710632, result.Delta, 1E-8, ""); Assert.AreEqual(2.989637326322736, result.Gamma, 1E-8, ""); Assert.AreEqual(7.0000209372153677, result.Vega, 1E-8, ""); Assert.AreEqual(-3.570910197936211, result.Theta, 1E-8, ""); Assert.AreEqual(0.00835458118292216, result.Rho, 1E-8, ""); //KIKO trade = new trade() { TradeType = "障碍期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 145, Notional = 100, trade_barrier_option = new trade_barrier_option() { BarrierType = "KIKO", BarrierPrice = 146, UpperBarrierPrice = 148, BarrierShift = 0.0, Discrete = "离散", Rebate = 20.0, KnockInOutStatus = "Monitoring" } }; parameter = new BarrierOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 146.9 } }, RiskFreeRate = 0.035 }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(-414.20440415099324, result.Pv, 1E-8, ""); Assert.AreEqual(186.12515246873045, result.Delta, 1E-8, ""); Assert.AreEqual(5.5092195839279157, result.Gamma, 1E-8, ""); Assert.AreEqual(9.4165577108014986, result.Vega, 1E-8, ""); Assert.AreEqual(-10.397275659495108, result.Theta, 1E-8, ""); Assert.AreEqual(0.01632015110478733, result.Rho, 1E-8, ""); //自定义观察日 trade = new trade() { TradeType = "障碍期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_barrier_option = new trade_barrier_option() { BarrierType = "上升敲出", BarrierPrice = 3000.0, BarrierShift = 0.0, Discrete = "离散", Rebate = 20.0, KnockInOutStatus = "Monitoring", ObservationDates = "2019-04-09,2019-04-16,2019-04-23,2019-04-29,2019-05-06" } }; parameter = new BarrierOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035 }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(1439.9127764086413, result.Pv, 1E-8, ""); Assert.AreEqual(5.1646784276044855, result.Delta, 1E-8, ""); Assert.AreEqual(-0.016520966710231733, result.Gamma, 1E-8, ""); Assert.AreEqual(-17.501027350181175, result.Vega, 1E-8, ""); Assert.AreEqual(10.403561845246486, result.Theta, 1E-8, ""); Assert.AreEqual(0.12190782245161244, result.Rho, 1E-8, ""); } [TestMethod] public void ValueAsianOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); var result = OptionCalculatorV1.ValueAsianOptionTrade( marketProxy, valueDate, underlyingTicker, "CommodityFutures", 2900.0, valueDate, "2019-05-06", "Call", "European", "ArithmeticAverage", "Fixed", 2900.0, 100.0, underlyingTicker + "_VolSurface", 0.035, "Buy", "2019-05-06", isAnnualized: false, annualizeFactor: 1.0, dividendRate: 0.0, fixings: "2019-04-01,2850;2019-04-02,2855;2019-04-03,2899", averagingPeriodStartDate: "2019-04-01", ignoreSkewMap: true); Assert.AreEqual(3164.92251559125, result.Pv, 1E-8, ""); Assert.AreEqual(44.185302306550511, result.Delta, 1E-8, ""); Assert.AreEqual(0.38820497138658538, result.Gamma, 1E-8, ""); Assert.AreEqual(165.84751675402458, result.Vega, 1E-8, ""); Assert.AreEqual(-294.4723867871885, result.Theta, 1E-8, ""); Assert.AreEqual(-0.02594092466551956, result.Rho, 1E-8, ""); //增强型 result = OptionCalculatorV1.ValueAsianOptionTrade( marketProxy, valueDate, underlyingTicker, "CommodityFutures", 2900.0, valueDate, "2019-05-06", "Call", "European", "EnhancedArithmeticAverage", "Fixed", 2900.0, 100.0, underlyingTicker + "_VolSurface", 0.035, "Buy", "2019-05-06", isAnnualized: false, annualizeFactor: 1.0, dividendRate: 0.0, fixings: "", averagingPeriodStartDate: "2019-04-04", ignoreSkewMap: true); Assert.AreEqual(4341.7462907276122, result.Pv, 1E-8, ""); Assert.AreEqual(53.059818666679348, result.Delta, 1E-8, ""); Assert.AreEqual(476.57855693614692, result.Gamma, 1E-8, ""); Assert.AreEqual(217.05074145074832, result.Vega, 1E-8, ""); Assert.AreEqual(-314.50937525089466, result.Theta, 1E-8, ""); Assert.AreEqual(-0.021944944954884704, result.Rho, 1E-8, ""); } [TestMethod] public void ValueAsianOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "亚式期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_asian_option = new trade_asian_option() { PayoffType = "ArithmeticAverage", StrikeType = "Fixed", AveragingPeriodStartDate = new DateTime(2019, 4, 1) } }; var parameter = new AsianOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035, Fixings = "2019-04-01,2850;2019-04-02,2855;2019-04-03,2899" }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(3164.92251559125, result.Pv, 1E-8, ""); Assert.AreEqual(44.185302306550511, result.Delta, 1E-8, ""); Assert.AreEqual(0.38820497138658538, result.Gamma, 1E-8, ""); Assert.AreEqual(165.84751675402458, result.Vega, 1E-8, ""); Assert.AreEqual(-294.4723867871885, result.Theta, 1E-8, ""); Assert.AreEqual(-0.02594092466551956, result.Rho, 1E-8, ""); //增强型 trade = new trade() { TradeType = "亚式期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_asian_option = new trade_asian_option() { PayoffType = "EnhancedArithmeticAverage", StrikeType = "Fixed", AveragingPeriodStartDate = new DateTime(2019, 4, 4) } }; parameter = new AsianOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035, Fixings = "" }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(4341.7462907276122, result.Pv, 1E-8, ""); Assert.AreEqual(53.059818666679348, result.Delta, 1E-8, ""); Assert.AreEqual(476.57855693614692, result.Gamma, 1E-8, ""); Assert.AreEqual(217.05074145074832, result.Vega, 1E-8, ""); Assert.AreEqual(-314.50937525089466, result.Theta, 1E-8, ""); Assert.AreEqual(-0.021944944954884704, result.Rho, 1E-8, ""); } [TestMethod] public void ValueBinaryOptionTest() { TradeValueResult result; var valueDate = new DateTime(2019, 04, 04); var underlyingTicker = "RB00"; var vol = QdpVolHelper.GetDefaultVolatility(0.2); var valueDateStr = "2019-04-04"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDateStr), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); result = OptionCalculatorV1.ValueBinaryOptionTrade( marketProxy, valueDateStr, underlyingTicker, "CommodityFutures", 2900.0, valueDateStr, "2019-05-06", "Call", "European", "CashOrNothing", //payoffType 200.0, 2900.0, 100.0, underlyingTicker + "_VolSurface", 0.035, "Buy", "2019-05-06", dividendRate: 0.0, binaryRebateType: "AtHit", binaryOptionReplicationStrategy: "None", replicationShiftSize: 0.0, ignoreSkewMap: true, participationRate: 1.0, principalRate: 0.0, isAnnualized: false, annualizeFactor: 1.0); Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, ""); Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, ""); Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, ""); Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, ""); Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, ""); Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, ""); var tradeId = Guid.NewGuid().ToString(); using var mp = new MarketProxy(valueDate, 0.035); mp.SetVolSurface(tradeId, vol); var tdParam = new BinaryOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", strike = 2900.0, startDate = valueDate, endDate = new DateTime(2019, 05, 06), optionType = OptionType.Call, exerciseType = "European", payoffType = "CashOrNothing", //payoffType cashOrNothingAmount = 200.0, initialSpotPrice = 2900.0, notional = 100.0, volSurfaceNames = new[] { tradeId }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2019, 05, 06), dividendRate = 0.0, binaryRebateType = "AtHit", binaryOptionReplicationStrategy = "None", replicationShiftSize = 0.0, participationRate = 1.0, principalRate = 0.0, isAnnualized = false, annualizedFactor = 1.0 }; result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam(tdParam) { spotPrices = new[] { 2900d } }); Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, ""); Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, ""); Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, ""); Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, ""); Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, ""); Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, ""); tdParam = new BinaryOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", strike = 2900.0, startDate = valueDate, endDate = new DateTime(2019, 05, 06), optionType = OptionType.Call, exerciseType = "European", payoffType = "CashOrNothing", //payoffType cashOrNothingAmount = 200.0, initialSpotPrice = 2900.0, notional = 100.0, volSurfaceNames = new[] { tradeId }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2019, 05, 06), dividendRate = 0.0, binaryRebateType = "AtHit", binaryOptionReplicationStrategy = "Down", replicationShiftSize = 0.0, participationRate = 1.0, principalRate = 0.0, isAnnualized = false, annualizedFactor = 1.0 }; result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam(tdParam) { spotPrices = new[] { 2900d }, engineName = "AnalyticalBinaryEuropeanOptionReplicationEngine" }); Assert.AreEqual(10439.754311151559, result.Pv, 1E-8, ""); Assert.AreEqual(47.767642553136, result.Delta, 1E-8, ""); Assert.AreEqual(-0.033387487778311659, result.Gamma, 1E-8, ""); Assert.AreEqual(-46.042248515481454, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.085568249705202437, result.Rho, 1E-8, ""); //美式二元 tdParam = new BinaryOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", strike = 950.0, startDate = valueDate, endDate = new DateTime(2019, 05, 06), optionType = OptionType.Call, exerciseType = "American", payoffType = "DoubleOneTouch", //payoffType cashOrNothingAmount = 200.0, initialSpotPrice = 990.0, notional = 100.0, volSurfaceNames = new[] { tradeId }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2019, 05, 06), upperBarrier = 1100.0, dividendRate = 0.0, binaryRebateType = "AtHit", binaryOptionReplicationStrategy = "Down", replicationShiftSize = 0.0, participationRate = 1.0, principalRate = 0.0, isAnnualized = false, annualizedFactor = 1.0 }; result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam(tdParam) { spotPrices = new[] { 990.0 } }); Assert.AreEqual(10835.184736140083, result.Pv, 1E-8, ""); Assert.AreEqual(-165.90143058310787, result.Delta, 1E-8, ""); Assert.AreEqual(4.3446263953228481, result.Gamma, 1E-8, ""); Assert.AreEqual(696.36722659533916, result.Vega, 1E-8, ""); Assert.AreEqual(-354.58732062354829, result.Theta, 1E-8, ""); Assert.AreEqual(-0.040437084736549875, result.Rho, 1E-8, ""); } [TestMethod] public void ValueBinaryOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "二元期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_binary_option = new trade_binary_option() { PayoffType = "CashOrNothing", CashOrNothingAmount = 200, RebateType = "AtHit" } }; var parameter = new BinaryOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, ""); Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, ""); Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, ""); Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, ""); Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, ""); Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, ""); parameter = new BinaryOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900.0 } }, RiskFreeRate = 0.035, EngineName = "AnalyticalBinaryEuropeanOptionReplicationEngine", BinaryReplicationStrategy = "Down", ReplicationShiftSize = 0.0 }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(10439.754311151559, result.Pv, 1E-8, ""); Assert.AreEqual(47.767642553136, result.Delta, 1E-8, ""); Assert.AreEqual(-0.033387487778311659, result.Gamma, 1E-8, ""); Assert.AreEqual(-46.042248515481454, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.085568249705202437, result.Rho, 1E-8, ""); //美式二元 trade = new trade() { TradeType = "二元期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "American", BuySell = "Buy", Strike = 950, Notional = 100, trade_binary_option = new trade_binary_option() { PayoffType = "DoubleOneTouch", CashOrNothingAmount = 200, RebateType = "AtHit", UpperBarrier = 1100.0, MonitorType = "连续", } }; parameter = new BinaryOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 990.0 } }, RiskFreeRate = 0.035 }; result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(10835.184736140083, result.Pv, 1E-8, ""); Assert.AreEqual(-165.90143058310787, result.Delta, 1E-8, ""); Assert.AreEqual(4.3446263953228481, result.Gamma, 1E-8, ""); Assert.AreEqual(696.36722659533916, result.Vega, 1E-8, ""); Assert.AreEqual(-354.58732062354829, result.Theta, 1E-8, ""); Assert.AreEqual(-0.040437084736549875, result.Rho, 1E-8, ""); } [TestMethod] public void ValueRainbowOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker1 = "RB00"; var underlying1 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker1 }; var underlyingTicker2 = "RB01"; var underlying2 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker2 }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying1).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); var singleVols2 = new List(); for (var i = 0; i < vols.GetLength(0); ++i) { for (var j = 0; j < vols.GetLength(1); ++j) { vols[i, j] = 0.25; singleVols2.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.25 }); } } var initParam2 = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying2).SetValueDate(valueDate).Build("MoneynessVol", singleVols2); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam2); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var result = OptionCalculatorV1.ValueRainbowOptionTrade( marketProxy, valueDate, "CommodityFutures", new string[] { underlyingTicker1, underlyingTicker2 }, new string[] { underlyingTicker1 + "_VolSurface", underlyingTicker2 + "_VolSurface" }, new double[] { 2900.0, 2950.0 }, valueDate, "2019-05-06", "Call", "European", "BestOfAssetsOrCash", //rainbowType 150.0, // cashAmount new double[] { 2900.0, 2950.0 }, 100.0, 0.035, 0.85, //correlation "Buy", "2019-05-06", dividendRate: 0.0, ignoreSkewMap: true, participationRate: 1.0, principalRate: 0.0, isAnnualized: false, annualizeFactor: 1.0); Assert.AreEqual(3010.0301061974196, result.Pv, 1E-8, ""); Assert.AreEqual(0.15599592643411597, result.Delta, 1E-8, ""); Assert.AreEqual(0.0022282620193436742, result.Gamma, 1E-8, ""); Assert.AreEqual(0.959972953476381, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.024672276803812565, result.Rho, 1E-8, ""); Assert.AreEqual(0.50413404551363783, result.Delta2.Value, 1E-8, ""); Assert.AreEqual(0.0027284841053187847, result.Gamma2.Value, 1E-8, ""); Assert.AreEqual(2.9983269828480843, result.Vega2.Value, 1E-8, ""); Assert.AreEqual(-0.0016143530956469476, result.CrossGamma, 1E-8, ""); Assert.AreEqual(-0.062994161204528609, result.CrossVogga, 1E-8, ""); Assert.AreEqual(-0.56289229188678291, result.CorrVega, 1E-8, ""); } [TestMethod] public void ValueRainbowOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker1 = "RB00"; var underlying1 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker1, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var underlyingTicker2 = "RB01"; var underlying2 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker2, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "彩虹期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900.0, Notional = 100, trade_rainbow_option = new trade_rainbow_option() { RainbowType = "BestOfAssetsOrCash", CashAmount = 150.0, UnderlyingAssetCode = underlyingTicker1, UnderlyingAssetCode2 = underlyingTicker2, Strike2 = 2950.0 } }; var parameter = new RainbowOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, Volatility2 = 0.25, SpotPrices = new Dictionary() { { underlying1.UnderlyingCode, 2900.0 }, { underlying2.UnderlyingCode, 2950.0 } }, Correlation = 0.85, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying1, parameter); Assert.AreEqual(3010.0301061974196, result.Pv, 1E-8, ""); Assert.AreEqual(0.15599592643411597, result.Delta, 1E-8, ""); Assert.AreEqual(0.0022282620193436742, result.Gamma, 1E-8, ""); Assert.AreEqual(0.959972953476381, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.024672276803812565, result.Rho, 1E-8, ""); Assert.AreEqual(0.50413404551363783, result.Delta2.Value, 1E-8, ""); Assert.AreEqual(0.0027284841053187847, result.Gamma2.Value, 1E-8, ""); Assert.AreEqual(2.9983269828480843, result.Vega2.Value, 1E-8, ""); Assert.AreEqual(-0.0016143530956469476, result.CrossGamma, 1E-8, ""); Assert.AreEqual(-0.062994161204528609, result.CrossVogga, 1E-8, ""); Assert.AreEqual(-0.56289229188678291, result.CorrVega, 1E-8, ""); } [TestMethod] public void ValueSyntheticNormalSpreadOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); //计算 var result = OptionCalculatorV1.ValueSyntheticNormalSpreadOptionTrade( marketProxy, valueDate, underlyingTicker, "CommodityFutures", 2900.0, valueDate, "2019-05-06", "Call", "European", 2900.0, 100.0, underlyingTicker + "_VolSurface", 0.035, null, "Buy", "2019-05-06", dividendRate: 0, ignoreSkewMap: true, participationRate: 1.0, principalRate: 0.0, isAnnualized: false, annualizeFactor: 1.0); Assert.AreEqual(2.2777928184782521, result.Pv, 1E-8, ""); Assert.AreEqual(53.321595022577874, result.Delta, 1E-8, ""); Assert.AreEqual(692.96641664031711, result.Gamma, 1E-8, ""); Assert.AreEqual(0.11388964092384768, result.Vega, 1E-8, ""); Assert.AreEqual(-0.057356519934982586, result.Theta, 1E-8, ""); Assert.AreEqual(-1.8669667777526655E-05, result.Rho, 1E-8, ""); } [TestMethod] public void ValueSyntheticNormalSpreadOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "合成价差期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900, Notional = 100 }; var parameter = new SyntheticNormalSpreadOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 2900 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(2.2777928184782521, result.Pv, 1E-8, ""); Assert.AreEqual(53.321595022577874, result.Delta, 1E-8, ""); Assert.AreEqual(692.96641664031711, result.Gamma, 1E-8, ""); Assert.AreEqual(0.11388964092384768, result.Vega, 1E-8, ""); Assert.AreEqual(-0.057356519934982586, result.Theta, 1E-8, ""); Assert.AreEqual(-1.8669667777526655E-05, result.Rho, 1E-8, ""); } [TestMethod] public void ValueAutocallTest() { var valueDate = "2019-07-30"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.35; singleVols.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.35 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); //计算 var result = OptionCalculatorV1.ValueAutocallTrade( marketProxy: marketProxy, valueDate: valueDate, underlyingCode: underlyingTicker, underlyingInstrumentType: "CommodityFutures", startDate: valueDate, endDate: "2019-09-08", callPut: "Call", koBarrier: 100.0, kiBarrier: 80.0, couponBarrier: 80.0, koObservationDateStr: "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31", observationDateStr: null, coupon: 0.12, couponPayAtMaturity: false, includeCouponAfterKI: true, isFixedCoupon: false, annualizedOptionPayoff: false, participationRate: 0.75, principalRate: 0.0, spotPrice: 100.0, notional: 12.0, volSurfaceName: underlyingTicker + "_VolSurface", riskFreeRate: 0.035, buySell: "Buy", exerciseDate: "2020-02-01", annualizeFactor: 1.0, couponDayCount: "", strike: 100.0, spreadStrike: 0.0, happenedObservations: null, initialSpotPrice: 100.0); Assert.AreEqual(8.5343, result.Pv, 0.01); } [TestMethod] public void ValueAsianSyntheticNormalSpreadOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.3; singleVols.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.3 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); var result = OptionCalculatorV1.ValueAsianSyntheticNormalSpreadOptionTrade( marketProxy, valueDate, underlyingTicker, "CommodityFutures", 100, valueDate, "2019-04-30", "Call", "European", "ArithmeticAverage", "Fixed", 100.0, 1000.0, underlyingTicker + "_VolSurface", 0.03, "Buy", "2019-04-30", isAnnualized: false, annualizeFactor: 1.0, dividendRate: 0.0, averagingPeriodStartDate: null, ignoreSkewMap: true); Assert.AreEqual(18.200884513861684, result.Pv, 1E-8, ""); Assert.AreEqual(542.322618892204, result.Delta, 1E-8, ""); Assert.AreEqual(8673.3218846805466, result.Gamma, 1E-8, ""); Assert.AreEqual(0.606696150462227, result.Vega, 1E-8, ""); Assert.AreEqual(-0.54126177511056994, result.Theta, 1E-8, ""); Assert.AreEqual(-0.00012680502384547764, result.Rho, 1E-8, ""); } [TestMethod] public void ValueAsianSyntheticNormalSpreadOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "亚式合成价差期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 4, 30), ExerciseDate = new DateTime(2019, 4, 30), ExerciseMode = "European", OptionType = "看涨", BuySell = "Buy", Strike = 100, Notional = 1000, trade_asian_option = new trade_asian_option() { PayoffType = "ArithmeticAverage", StrikeType = "Fixed" } }; var parameter = new AsianSyntheticNormalSpreadOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.3, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 100 } }, RiskFreeRate = 0.03, Fixings = "" }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(18.200884513861684, result.Pv, 1E-8, ""); Assert.AreEqual(542.322618892204, result.Delta, 1E-8, ""); Assert.AreEqual(8673.3218846805466, result.Gamma, 1E-8, ""); Assert.AreEqual(0.606696150462227, result.Vega, 1E-8, ""); Assert.AreEqual(-0.54126177511056994, result.Theta, 1E-8, ""); Assert.AreEqual(-0.00012680502384547764, result.Rho, 1E-8, ""); } [TestMethod] public void ValueAutocallTestV2() { var valueDate = "2019-07-30"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "凤凰期权", TradeDate = new DateTime(2019, 7, 30), MaturityDate = new DateTime(2020, 9, 8), ExerciseDate = new DateTime(2020, 2, 1), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 100, Notional = 12, SpotPrice = 100, ParticipationRate = 0.75, trade_autocall = new trade_autocall() { KOBarrier = 100, KIBarrier = 80, Coupon = 0.12, CouponPayType = CouponPayTypeEnum.AtMaturity, KOObservationDates = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31" } }; var parameter = new AutocallParameter() { ValueDate = new DateTime(2019, 7, 30), Volatility = 0.35, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 100 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(8.5343, result.Pv, 0.01); } [TestMethod] public void ValueSnowballTest() { var valueDate = new DateTime(2019, 07, 30); var underlyingTicker = "RB00"; var vols = QdpVolHelper.GetDefaultVolatility(0.35); var tradeId = Guid.NewGuid().ToString(); using var mp = new MarketProxy(valueDate, 0.035); mp.SetVolSurface(tradeId, vols); var tdparam = new SnowballOptionTradeParam { underlyingTickers = new[] { underlyingTicker }, underlyingInstrumentType = "CommodityFutures", startDate = valueDate, endDate = new DateTime(2019, 09, 08), optionType = OptionType.Call, koBarrier = 100.0, kiBarrier = 80.0, koObservationDateStr = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31", observationDateStr = null, coupon = 0.12, participationRate = 0.75, principalRate = 0.0, initialSpotPrice = 100.0, notional = 12.0, volSurfaceNames = new[] { tradeId }, riskFreeRate = 0.035, buysell = "Buy", exerciseDate = new DateTime(2020, 1, 31), isAnnualized = false, annualizedFactor = 1.0, strike = 100.0, spreadStrikeAtKO = 0.0, spreadStrikeAtMaturity = 0.0, isFixedCoupon = false, koRebate = 12.0, koBarrierAdjustStep = 0.0, useOptionPayoffAtKO = false, useOptionPayoffAtMaturity = true, annualizedOptionPayoff = false, couponDayCount = "Act365", kiOptionType = OptionType.Coupon, koOptionType = OptionType.Call }; var result = TradeRiskCalcUtil.GetSnowballOptionValue(mp, new OptionCalcParam(tdparam) { spotPrices = new[] { 100d }, pricingRequest = PricingRequest.Pv, quadratureFastMode = true }); Assert.AreEqual(8.4353, result.Pv, 0.01); } [TestMethod] public void ValueSnowballTestV2() { var valueDate = "2019-07-30"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "雪球期权", TradeDate = new DateTime(2019, 7, 30), MaturityDate = new DateTime(2020, 9, 8), ExerciseDate = new DateTime(2020, 2, 1), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 100, Notional = 12, SpotPrice = 100, ParticipationRate = 0.75, trade_snowball = new trade_snowball() { KOBarrier = 100, KIBarrier = 80, Coupon = 0.12, KOObservationDates = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31" } }; var parameter = new SnowballParameter() { ValueDate = new DateTime(2019, 7, 30), Volatility = 0.35, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 100 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(8.4353, result.Pv, 0.01); } [TestMethod] public void ValueDoubleSharkFinOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); 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.2 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); var result = OptionCalculatorV1.ValueDoubleSharkFinOptionTrade( marketProxy, valueDate, underlyingTicker, "CommodityFutures", 125, 110, valueDate, "2019-05-06", "Call", "European", 144, 100, true, 120, 20, 20, "AtHit", 100, underlyingTicker + "_VolSurface", 0.035, "Buy", "2019-05-06", participationRate: 1.0, principalRate: 0.0, isAnnualized: false, annualizeFactor: 1.0, callParticipationRate: 1.0, putParticipationRate: 1.0); Assert.AreEqual(125.79272737448922, result.Pv, 1E-8, ""); Assert.AreEqual(20.046036888621188, result.Delta, 1E-8, ""); Assert.AreEqual(7.002952211507818, result.Gamma, 1E-8, ""); Assert.AreEqual(16.58915982588951, result.Vega, 1E-8, ""); Assert.AreEqual(-8.5410348523357555, result.Theta, 1E-8, ""); } [TestMethod] public void ValueDoubleSharkFinOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker = "RB00"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "双鲨期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 110, Notional = 100, trade_double_sharkfin_option = new trade_double_sharkfin_option() { BarrierHigh = 144, BarrierLow = 100, StrikeHigh = 125, StrikeLow = 110, Discrete = "离散", Rebate = 20.0, KnockInOutStatus = "Monitoring" } }; var parameter = new DoubleSharkFinOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatility = 0.2, SpotPrices = new Dictionary() { { underlying.UnderlyingCode, 120.0 } }, RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(125.79272737448922, result.Pv, 1E-8, ""); Assert.AreEqual(20.046036888621188, result.Delta, 1E-8, ""); Assert.AreEqual(7.002952211507818, result.Gamma, 1E-8, ""); Assert.AreEqual(16.58915982588951, result.Vega, 1E-8, ""); Assert.AreEqual(-8.5410348523357555, result.Theta, 1E-8, ""); } [TestMethod] public void ValueSpreadOptionTest() { var valueDate = "2019-04-04"; var underlyingTicker1 = "RB00"; var underlying1 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker1 }; var underlyingTicker2 = "RB01"; var underlying2 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker2 }; var underlyingTicker3 = "RB02"; var underlying3 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker3 }; //创建默认市场,并设置波动率曲面 var marketProxy = new PrebuiltQdpMarketProxy(); var tenors = new string[] { "1D", "2M", "1Y" }; var strikes = new double[] { 0.95, 1.0, 1.05, }; var vols1 = new double[3, 3]; var singleVols1 = new List(); for (var i = 0; i < vols1.GetLength(0); ++i) { for (var j = 0; j < vols1.GetLength(1); ++j) { vols1[i, j] = 0.2; singleVols1.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.2 }); } } var vols2 = new double[3, 3]; var singleVols2 = new List(); for (var i = 0; i < vols2.GetLength(0); ++i) { for (var j = 0; j < vols2.GetLength(1); ++j) { vols2[i, j] = 0.23; singleVols2.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.23 }); } } var vols3 = new double[3, 3]; var singleVols3 = new List(); for (var i = 0; i < vols3.GetLength(0); ++i) { for (var j = 0; j < vols3.GetLength(1); ++j) { vols3[i, j] = 0.25; singleVols3.Add(new SingleVol() { Strike = strikes[j], Expire = tenors[i], Vol = 0.25 }); } } PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var initParam = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying1).SetValueDate(valueDate).Build("MoneynessVol", singleVols1); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam); var initParam2 = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying2).SetValueDate(valueDate).Build("MoneynessVol", singleVols2); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam2); var initParam3 = new VolSurfaceInitParamsBuilder() .SetUnderlying(underlying3).SetValueDate(valueDate).Build("MoneynessVol", singleVols3); new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam3); var payoff = new SpreadOptionPayoff("S1+S2-S3-K"); //计算 var result = OptionCalculatorV1.ValueSpreadOption( marketProxy, valueDate, "CommodityFutures", new string[] { underlyingTicker1, underlyingTicker2, underlyingTicker3 }, payoff.Weights, payoff.SpreadType, new string[] { underlyingTicker1 + "_VolSurface", underlyingTicker2 + "_VolSurface", underlyingTicker3 + "_VolSurface" }, 2900.0, valueDate, "2019-05-06", "Call", "European", new double[] { 2850, 2930, 2987 }, 100.0, 0.035, new double[] { 0.85, 0.9, 0.75 }, "Buy", "2019-05-06", 1.0, false, 1.0); Assert.AreEqual(3712.3651708468392, result.Pv, 1E-8, ""); Assert.AreEqual(29.766132038275828, result.Delta, 1E-8, ""); Assert.AreEqual(0.17244019545614719, result.Gamma, 1E-8, ""); Assert.AreEqual(198.39776415513484, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.030429098001604871, result.Rho, 1E-8, ""); Assert.AreEqual(30.391497575692483, result.Delta2.Value, 1E-8, ""); Assert.AreEqual(0.17016645870171487, result.Gamma2.Value, 1E-8, ""); Assert.AreEqual(257.01927094713324, result.Vega2.Value, 1E-8, ""); Assert.AreEqual(-29.403113571788708, result.Delta3.Value, 1E-8, ""); Assert.AreEqual(0.17698766896501184, result.Gamma3.Value, 1E-8, ""); Assert.AreEqual(-120.56156531622924, result.Vega3.Value, 1E-8, ""); } [TestMethod] public void ValueSpreadOptionTestV2() { var valueDate = "2019-04-04"; var underlyingTicker1 = "RB00"; var underlying1 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker1, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var underlyingTicker2 = "RB01"; var underlying2 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker2, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var underlyingTicker3 = "RB02"; var underlying3 = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), UnderlyingCode = underlyingTicker3, UnderlyingInstrumentType = "CommodityFutures", MaturityDate = new DateTime(2019, 5, 6) }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var trade = new trade() { TradeType = "价差期权", TradeDate = new DateTime(2019, 4, 4), MaturityDate = new DateTime(2019, 5, 6), ExerciseDate = new DateTime(2019, 5, 6), OptionType = "看涨", ExerciseMode = "European", BuySell = "Buy", Strike = 2900, Notional = 100, trade_spread_option = new trade_spread_option() { Payoff = "S1+S2-S3-K", UnderlyingAssetCode1 = underlyingTicker1, UnderlyingAssetCode2 = underlyingTicker2, UnderlyingAssetCode3 = underlyingTicker3, } }; var parameter = new SpreadOptionParameter() { ValueDate = new DateTime(2019, 4, 4), Volatilities = new double[] { 0.2, 0.23, 0.25 }, SpotPrices = new Dictionary() { { underlying1.UnderlyingCode, 2850 }, { underlying2.UnderlyingCode, 2930 }, { underlying3.UnderlyingCode, 2987 } }, RiskFreeRate = 0.035, Correlations = new double[] { 0.85, 0.9, 0.75 } }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying1, parameter); Assert.AreEqual(3712.3651708468392, result.Pv, 1E-8, ""); Assert.AreEqual(29.766132038275828, result.Delta, 1E-8, ""); Assert.AreEqual(0.17244019545614719, result.Gamma, 1E-8, ""); Assert.AreEqual(198.39776415513484, result.Vega, 1E-8, ""); Assert.AreEqual(0, result.Theta, 1E-8, ""); Assert.AreEqual(-0.030429098001604871, result.Rho, 1E-8, ""); Assert.AreEqual(30.391497575692483, result.Delta2.Value, 1E-8, ""); Assert.AreEqual(0.17016645870171487, result.Gamma2.Value, 1E-8, ""); Assert.AreEqual(257.01927094713324, result.Vega2.Value, 1E-8, ""); Assert.AreEqual(-29.403113571788708, result.Delta3.Value, 1E-8, ""); Assert.AreEqual(0.17698766896501184, result.Gamma3.Value, 1E-8, ""); Assert.AreEqual(-120.56156531622924, result.Vega3.Value, 1E-8, ""); } [TestMethod] public void ValueCashFlowTradeTest() { var valueDate = "2020-01-04"; var underlying = new underlying_manager() { QuotationDate = DateTime.Parse(valueDate), MaturityDate = new DateTime(2020, 5, 6) }; var trade = new trade() { TradeType = "现金流交易", StartDate = new DateTime(2020, 1, 4), TradeDate = new DateTime(2020, 1, 4), MaturityDate = new DateTime(2020, 5, 6), BuySell = "Buy", StockEqvNotional = 1000000, trade_cashflow = new trade_cashflow() { ProfitRate = 0.03, RateType = CashFlowRateTypeEnum.年化利率, ProfitDayCount = "Act365", } }; var userId = Guid.NewGuid().ToString(); PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}"); var parameter = new CashFlowTradeParameter() { ValueDate = new DateTime(2020, 1, 4), RiskFreeRate = 0.035 }; var result = ValueCalculator.CalculateTradeValue( userId, trade, underlying, parameter); Assert.AreEqual(999300.87674743345, result.Pv, 1E-8, ""); } [TestMethod] public void GetAddDaysWithPrecisionOfMinuteTest() { //var privateType = new PrivateType(typeof(OptionCalculatorV1)); ////c1: after day close, before night market //var t = new DateTime(2019, 6, 10, 20, 0, 0); //var ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual(0, ttm, DELTA, "c1: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(0, ttm, DELTA, "c1: false"); ////c2: after night market open //t = new DateTime(2019, 6, 10, 21, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 0.5 / 6), ttm, DELTA, "c2: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1, ttm, DELTA, "c1: false"); ////c3: after night market active hour //t = new DateTime(2019, 6, 10, 23, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 2.0 / 6), ttm, DELTA, "c3: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1, ttm, DELTA, "c1: false"); ////c4: before AM trading //t = new DateTime(2019, 6, 10, 8, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 2.0 / 6), ttm, DELTA, "c4: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1, ttm, DELTA, "c4: false"); ////c5: AM trading //t = new DateTime(2019, 6, 10, 9, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 2.5 / 6), ttm, DELTA, "c5: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1 - 0.5 / 4, ttm, DELTA, "c5: false"); ////c6: lunch break //t = new DateTime(2019, 6, 10, 11, 40, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c6-1: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c6-1: false"); //t = new DateTime(2019, 6, 10, 13, 00, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c6-2: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c6-2: false"); ////c7: pm trading //t = new DateTime(2019, 6, 10, 13, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c7-1: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c7-1: false"); //t = new DateTime(2019, 6, 10, 14, 30, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual((1 - 5.5 / 6), ttm, DELTA, "c7-2: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1 - 3.5 / 4, ttm, DELTA, "c7-2: false"); ////c8: after pm trading //t = new DateTime(2019, 6, 10, 15, 00, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual(0, ttm, DELTA, "c8-1: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(0, ttm, DELTA, "c8-1: false"); //t = new DateTime(2019, 6, 10, 20, 00, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual(0, ttm, DELTA, "c8-2: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(0, ttm, DELTA, "c8-2: false"); ////c9: night market just open //t = new DateTime(2019, 6, 10, 21, 00, 0); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true)); //Assert.AreEqual(1, ttm, DELTA, "c9: true"); //ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false)); //Assert.AreEqual(1, ttm, DELTA, "c9: false"); } [TestMethod] public void GetHistoricalPricesTest() { var priceCount = 20; var volCurve = VolCaculator.Instance.GetHistoricalVolCurvePointsEx("I2012", DateTime.Now, priceCount, priceCount, 0.3, 0.7); Assert.IsTrue(volCurve.Points.Count == priceCount); } [TestMethod] public void GetSpotPriceFromBasisSpreadTest() { var valueDate = new DateTime(2020, 7, 24); var maturityDate = new DateTime(2020, 9, 1); var codelist = new List { "Ab00", "Un00", "Ub22" }; var tenors = new List { "1M", "2M", "3M" }; var spreads = new List { 5.0, -3.0, 7.0 }; var isClosePrice = true; var spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(4002.93548387, spotPrice, 1e-8); maturityDate = new DateTime(2020, 8, 24); spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(4005.0, spotPrice, 1e-8); maturityDate = new DateTime(2020, 9, 24); spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(3997.0, spotPrice, 1e-8); maturityDate = new DateTime(2020, 10, 24); spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(4007.0, spotPrice, 1e-8); maturityDate = new DateTime(2020, 11, 24); spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(4007.0, spotPrice, 1e-8); maturityDate = new DateTime(2020, 7, 31); spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads); Assert.AreEqual(4005.0, spotPrice, 1e-8); } [TestMethod] public void CCRService() { var tradeList = DbContextFactory.GetYLDbContext().trade.Where(O => O.TradeStatus == "确认成交" && O.ValidState != "InValid" && O.ExerciseDate >= valuedateBLL.ValueDate).ToList(); new CCRService(OptUserInfo.UnitTestUser).CalculationCCR(tradeList, 2, 485); } } }