using KellermanSoftware.CompareNetObjects; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using YLErp.Commons; using YLErp.DBModels; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Model; namespace YLErp.Modules.TradeModule.OrderModule { /// /// 测试交易保存服务 /// [TestClass] public class OtcTradeSaveServiceTest : YLUnitTestBase { readonly bool _delete = true; readonly CompareLogic _compareLogic; public OtcTradeSaveServiceTest() { _compareLogic = new CompareLogic(new ComparisonConfig { MaxDifferences = 10, DoublePrecision = 5, MembersToIgnore = new List { nameof(trade.id), nameof(trade.EncryptId), nameof(trade.CreateDate), nameof(trade.UnderlyingAssetClass) }, CaseSensitive = false, }); } [TestMethod("测试保存香草期权交易")] public void TestSaveVanillaOption() { var asset = GetAssetUnit(); var client = GetClient(); var uly = GetUnderlyingManager(true); var valueDate = ValueDate; var td = new OtcOptionTradeFullEx { AssetBookName = asset.Name, TraderName = "Admin", ClientNumber = client.Number, ClientName = client.Name, TradeType = "香草期权", TradeNumber = "UAT-" + UniqueTimeId.GetStr(), UnderlyingCode= uly.UnderlyingCode, BuySell="买入", ExerciseMode= "European", OptionType="Put", SpotPrice=12900, IsMoneynessOption="否", Strike= 12900, TradeDate=valueDate, ExerciseDate=valueDate.AddMonths(3), SettlementDate = valueDate.AddMonths(3), Notional = 400, TradeSinglePrice=100, SettlementType=0, ParticipationRate=1, IsAnnualized=false, PrincipalRate=0, NoRiskRate=0.05, DividendRate=0, TradeOpenVolatility=0.1616, TradeCloseVolatility = 0.1616, NumOfSmoothingDays=1, Comments="测试API" }; var td2 = new OtcTradeSaveService(this.OptUser).SaveOptionTradeFromApiOrImport(td, Model.Enum.TradeSourceEnum.WebApiV2); Assert.IsTrue(td.TradeSinglePrice==td2.TradeSinglePrice); } [TestMethod("测试保存亚式期权交易")] public void TestSaveAsianOption() { InnerTest("亚式期权"); } [TestMethod("测试保存二元期权交易")] public void TestSaveBinaryOption() { InnerTest("二元期权"); } [TestMethod("测试保存障碍期权交易")] public void TestSaveBarrierOption() { InnerTest("障碍期权"); } [TestMethod("测试保存双鲨期权交易")] public void TestSaveDoubleSharkfinOption() { InnerTest("双鲨期权"); } [TestMethod("测试保存区间累积期权交易")] public void TestSaveRangeAccOption() { InnerTest("区间累积期权"); } [TestMethod("测试保存气囊结构交易")] public void TestSaveAirBagOption() { InnerTest("气囊结构"); } [TestMethod("测试保存收益增强结构交易")] public void TestSaveUnderlyingEnhanceOption() { InnerTest("收益增强结构"); } [TestMethod("测试保存雪球期权交易")] public void TestSaveSnowballOption() { InnerTest("雪球期权"); } [TestMethod("测试保存凤凰期权交易")] public void TestSaveAutoCallOption() { InnerTest("凤凰期权"); } private void InnerTest(string tradeType) where TExtend : TradeExtendBase { var asset = GetAssetUnit(); var client = GetClient(); var uly = GetUnderlyingManager(true); var valueDate = ValueDate; var td = new OtcOptionTradeFull { AnnualizedEnhanceRate = 0.01, AnnualizedPremiumRate = 0.01, AnnualizeFactor = 100.0 / 244, AnnualizeFactor2 = 0.9, AssetBookName = asset.Name, AssetId = asset.id, AveragingPeriodStartDate = valueDate, BarrierHigh = 1.05, BarrierLow = 0.95, BarrierShift = 10, BarrierType = "双障碍敲出", BasisGap = 1, BasisUnderlyingCode = "RB00", BasisUnderlyingId = uly.id, BonusRate = 0.1, BuySell = "卖出", CalcFlag = 0, CalcId = "CalcId", OptionType = "看涨", CashOrNothingAmount = 500, CashOrNothingAmountHigh = 1000, CashOrNothingAmountHighRate = 0.1, CashOrNothingAmountRate = 0.05, CheckStatus = 0, CheckTradeUpdate = 0, ClientId = client.id, ClientName = client.Name, Comments = "单元测试", ContractVersion = "V2", Coupon = 0.1, CouponBarrier = 1.05, CouponPayType = CouponPayTypeEnum.AtMaturity, CreateDate = valueDate, DividendDate = DateTime.MinValue, DividendRate = 0.1, DurationDays = 10, ExerciseDate = valueDate.AddMonths(3), ExerciseMode = ConsGlobal.ExerciseMode.American, FinalPrice = 3700, GroupId = 1, GroupName = "Test", HasPartialUnWind = 0, HasPayoffLimit = true, HighStrike = 1.05, IncludeCouponAfterKI = true, InitialSpotPriceState = "期初价格已确认", IsAnnualized = true, IsAnnualized2 = true, IsDiscreteMonitored = true, IsFixedCoupon = false, IsMoneynessOption = "是", IsSingleContract = 1, IsTradePricePayType = false, IsUsePremiumRate = true, InitialMargin = 100, KIBarrier = 0.9, KIParticipationRate = 0.1, KIPayoffType = KIPayoffTypeEnum.ToCallSpreadOption, KOBarrier = 1.05, KOObservationDates = valueDate.OtcFormatDate(), KOObservationSettleDates = valueDate.OtcFormatDate(), KOPayoffType = KOPayoffTypeEnum.ToSpreadOption, KORebate = 0.1, KORebateType = RebateTypeEnum.AtEnd, Lots = 10, LowerRange = 0.9, MaturityDate = uly.MaturityDate, MonitorType = "离散", NoRiskRate = 0.05, NumOfSmoothingDays = 10, Notional = 100, ObservationDates = valueDate.OtcFormatDate(), ObservationDateStr = valueDate.OtcFormatDate(), OptDate = OptDate, OptId = UserId, OptName = UserName, OriginalNotional = 100, OriginalStockEqvNotional = 0, PairTrade = "", ParentTradeId = 0, ParticipationRate = 0.5, PayoffType = "DoubleNoTouch", PremiumPayDate = valueDate.AddMonths(3), PremiumRate = 0.1, PricingModel = "", PrincipalRate = 0.05, ProcessOptDate = null, ProcessOrderId = 0, ProcessStatus = "", Rebate = 500, RebateHigh = 1000, RebateRate = 0.05, RebateHighRate = 0.1, RebateType = "AtHit", SentMailCount = 0, SettlementDate = valueDate.AddMonths(3), SettlementType = 0, SpreadStrike = 0.95, SpreadStrike1 = 0.9, SpreadStrikeAtKO = 1.06, SpreadStrikeAtKO1 = 1.01, StartDate = valueDate, StockEqvNotional = 0, StockEqvNotionalMax = 0, StockEqvNotionalReal = 100 * 3600, Strike = 1.002, StrikeGearingFactor = 1, StrikeHigh = 1.02, StrikeType = ConsTrade.AsiaStrikeType.Fixed, StructureIntroduction = "StructureIntroduction", StructureType = "", TradeAmount = 100, TradeDate = valueDate, TradeInstruction = "TradeInstruction", TradeCloseVolatility = 0.5, TradeNumber = "UT-" + Guid.NewGuid().ToString("N"), TradeOpenVolatility = 0.45, TradePremium = 0.03, TraderId = 1, TraderName = "Admin", TradeSavedVol = 0.4, TradeSource = "系统交易", TradeStatus = "新增待确认", TradeType = tradeType, TradeUnit = "吨", TTMDays = null, UnderlyingAssetClass = "螺纹钢", UnderlyingCode = uly.UnderlyingCode, UnderlyingId = uly.id, UnderlyingInstrumentType = uly.UnderlyingInstrumentType, UnderlyingAssetName = uly.UnderlyingName, UnderlyingPrice = null, UnWindDate = null, UnWindNotional = null, UpperRange = 1.1, ValidState = ConsGlobal.Valid, Vol = null, VolType = null, SpotPrice = 3600 }; td.KOObservationDates += "," + td.ExerciseDate.OtcFormatDate(); if (tradeType == "雪球期权" || tradeType == "凤凰期权") { td.IsAnnualized = false; td.AnnualizeFactor = 1; td.MetaDic[nameof(td.AnnualizeFactor)] = "/"; td.ExerciseMode = ConsTrade.ExerciseType.European; td.StockEqvNotionalMax = td.OriginalStockEqvNotional = td.StockEqvNotional = td.StockEqvNotionalReal; var spotPrice = Math.Abs(td.SpotPrice.Value); td.StockEqvNotionalReal = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); td.TradeAmount = td.Notional = spotPrice > 0 ? td.StockEqvNotionalReal / spotPrice : 0; } else { td.MetaDic[nameof(td.AnnualizeFactor)] = "100/244"; if (tradeType == "双鲨期权") { td.ExerciseMode = ConsTrade.ExerciseType.European; } else if (tradeType == "亚式期权") { td.PayoffType = ConsTrade.AsianAverageType.ArithmeticAverage; } td.StockEqvNotionalMax = td.OriginalStockEqvNotional = td.StockEqvNotional = TradeHelper.GetStockEqvNotional(td.StockEqvNotionalReal, td.ParticipationRate, td.AnnualizeFactor); } td.OriginalNotional = td.Notional; td.TradePrice = TradeHelper.GetTradePriceByPremiumRate(td.PremiumRate, td.StockEqvNotional, td.ParticipationRate, td.PrincipalRate, td.AnnualizeFactor,td.BuySell,td.TradeType,false); td.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByPremiumRate(td.PremiumRate, td.SpotPrice); var saved = new OtcTradeSaveService(this).SaveOptionTradesFromTradeEdit(td); td.id = saved.id; var dbTrade = new TradeDetailsQueryService(this).GetOtcTradeFull(saved.TradeNumber); if (_delete) { AddClearSQL("id=" + td.id); AddClearSQL("TradeId=" + td.id); AddClearSQL("TradeId=" + td.id); } var map1 = YLAutoMapper.Map(td); var map2 = YLAutoMapper.Map(dbTrade); ComparisonResult result = _compareLogic.Compare(map1, map2); Assert.IsTrue(result.AreEqual, result.DifferencesString); var tdex1 = YLAutoMapper.Map(td); var tdex2 = YLAutoMapper.Map(dbTrade); Assert.IsTrue(tdex2.TradeId > 0, "TradeId映射失败"); result = _compareLogic.Compare(tdex1, tdex2); Assert.IsTrue(result.AreEqual, result.DifferencesString); } class VanillaTrade : TradeExtendBase { } } }