diff --git a/Framework/YLErp.Core/DBModels/Enums/MarginTypeEnum.cs b/Framework/YLErp.Core/DBModels/Enums/MarginTypeEnum.cs index 9f346bc2..0f6b0ac4 100644 --- a/Framework/YLErp.Core/DBModels/Enums/MarginTypeEnum.cs +++ b/Framework/YLErp.Core/DBModels/Enums/MarginTypeEnum.cs @@ -5,9 +5,6 @@ /// public enum MarginTypeEnum { - [Description("兴业商贸")] - XingYe = -1, - [Description("系统默认")] DEFAULT = 0, @@ -21,10 +18,6 @@ FLOAT = 3, [Description("按浮动盈亏和持仓名义本金")] - FLOATP = 4, - [Description("国投初始预付金锁定模板")] - GuoTouLock = 6, - [Description("国投初始预付金不锁定模板")] - GuoTouNoLock = 5 + FLOATP = 4 } } diff --git a/UnitTestProject/Modules/CalcModules/MarginCalculationTest.cs b/UnitTestProject/Modules/CalcModules/MarginCalculationTest.cs deleted file mode 100644 index 417ae9a4..00000000 --- a/UnitTestProject/Modules/CalcModules/MarginCalculationTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using YLErp.BLL.MarginCalculation; -using YLErp.Modules.DataProviderModule; - -namespace YLErp.Modules.CalcModules -{ - [TestClass] - public class MarginCalculationTest - { - /// - /// 测试招证预付金 - /// - [TestMethod] - public void ZhaoZhengMarginCalculation_RunMarginCalculation() - { - //List tradeList = new List(); - //var db = DbContextFactory.GetYLDbContext(); - //var tradeNumbers = new List() { "CW20221207OP220919005X", "CW20221207OP220919006X" }; - //tradeList.AddRange(db.trade.Where(O => tradeNumbers.Contains(O.TradeNumber))); - var tradeJson = "[{\"MaturityWorkDay\":14,\"ShowNotional\":-1.0,\"MaturityDay\":28,\"TradeOpenVolatilityString\":\"30.00%\",\"ExerciseDateString\":\"2023-02-03\",\"ActualStrike\":5946.0,\"StrikeString\":\"5,946.000000\",\"TradeSinglePriceString\":\"434.2263\",\"TradeDateString\":\"2022-09-19\",\"StockEqvNotionalToShow\":5936.0,\"SettlementTypeDesc\":\"收盘价\",\"StrikeToShow\":\"5,946.000000\",\"CurNotional\":0.0,\"LastDayNotional\":0.0,\"UnWindTimes\":0,\"DividendRatio\":0.0,\"UnderlyingInstrumentTypeCn\":\"商品期货\",\"ExerciseModeCn\":\"欧式\",\"SummaryType\":\"欧式香草看涨\",\"trade_forward\":{\"id\":0,\"TradeId\":0,\"OpenCommission\":0.0,\"AnnualMarginRate\":0.0,\"AnnualStoragePrice\":0.0,\"ForwardValue\":0.0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_asian_option\":{\"StrikeGearingFactor\":1.0,\"EnhancedPrice\":0.0,\"StrikeTypeCn\":\"\",\"PayoffTypeCn\":\"\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_rainbow_option\":{\"Vol2\":0.0,\"UnderlyingCodes\":[null,null],\"Strikes\":[0.0,0.0],\"SpotPrices\":[0.0,0.0],\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_barrier_option\":{\"KnockInOutStatusCn\":\"观察中\",\"IsDiscrete\":false,\"RebateAnnualizedAtKO\":false,\"RebateTypeCn\":\"\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_risky_option\":{\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_binary_option\":{\"RebateTypeCn\":\"\",\"PayoffType\":\"\",\"RebateAnnualizedAtKO\":false,\"UpperBarrierRelative\":\"0\",\"IsDiscreteMonitored\":false,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_spread_option\":{\"Payoff\":\"S1-S2\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_double_sharkfin_option\":{\"KnockInOutStatusCn\":\"观察中\",\"IsDiscrete\":false,\"BarrierHigh\":0.0,\"BarrierLow\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_autocall\":{\"KnockInOutStatusCn\":\"观察中\",\"KOBarrier\":0.0,\"KIBarrier\":0.0,\"CouponBarrier\":0.0,\"Coupon\":0.0,\"IsFixedCoupon\":false,\"CouponPayType\":0,\"CouponPayAtMaturity\":false,\"IncludeCouponAfterKI\":false,\"IsAnnualized2\":false,\"CouponDayCount\":\"Act365\",\"KIPayoffType\":0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_snowball\":{\"IsInitialKnockedIn\":false,\"KnockInOutStatusCn\":\"观察中\",\"KOBarrier\":0.0,\"KIBarrier\":0.0,\"Coupon\":0.0,\"KORebate\":0.0,\"KORebateType\":0,\"IsFixedCoupon\":false,\"KOPayoffType\":0,\"KIPayoffType\":0,\"IsAnnualized2\":false,\"PrepaymentUsed\":false,\"KIObservationType\":0,\"KOBarrierAdjustStep\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_rangeaccrual\":{\"LowerRange\":0.0,\"UpperRange\":0.0,\"BonusRate\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_airbag\":{\"KnockInOutStatusCn\":\"观察中\",\"HighStrike\":0.0,\"HasPayoffLimit\":false,\"Barrier\":0.0,\"KIParticipationRate\":0.0,\"IsDiscreteMonitored\":false,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_accumulator_option\":{\"AccumuTradeAmount\":0.0,\"OriginalAccumuTradeAmount\":0.0,\"AccumuType\":\"\",\"Coupon\":0.0,\"CouponPercent\":false,\"IsFixedCoupon\":false,\"PutMultiplier\":1.0,\"CallMultiplier\":1.0,\"EarlyTerminate\":false,\"AccumulatorStructureType\":0,\"KnockInOutStatusCn\":\"观察中\",\"StrikeGearingFactor\":1.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_swap\":{\"IsGetFloatingProfit\":false,\"GetSwapRate\":0.0,\"GetMarginRate\":0.0,\"IsPayFloatingProfit\":false,\"PaySwapRate\":0.0,\"RateCalcMode\":\"11\",\"IncludeFirstDay\":true,\"PayMarginRate\":0.0,\"AnnualVarIncome\":false,\"SettlementPayType\":0,\"IsTradePriceWhenOpen\":false,\"IsShare\":false,\"GetCountRatio\":0.0,\"PayCountRatio\":0.0,\"GetContractSize\":0.0,\"PayContractSize\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"get_trade_swap_details\":[],\"pay_trade_swap_details\":[],\"trade_underlying_enhance\":{\"AnnualizedEnhanceRate\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_cashflow\":{\"ProfitRate\":0.0,\"RateType\":0,\"DepositType\":0,\"PrepayRatio\":0.0,\"ProfitDayCount\":\"Act365\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_custom\":{\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_swap_gj\":{},\"TradeType\":\"香草期权\",\"TradeSavedVol\":0.3,\"CreateDate\":\"2023-01-04 10:53:42\",\"PairTrade\":\"\",\"TradeSinglePrice\":434.2263,\"GroupName\":\"\",\"NumOfSmoothingDays\":1,\"ParentTradeId\":120471,\"TradeCloseVolatility\":0.3,\"TradeOpenVolatility\":0.3,\"CheckTradeUpdate\":1,\"InitialSpotPrice\":5936.0,\"IsMoneynessOption\":\"否\",\"TradeAmount\":1.0,\"TradeUnit\":\"\",\"StockEqvNotional\":5936.0,\"StockEqvNotionalMax\":5936.0,\"StockEqvNotionalReal\":5936.0,\"VolType\":\"交易\",\"UnderlyingInstrumentType\":\"CommodityFutures\",\"ExerciseDate\":\"2023-02-03 00:00:00\",\"TraderName\":\"初始用户\",\"TraderId\":170,\"Strike\":5946.0,\"UnderlyingId\":31590,\"AssetBookName\":\"保险+期货项目\",\"AssetId\":146,\"Notional\":1.0,\"OptionType\":\"看涨\",\"ExerciseMode\":\"European\",\"NoRiskRate\":0.0121,\"SpotPrice\":5936.0,\"TradeNumber\":\"CW20221207OP220919005X\",\"ClientId\":1558,\"ClientName\":\"张兰\",\"UnderlyingCode\":\"A00\",\"UnderlyingAssetClass\":\"黄大豆1号\",\"TradeDate\":\"2022-09-19 00:00:00\",\"BuySell\":\"买入\",\"StartDate\":\"2022-09-19 00:00:00\",\"MaturityDate\":\"2039-12-31 00:00:00\",\"TradePrice\":434.23,\"TradeStatus\":\"确认成交\",\"ProcessStatus\":\"通过审批\",\"ProcessOrderId\":-2,\"ProcessOrderBranch\":0,\"ProcessOptDate\":\"2023-01-04 10:54:45\",\"SettlementType\":0,\"ValidState\":\"Valid\",\"Lots\":0.1,\"OriginalNotional\":1.0,\"TradeSource\":\"系统交易\",\"OriginalStockEqvNotional\":5936.0,\"OriginalStockEqvNotionalV2\":5936.0,\"IsUsePremiumRate\":false,\"IsTradePricePayType\":false,\"IsAnnualized\":false,\"AnnualizeFactor\":1.0,\"ParticipationRate\":1.0,\"PrincipalRate\":0.0,\"OriginalPrincipalSum\":0.0,\"PrincipalRateWrite\":0.0,\"SettlementDate\":\"2023-02-03 00:00:00\",\"SettlementFlag\":0,\"SettlementFlagStr\":\"否\",\"CalcFlag\":0,\"PremiumPayDate\":\"2022-09-19 00:00:00\",\"PremiumRate\":0.07315133,\"UnderlyingAssetName\":\"黄大豆1号11811合约\",\"OpponentRole\":\"乙方\",\"DurationDays\":138,\"StructureType\":\"自定义黑箱结构\",\"InitialMargin\":0.0,\"MarginTemplateName\":\"系统默认\",\"MarginType\":0,\"MarginRate\":0.0,\"PositionMarginRate\":0.0,\"QuoteCurrency\":\"USD\",\"IsGroup\":2,\"IsNight\":false,\"Propertys\":[],\"OptId\":170,\"OptName\":\"初始用户\",\"OptDate\":\"2023-01-04 10:54:45\",\"IsApproval\":false,\"Warning\":false,\"DividendDate\":\"2000-01-01 00:00:00\",\"CountRatio\":1,\"CallPut\":\"Call\",\"IsMoneynessOptionData\":false,\"MetaDic\":{},\"TradeMultipleType\":\"欧式香草看涨\",\"id\":120468,\"EncryptId\":\"hpVYU8I-FVjdGvlvHAEFzg\"}," + - "{\"MaturityWorkDay\":14,\"ShowNotional\":-1.0,\"MaturityDay\":28,\"TradeOpenVolatilityString\":\"30.00%\",\"ExerciseDateString\":\"2023-02-03\",\"ActualStrike\":5936.0,\"StrikeString\":\"5,936.000000\",\"TradeSinglePriceString\":\"434.2263\",\"TradeDateString\":\"2022-09-19\",\"StockEqvNotionalToShow\":5936.0,\"SettlementTypeDesc\":\"收盘价\",\"StrikeToShow\":\"5,936.000000\",\"CurNotional\":0.0,\"LastDayNotional\":0.0,\"UnWindTimes\":0,\"DividendRatio\":0.0,\"UnderlyingInstrumentTypeCn\":\"商品期货\",\"ExerciseModeCn\":\"欧式\",\"SummaryType\":\"欧式香草看涨\",\"trade_forward\":{\"id\":0,\"TradeId\":0,\"OpenCommission\":0.0,\"AnnualMarginRate\":0.0,\"AnnualStoragePrice\":0.0,\"ForwardValue\":0.0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_asian_option\":{\"StrikeGearingFactor\":1.0,\"EnhancedPrice\":0.0,\"StrikeTypeCn\":\"\",\"PayoffTypeCn\":\"\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_rainbow_option\":{\"Vol2\":0.0,\"UnderlyingCodes\":[null,null],\"Strikes\":[0.0,0.0],\"SpotPrices\":[0.0,0.0],\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_barrier_option\":{\"KnockInOutStatusCn\":\"观察中\",\"IsDiscrete\":false,\"RebateAnnualizedAtKO\":false,\"RebateTypeCn\":\"\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_risky_option\":{\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_binary_option\":{\"RebateTypeCn\":\"\",\"PayoffType\":\"\",\"RebateAnnualizedAtKO\":false,\"UpperBarrierRelative\":\"0\",\"IsDiscreteMonitored\":false,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_spread_option\":{\"Payoff\":\"S1-S2\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_double_sharkfin_option\":{\"KnockInOutStatusCn\":\"观察中\",\"IsDiscrete\":false,\"BarrierHigh\":0.0,\"BarrierLow\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_autocall\":{\"KnockInOutStatusCn\":\"观察中\",\"KOBarrier\":0.0,\"KIBarrier\":0.0,\"CouponBarrier\":0.0,\"Coupon\":0.0,\"IsFixedCoupon\":false,\"CouponPayType\":0,\"CouponPayAtMaturity\":false,\"IncludeCouponAfterKI\":false,\"IsAnnualized2\":false,\"CouponDayCount\":\"Act365\",\"KIPayoffType\":0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_snowball\":{\"IsInitialKnockedIn\":false,\"KnockInOutStatusCn\":\"观察中\",\"KOBarrier\":0.0,\"KIBarrier\":0.0,\"Coupon\":0.0,\"KORebate\":0.0,\"KORebateType\":0,\"IsFixedCoupon\":false,\"KOPayoffType\":0,\"KIPayoffType\":0,\"IsAnnualized2\":false,\"PrepaymentUsed\":false,\"KIObservationType\":0,\"KOBarrierAdjustStep\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_rangeaccrual\":{\"LowerRange\":0.0,\"UpperRange\":0.0,\"BonusRate\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_airbag\":{\"KnockInOutStatusCn\":\"观察中\",\"HighStrike\":0.0,\"HasPayoffLimit\":false,\"Barrier\":0.0,\"KIParticipationRate\":0.0,\"IsDiscreteMonitored\":false,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_accumulator_option\":{\"AccumuTradeAmount\":0.0,\"OriginalAccumuTradeAmount\":0.0,\"AccumuType\":\"\",\"Coupon\":0.0,\"CouponPercent\":false,\"IsFixedCoupon\":false,\"PutMultiplier\":1.0,\"CallMultiplier\":1.0,\"EarlyTerminate\":false,\"AccumulatorStructureType\":0,\"KnockInOutStatusCn\":\"观察中\",\"StrikeGearingFactor\":1.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_swap\":{\"IsGetFloatingProfit\":false,\"GetSwapRate\":0.0,\"GetMarginRate\":0.0,\"IsPayFloatingProfit\":false,\"PaySwapRate\":0.0,\"RateCalcMode\":\"11\",\"IncludeFirstDay\":true,\"PayMarginRate\":0.0,\"AnnualVarIncome\":false,\"SettlementPayType\":0,\"IsTradePriceWhenOpen\":false,\"IsShare\":false,\"GetCountRatio\":0.0,\"PayCountRatio\":0.0,\"GetContractSize\":0.0,\"PayContractSize\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"get_trade_swap_details\":[],\"pay_trade_swap_details\":[],\"trade_underlying_enhance\":{\"AnnualizedEnhanceRate\":0.0,\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_cashflow\":{\"ProfitRate\":0.0,\"RateType\":0,\"DepositType\":0,\"PrepayRatio\":0.0,\"ProfitDayCount\":\"Act365\",\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_custom\":{\"id\":0,\"TradeId\":0,\"EncryptId\":\"D1k5faKQ2YC4qnUw579Wig\"},\"trade_swap_gj\":{},\"TradeType\":\"香草期权\",\"TradeSavedVol\":0.3,\"CreateDate\":\"2023-01-04 10:53:42\",\"PairTrade\":\"\",\"TradeSinglePrice\":434.2263,\"GroupName\":\"\",\"NumOfSmoothingDays\":1,\"ParentTradeId\":120471,\"TradeCloseVolatility\":0.3,\"TradeOpenVolatility\":0.3,\"CheckTradeUpdate\":1,\"InitialSpotPrice\":5936.0,\"IsMoneynessOption\":\"否\",\"TradeAmount\":1.0,\"TradeUnit\":\"\",\"StockEqvNotional\":5936.0,\"StockEqvNotionalMax\":5936.0,\"StockEqvNotionalReal\":5936.0,\"VolType\":\"交易\",\"UnderlyingInstrumentType\":\"CommodityFutures\",\"ExerciseDate\":\"2023-02-03 00:00:00\",\"TraderName\":\"初始用户\",\"TraderId\":170,\"Strike\":5936.0,\"UnderlyingId\":31590,\"AssetBookName\":\"保险+期货项目\",\"AssetId\":146,\"Notional\":1.0,\"OptionType\":\"看涨\",\"ExerciseMode\":\"European\",\"NoRiskRate\":0.0121,\"SpotPrice\":5936.0,\"TradeNumber\":\"CW20221207OP220919006X\",\"ClientId\":1558,\"ClientName\":\"张兰\",\"UnderlyingCode\":\"A00\",\"UnderlyingAssetClass\":\"黄大豆1号\",\"TradeDate\":\"2022-09-19 00:00:00\",\"BuySell\":\"买入\",\"StartDate\":\"2022-09-19 00:00:00\",\"MaturityDate\":\"2039-12-31 00:00:00\",\"TradePrice\":434.23,\"TradeStatus\":\"确认成交\",\"ProcessStatus\":\"通过审批\",\"ProcessOrderId\":-2,\"ProcessOrderBranch\":0,\"ProcessOptDate\":\"2023-01-04 10:54:45\",\"SettlementType\":0,\"ValidState\":\"Valid\",\"Lots\":0.1,\"OriginalNotional\":1.0,\"TradeSource\":\"系统交易\",\"OriginalStockEqvNotional\":5936.0,\"OriginalStockEqvNotionalV2\":5936.0,\"IsUsePremiumRate\":false,\"IsTradePricePayType\":false,\"IsAnnualized\":false,\"AnnualizeFactor\":1.0,\"ParticipationRate\":1.0,\"PrincipalRate\":0.0,\"OriginalPrincipalSum\":0.0,\"PrincipalRateWrite\":0.0,\"SettlementDate\":\"2023-02-03 00:00:00\",\"SettlementFlag\":0,\"SettlementFlagStr\":\"否\",\"CalcFlag\":0,\"PremiumPayDate\":\"2022-09-19 00:00:00\",\"PremiumRate\":0.07315133,\"UnderlyingAssetName\":\"黄大豆1号11811合约\",\"OpponentRole\":\"乙方\",\"DurationDays\":138,\"StructureType\":\"自定义黑箱结构\",\"InitialMargin\":0.0,\"MarginTemplateName\":\"系统默认\",\"MarginType\":0,\"MarginRate\":0.0,\"PositionMarginRate\":0.0,\"QuoteCurrency\":\"USD\",\"IsGroup\":2,\"IsNight\":false,\"Propertys\":[],\"OptId\":170,\"OptName\":\"初始用户\",\"OptDate\":\"2023-01-04 10:54:45\",\"IsApproval\":false,\"Warning\":false,\"DividendDate\":\"2000-01-01 00:00:00\",\"CountRatio\":1,\"CallPut\":\"Call\",\"IsMoneynessOptionData\":false,\"MetaDic\":{},\"TradeMultipleType\":\"欧式香草看涨\",\"id\":120469,\"EncryptId\":\"Sm5h53s-HKd6axDkSIXGGQ\"}]"; - List tradeList = JsonHelper.Deserialize>(tradeJson); - var req = new RunMarginCalculationReq(OptUserInfo.UnitTestUser) - { - CalcMarginType = Enums.CalcMarginTypeEnum.InitialMargin, - PriceProvider = new ManualPriceProvider(new Dictionary() { { "A00", 6300 } }), - realTradeId = 0, - settleDate = new DateTime(2022, 12, 23), - settlementType = SettlementTypeEnum.ClosePrice, - tradeList = tradeList - }; - var tradeSpanList = ZhaoZhengMarginCalculation.Instance.RunMarginCalculation(req); - Assert.IsNotNull(tradeSpanList); - Assert.IsTrue(tradeSpanList.Count == 2); - Assert.IsTrue(tradeSpanList[0].WorstCastClientPayable == 994.80888800181526); - Assert.IsTrue(tradeSpanList[1].WorstCastClientPayable == 1004.274225425179); - } - } -} diff --git a/UnitTestProject/Modules/CalcModules/SwapCalcTest.cs b/UnitTestProject/Modules/CalcModules/SwapCalcTest.cs deleted file mode 100644 index 8b5c3e9b..00000000 --- a/UnitTestProject/Modules/CalcModules/SwapCalcTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -using YLErp.BLL.MarginCalculation; -using YLErp.Modules.DataProviderModule; - -namespace YLErp.Modules.CalcModules -{ - [TestClass] - public class SwapCalcTest - { - [TestMethod] - public void TestCalc1() - { - //var db = DbContextFactory.GetYLDbContext(); - //var td = db.trade.AsNoTracking().FirstOrDefault(n => n.TradeNumber == "SHBX-BX-21051203"); - //var tdswap = db.trade_swap.FirstOrDefault(n => n.TradeId == td.id); - - //var priceProvidr = new ManualPriceProvider(); - //priceProvidr.SetPrice("AG00", 5262); - //var optionValue = PayoffSwapCalcService.CalcValue(td, tdswap, new DateTime(2021, 5, 12), priceProvidr, true); - //Console.WriteLine(optionValue.Pv); - - //priceProvidr = new ManualPriceProvider(); - //priceProvidr.SetPrice("AG00", 5661.36); - //optionValue = PayoffSwapCalcService.CalcValue(td, tdswap, new DateTime(2021, 5, 12), priceProvidr, true); - //Console.WriteLine(optionValue.Pv); - var db = DbContextFactory.GetYLDbContext(); - var td = db.trade.AsNoTracking().FirstOrDefault(n => n.TradeNumber == "CW20180051C3248"); - var date = new DateTime(2022, 5, 30); - var priceProvider = new EodPriceProvider(date); - var req = new RunMarginCalculationReq(OptUserInfo.SystemUser) - { - tradeList = new System.Collections.Generic.List { td }, - settleDate = date, - PriceProvider = priceProvider.GetPriceProvider(), - CalcMarginType = Enums.CalcMarginTypeEnum.EodMargin, - volType = "持仓" - }; - GuoTouMarginCalculation.TradeMargin(req, td); - } - } -} diff --git a/UnitTestProject/Modules/MarginModule/HaiTongMarginTest.cs b/UnitTestProject/Modules/MarginModule/HaiTongMarginTest.cs deleted file mode 100644 index 6d8c0670..00000000 --- a/UnitTestProject/Modules/MarginModule/HaiTongMarginTest.cs +++ /dev/null @@ -1,167 +0,0 @@ -using CsvHelper; -using CsvHelper.Configuration; -using Org.BouncyCastle.Ocsp; -using System.Globalization; -using YLErp.Model.Enum; -using static NPOI.HSSF.Util.HSSFColor; - -namespace YLErp.Modules.MarginModule -{ - [TestClass] - public class HaiTongMarginTest - { - [TestMethod] - public void TestMethod1() - { - var csvFile = Path.Combine(AppContext.BaseDirectory, "Resources\\MarginModule\\tradespans.csv"); - - var config = new CsvConfiguration(CultureInfo.InvariantCulture) { HeaderValidated = null, MissingFieldFound=null }; - using var reader = new StreamReader(csvFile); - using var csv = new CsvReader(reader, config); - var tradeSpans = csv.GetRecords().Where(n => n.ValueDate.Day == 10).ToList(); - var clientSpanNews = new List(); - - if (tradeSpans != null && tradeSpans.Count > 0) - { - var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); - - //海通预付金保底收益率-用来计算名义本金 - double GuaranteedIncome = 0.01; - - var clientGroups = tradeSpans.GroupBy(t => t.ClientId); - - foreach (var clientGroup in clientGroups) - { - var clientRatio = 1.1; - - var underlyingGroup = clientGroup.Where(x => x.IsSingleMargin != true).GroupBy(t => t.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key ?? 0, - ValueDate = DateTime.Today, - //负数代表客户应缴预付金,正数代表客户应收预付金 - Spv1 = -t.Sum(g => g.Spv1), - Spv2 = -t.Sum(g => g.Spv2), - Spv3 = -t.Sum(g => g.Spv3), - Spv4 = -t.Sum(g => g.Spv4), - Spv5 = -t.Sum(g => g.Spv5), - Spv6 = -t.Sum(g => g.Spv6), - Spv7 = -t.Sum(g => g.Spv7), - Spv8 = -t.Sum(g => g.Spv8), - WorstCastClientPayable = -t.Sum(g => g.WorstCastClientPayable), - OptId = 0, - OptName = "ddd", - OptDate = DateTime.Now, - SpanType = 1 - }).ToList(); - - foreach (var item in underlyingGroup) - { - if (clientGroup.Count(m => m.UnderlyingId == item.UnderlyingId && m.ClientId == item.ClientId) > 1) - { - item.SetWorstCastClientPayableMin(); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.TradeId); - var tradeSpansUpdate = new List(); - var tradeSpansReq = new List(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else if (item.WorstCastClientPayable == item.Spv7) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - else if (item.WorstCastClientPayable == item.Spv8) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8); - } - - #endregion - } - else - { - var tradeSpansUpdate = new List(); - tradeSpansUpdate.ForEach(x => x.Comment = "单笔计算"); - } - - //客户信息中追保方向为“单向追保”或“双向追保”的客户: call 看涨 - //(1)Call净名义本金 = 客户Call卖方持仓名义本金 - 客户Call买方持仓名义本金; - //(2)Put净名义本金 = 客户Put卖方持仓名义本金 - 客户Put买方持仓名义本金; - //(3)单品种预付金占用 = max(0, max(∑逐笔交易持仓预付金,(Call净名义本金 + Put净名义本金)*1 % *1.1)); - //(4)预付金占用 =∑单品种预付金占用。 - //客户信息追保方向“对手方单向追保”或“其他”的客户:预付金占用 = 0。 - - //var callsale = clientGroup.Where(m => m.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "买入" && m.trade.OptionType == "看涨").Select(m => m.trade.StockEqvNotional).Sum(); - //var callbuy = clientGroup.Where(m => m.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "卖出" && m.trade.OptionType == "看涨").Select(m => m.trade.StockEqvNotional).Sum(); - //var putsale = clientGroup.Where(m => m.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "买入" && m.trade.OptionType == "看跌").Select(m => m.trade.StockEqvNotional).Sum(); - //var putbuy = clientGroup.Where(m => m.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "卖出" && m.trade.OptionType == "看跌").Select(m => m.trade.StockEqvNotional).Sum(); - - //var StockEqvNotional = (double)((callsale - callbuy + putsale - putbuy) * GuaranteedIncome * clientRatio); - - //if (client.MarginOptionType != (int)MarginOptionEnum.双向追保) - //{ - // item.WorstCastClientPayable = -Math.Max(0, Math.Max(-(double)item.WorstCastClientPayable, StockEqvNotional)); - //} - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = DateTime.Now, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - Spv5 = underlyingGroup.Sum(g => g.Spv5), - Spv6 = underlyingGroup.Sum(g => g.Spv6), - Spv7 = underlyingGroup.Sum(g => g.Spv7), - Spv8 = underlyingGroup.Sum(g => g.Spv8), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - DeltaMargin = 0, - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = 0, - OptName = "ddd", - OptDate = DateTime.Now, - SpanType = 1, - AdditionalWorstCastClientPayable = 0 - }; - - clientSpanNews.Add(clientSpan); - } - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ALQHMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ALQHMarginCalculation.cs deleted file mode 100644 index 270bad17..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ALQHMarginCalculation.cs +++ /dev/null @@ -1,191 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.DBModels.Helpers; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 安粮 - /// - public class ALQHMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly ALQHMarginCalculation Instance; - - static ALQHMarginCalculation() - { - Instance = new ALQHMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private ALQHMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - if (req.tradeList != null && req.tradeList.Count > 0) - { - var tempStockTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); - if (tempStockTradeList.Any()) - { - var stockTradeSpanlist = StockMarginCalculation(req.Clone(tempStockTradeList)); - if (stockTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(stockTradeSpanlist); - } - } - var tempFutureTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); - if (tempFutureTradeList.Any()) - { - var futureTradeSpanlist = FutureMarginCalculation(req.Clone(tempFutureTradeList)); - if (futureTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(futureTradeSpanlist); - } - } - } - return tradeSpans; - } - - /// - /// 股票类期权计算预付金 - /// - private List StockMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - - if (req.tradeList == null || req.tradeList.Count < 1) - { - return tradeSpans; - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; - - foreach (var t in req.tradeList) - { - var client = helper.GetClient(t.ClientId); - if (client == null) - { - continue; - } - //未设置相关预付金系数默认为1.0 - var clientRatio = client?.Ratio ?? 1.0; - //如果是股票去名义本金,如果是期货取:份额 * 即期价格 - var baseValue = (t.StockEqvNotional == 0 ? TradeHelper.GetStockEqvNotional(t.Notional * t.SpotPrice, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotional) * marginRation; - var value = baseValue * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.MarginOptionType == 1 ? -1 : 0)) * clientRatio; - var twoSideMargin = baseValue * (t.BuySell == "买入" ? 1 : -1) * clientRatio; - tradeSpans.Add(new trade_span - { - TradeId = t.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = client.ClientId, - UnderlyingId = t.UnderlyingId, - UnderlyingCode = t.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value, - TwoSideMargin = twoSideMargin - }); - } - - return tradeSpans; - } - - /// - /// 商品期权计算预付金 - /// - public List FutureMarginCalculation(RunMarginCalculationReq req) - { - var futureTradeList = req.tradeList; - var tradeSpans = new List(); - - if (req.tradeList == null || req.tradeList.Count < 1) - { - return tradeSpans; - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - helper.SetFieldsByTradeType(); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: futureTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_GREEKS, - addVolRateDic: null, - volType: req.volType, - settlementType: req.settlementType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != Enums.CalcMarginTypeEnum.EodMargin); - - var deltaCoefficient = valuedateBLL.SystemDate.FutureMarginDeltaCoefficient ?? 1; - var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; - var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; - var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; - - foreach (var item in tradeRiskResult.Results) - { - var tempTrade = futureTradeList.FirstOrDefault(t => t.id == item.Trade.id); - var optionValue = item.ValueResult; - var tempVariety = _underlyingDataProvider.GetVariety(tempTrade.UnderlyingId); - var closePrice = req.PriceProvider.GetPrice(tempTrade.UnderlyingCode); - var client = helper.GetClient(item.Trade.ClientId); - if (tempTrade != null && item.ValueResult != null && tempVariety != null) - { - //未设置相关预付金系数默认为1.0 - var clientRatio = client?.Ratio ?? 1.0; - //预付金 = ( a * DeltaCash + b* GammaCash * PricingVol / 16) * 当前标的预付金率 + c * Vega - var value = ((optionValue.DeltaCash * deltaCoefficient - + optionValue.GammaCash * 0.01 * (optionValue.Vol / 16) * omegaCoefficient) * tempVariety.Margin - + optionValue.Vega * vegaCoefficient - ) * alphaRate * (tempTrade.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.MarginOptionType == 1 ? 1 : 0)) * clientRatio; - var twoSideMargin = ((optionValue.DeltaCash * deltaCoefficient - + optionValue.GammaCash * 0.01 * (optionValue.Vol / 16) * omegaCoefficient) * tempVariety.Margin - + optionValue.Vega * vegaCoefficient - ) * alphaRate * (tempTrade.BuySell == "买入" ? 1 : -1) * clientRatio; - tradeSpans.Add(new trade_span - { - TradeId = tempTrade.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = tempTrade.ClientId, - UnderlyingId = tempTrade.UnderlyingId, - UnderlyingCode = tempTrade.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value, - TwoSideMargin = twoSideMargin - }); - } - } - - return tradeSpans; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var marginReq = req.GetRunMarginCalculationReq(); - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/BHRSMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/BHRSMarginCalculation.cs deleted file mode 100644 index 70f33271..00000000 --- a/YLErpDAL/BLL/MarginCalculation/BHRSMarginCalculation.cs +++ /dev/null @@ -1,550 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.BLL.Eod; -using YLErp.DBModels.Helpers; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 渤海荣盛 - /// - public class BHRSMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly BHRSMarginCalculation Instance; - - static BHRSMarginCalculation() - { - Instance = new BHRSMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private BHRSMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - - if (req?.tradeList == null || !req.tradeList.Any()) - { - return tradeSpans; - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - var tempStockTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); - if (tempStockTradeList.Any()) - { - var stockTradeSpanlist = StockMarginCalculation(req.Clone(tempStockTradeList), helper); - if (stockTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(stockTradeSpanlist); - } - } - - var tempFutureTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); - if (tempFutureTradeList.Any()) - { - - var tradeList = tempFutureTradeList.Where(a => a.TradeType != "远期").ToList(); - if (tradeList.Any()) - { - req = req.Clone(tradeList); - var futureTradeSpanlist = FutureMarginCalculation(req, helper); - if (futureTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(futureTradeSpanlist); - } - } - - var forwardTradeList = tempFutureTradeList.Where(a => a.TradeType == "远期").ToList(); - if (forwardTradeList.Any()) - { - req = req.Clone(forwardTradeList); - var futureTradeSpanlist = ForwardMarginCalculation(req, helper); - if (futureTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(futureTradeSpanlist); - } - } - } - return tradeSpans; - } - - /// - /// 股票类期权计算预付金 - /// - private List StockMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper) - { - var tradeSpans = new List(); - - if (req?.tradeList == null || !req.tradeList.Any()) - { - return tradeSpans; - } - - var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; - - foreach (var t in req.tradeList) - { - var client = helper.GetClient(t.ClientId); - - if (client == null) - { - continue; - } - - double twoSideMargin; - - if (helper.GetSpecialMargin(t, 0, out var value)) - { - twoSideMargin = value; - } - else - { - var clientRatio = client?.Ratio ?? 1.0; - //如果是股票去名义本金,如果是期货取:份额 * 即期价格 - var baseValue = (t.StockEqvNotional == 0 ? TradeHelper.GetStockEqvNotional(t.Notional * t.SpotPrice, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotional) * marginRation; - value = baseValue * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.MarginOptionType == 1 ? -1 : 0)) * clientRatio; - twoSideMargin = baseValue * (t.BuySell == "买入" ? 1 : -1) * clientRatio; - } - - tradeSpans.Add(new trade_span - { - TradeId = t.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = client.ClientId, - UnderlyingId = t.UnderlyingId, - UnderlyingCode = t.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value, - TwoSideMargin = twoSideMargin - }); - } - - return tradeSpans; - } - /// - /// 商品期权计算预付金 - /// - private List FutureMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper) - { - var futureTradeList = req.tradeList; - var tradeSpans = new List(); - using (var db = new YLContext()) - { - if (!req.hasOptionInfo) - { - tradeBLL.SetFieldsByTradeType(futureTradeList); - } - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: futureTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_GREEKS, addVolRateDic: null, - volType: req.volType, - settlementType: req.settlementType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - logger.Info($"商品期货预付金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); - - //计算预付金包含错误信息时弹出错误信息 - if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) - { - throw new Exception(tradeRiskResult.ErrorMessage); - } - - if (tradeRiskResult.Results.Count < 1) - { - return tradeSpans; - } - - var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; - var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; - var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; - - foreach (var item in tradeRiskResult.Results) - { - var tempVariety = _underlyingDataProvider.GetVariety(item.Trade.UnderlyingCode); - double closePrice = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.None: - case CalcMarginTypeEnum.EodMargin: - closePrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - break; - case CalcMarginTypeEnum.InitialMargin: - closePrice = item.Trade.SpotPrice ?? 0; - break; - default: - break; - } - - var client = helper.GetClient(item.Trade.ClientId); - if (item.ValueResult == null) - { - throw new Exception("PV结算结果为null"); - } - - var deltaMerge = item.ValueResult.Delta; - var vegaMerge = item.ValueResult.Vega; - var gammaMerge = item.ValueResult.Gamma; - var pvMerge = item.ValueResult.Pv; - - var PositionPnl = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? 0 : - pvMerge - (EodOperationBase.GetPositionCost(item.Trade.TradePrice ?? 0, item.Trade.Notional, item.Trade.OriginalNotional ?? 0, item.Trade.BuySell)); - - PositionPnl = PositionPnl > 0 ? PositionPnl : 0; - - bool isTwoSide = HasTwoSideMargin(item.Trade.ClientId); - //逐笔预付金算法 - var margin = MarginAlgorithm(deltaMerge, pvMerge, closePrice, isTwoSide, tempVariety.Margin ?? 0, item.Trade, PositionPnl); - - if (item.Trade.TradeType == "自定义交易") - { - if (helper.GetSpecialMargin(item.Trade, 0, out var value)) - { - margin = value; - } - } - - tradeSpans.Add(new trade_span - { - TradeId = item.Trade.id,//默认记录为第一条交易记录中 - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = item.Trade.ClientId, - ValueDate = req.settleDate, - UnderlyingId = item.Trade.UnderlyingId, - UnderlyingCode = item.Trade.UnderlyingCode, - DeltaMargin = margin, - WorstCastClientPayable = margin, - Comment = $"delta:{deltaMerge},closePrice:{closePrice},pv:{pvMerge}" + - $",gamma{gammaMerge},交易员方向:{item.Trade.BuySell},持仓盈亏:{PositionPnl},预付金率:{tempVariety.Margin},单双向:{client.MarginOptionType}" - }); - - } - return tradeSpans; - } - } - - private List ForwardMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper) - { - var futureTradeList = req.tradeList; - var tradeSpans = new List(); - using (var db = new YLContext()) - { - if (!req.hasOptionInfo) - { - tradeBLL.SetFieldsByTradeType(futureTradeList); - } - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: futureTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_GREEKS, addVolRateDic: null, - volType: req.volType, isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - logger.Info($"远期预付金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); - - //计算预付金包含错误信息时弹出错误信息 - if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) - { - throw new Exception(tradeRiskResult.ErrorMessage); - } - - if (tradeRiskResult.Results.Count < 1) - { - return tradeSpans; - } - var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; - var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; - var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; - //如果持仓中的所有远期delta方向相同,那么无视delta方向,每笔远期交易都按照delta绝对值计算margin; - bool IsDeltaMerge = tradeRiskResult.Results.All(a => a.ValueResult.Delta >= 0) || tradeRiskResult.Results.All(a => a.ValueResult.Delta <= 0); - - var tradeIds = futureTradeList.Where(O => O.id > 0).Select(O => O.id); - var tradeCashDict = - db.trade_cash.Where(O => tradeIds.Contains(O.TradeId) && O.ValidState != "InValid" && !O.IsDeleted && O.Action != ClientCashInCashOut.系统操作_期权费) - .AsEnumerable() - .GroupBy(O => O.TradeId) - .ToDictionary(K => K.Key, V => V.ToList()); - - var marginCostDict = db.eod_forward_margin.Where(x => x.ValueDate == req.settleDate && tradeIds.Contains(x.TradeId)) - .AsEnumerable() - .GroupBy(O => O.TradeId) - .ToDictionary(K => K.Key, V => V.FirstOrDefault()?.MarginCost ?? 0); - - foreach (var item in tradeRiskResult.Results) - { - var tempVariety = _underlyingDataProvider.GetVariety(item.Trade.UnderlyingCode); - double closePrice = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.None: - case CalcMarginTypeEnum.EodMargin: - closePrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - break; - case CalcMarginTypeEnum.InitialMargin: - closePrice = item.Trade.SpotPrice ?? 0; - break; - default: - break; - } - - if (item.ValueResult == null) - { - throw new Exception("PV结算结果为null"); - } - - var deltaMerge = item.ValueResult.Delta; - var vegaMerge = item.ValueResult.Vega; - var gammaMerge = item.ValueResult.Gamma; - var pvMerge = item.ValueResult.Pv; - var marginCost = marginCostDict.TryGetValue(item.Trade.id, out var margincost) ? margincost : 0; - var unwindTradeCashList = tradeCashDict.TryGetValue(item.Trade.id, out var cashList) ? cashList : new List(); - //平仓比例 - double unwindRatio = unwindTradeCashList.Any() ? unwindTradeCashList.Sum(a => a.UnwindNotional.Value) / item.Trade.OriginalNotional.Value : 0; - //持仓比例 - double positionRatio = 1 - unwindRatio; - //持仓盈亏 = 持仓市值+开仓总费用 * 持仓比例 - var pnl = pvMerge + item.Trade.TradePrice.Value * positionRatio + marginCost; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}持仓盈亏 = 持仓市值 + 开仓总费用 * 持仓比例"); - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}PnL = {pvMerge} + {item.Trade.TradePrice.Value} * {positionRatio} + {marginCost}"); - pnl = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? 0 : Math.Max(0, pnl); - - deltaMerge = IsDeltaMerge ? Math.Abs(deltaMerge) : deltaMerge; - //预付金计算公式: delta * 标的收盘价 * 交易所预付金率 + 客户亏损部分 - double value = deltaMerge * closePrice * (tempVariety.Margin ?? 0) + pnl; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金计算公式: delta * 标的收盘价 * 交易所预付金率 + 客户亏损部分"); - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = {deltaMerge} * {closePrice} * {(tempVariety.Margin ?? 0)} + {pnl}"); - - tradeSpans.Add(new trade_span - { - TradeId = item.Trade.id,//默认记录为第一条交易记录中 - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = item.Trade.ClientId, - ValueDate = req.settleDate, - UnderlyingId = item.Trade.UnderlyingId, - UnderlyingCode = item.Trade.UnderlyingCode, - DeltaMargin = value, - WorstCastClientPayable = value, - Comment = $"远期交易,delta:{deltaMerge},closePrice:{closePrice},pv:{pvMerge}" + - $",gamma{gammaMerge},交易员方向:{item.Trade.BuySell},预付金率:{tempVariety.Margin}" - }); - } - - } - return tradeSpans; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = req.tradeSpans.AsEnumerable().GroupBy(t => t.ClientId); - - foreach (var clientGroup in clientGroups) - { - - List clientSpans = new List(); - - var tradeSpanGroup = clientGroup.ToList(); - var tradeIds = tradeSpanGroup.Select(a => a.TradeId).ToList(); - - var notForwardTrades = db.trade.Where(a => tradeIds.Contains(a.id) && a.TradeType != "远期").ToList(); - - #region 非远期 - if (notForwardTrades.Any()) - { - var notForwardTradeIds = notForwardTrades.Select(a => a.id); - //双向追保,客户只有买入交易 则预付金为0 - if (notForwardTrades.All(a => a.BuySell == "卖出") && HasTwoSideMargin(clientGroup.Key ?? 0)) - { - - var tradeSpansUpdate = db.trade_span.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - DeltaMargin = 0, - WorstCastClientPayable = 0 - }; - clientSpans.Add(clientSpan); - } - else - { - var umTradeSpanGroup = tradeSpanGroup.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).AsEnumerable().GroupBy(a => a.UnderlyingId); - var umClientSpans = new List(); - - foreach (var umTrade in umTradeSpanGroup) - { - var umClientSpan = new ClientSpan - { - UnderlyingId = umTrade.Key, - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - DeltaMargin = umTrade.Sum(u => u.DeltaMargin) * (-1) - }; - - umClientSpans.Add(umClientSpan); - } - var notForwardClientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - DeltaMargin = umClientSpans.Sum(g => g.DeltaMargin), - WorstCastClientPayable = umClientSpans.Sum(g => g.DeltaMargin) - }; - clientSpans.Add(notForwardClientSpan); - } - } - #endregion - #region 远期 - var forwardTrades = db.trade.Where(a => tradeIds.Contains(a.id) && a.TradeType == "远期").ToList(); - if (forwardTrades.Any()) - { - var forwardTradeIds = forwardTrades.Select(a => a.id); - var forwardTradeSpans = tradeSpanGroup.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate); - - var margin = Math.Abs((forwardTradeSpans.Sum(g => g.DeltaMargin) ?? 0)) * -1; - var forwardClientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - DeltaMargin = margin, - WorstCastClientPayable = margin - }; - clientSpans.Add(forwardClientSpan); - - var tradeSpansUpdate = db.trade_span.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - if (margin > 0) - { - tradeSpansUpdate.ForEach(a => a.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(a => a.WorstCastClientPayable = 0); - } - } - #endregion - - var item = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - DeltaMargin = clientSpans.Sum(g => g.DeltaMargin), - WorstCastClientPayable = clientSpans.Sum(g => g.DeltaMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 - }; - clientSpanNews.Add(item); - - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - - - if (clientSpanNews.Count > 0) - { MySqlBulkExtensions.BulkInsert(db, clientSpanNews); } - db.SaveChanges(); - return req.tradeSpans; - } - } - - /// - /// 预付金算法 - /// - /// - public double? MarginAlgorithm(double deltaMerge, double pvMerge, double closePrice, bool isTwoSide, double Margin, trade tradeModel, double PositionPnl) - { - //交易员买入 delta为正,卖出为负 - deltaMerge = tradeModel.BuySell == "买入" ? Math.Abs(deltaMerge) : -Math.Abs(deltaMerge); - var value = 0.0; - // 预付金 = delta(交易员方向delta) * 标的收盘价 * 交易所预付金率 + 持亏(交易员方向) - value = deltaMerge * closePrice * Margin + PositionPnl; - - if (tradeModel.BuySell == "卖出" && !isTwoSide)//单向 客户买入 - { - value = 0; - } - - return value; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/BXMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/BXMarginCalculation.cs deleted file mode 100644 index abbdfc76..00000000 --- a/YLErpDAL/BLL/MarginCalculation/BXMarginCalculation.cs +++ /dev/null @@ -1,320 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules.CalculationModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 伴兴预付金计算 - /// - public class BXMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly BXMarginCalculation Instance; - - static BXMarginCalculation() - { - Instance = new BXMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected BXMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var resultMap = new List(); - - var list2 = new List(req.tradeList.Count); - - foreach (var td in req.tradeList) - { - if (td.InitialMargin != null && td.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) - { - var initMargin = td.InitialMargin * (td.Notional / td.OriginalNotional); - var ts = new trade_span() - { - TradeId = td.id, - ClientId = td.ClientId, - ValueDate = req.settleDate, - UnderlyingId = td.UnderlyingId, - UnderlyingCode = td.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - Spv1 = initMargin, - Spv2 = initMargin, - Spv3 = initMargin, - Spv4 = initMargin, - }; - ts.SetWorstCastClientPayable(); - resultMap.Add(ts); - } - else - { - list2.Add(td); - } - } - - resultMap.AddRange(marginCalculation(req.Clone(list2))); - - return resultMap; - } - - private List marginCalculation(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - helper.SetFieldsByTradeType(); - - using (var db = new YLContext()) - { - helper.GetTradVolRateDic(out var tradeVolRateDic, t => - { - var pclass = helper.GetClient(t.ClientId)?.ProperClientClass; - return pclass != null && pclass.Contains("普通投资者") ? 0.02 : 0; - }); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - - var prices = new (string, IPriceProvider)[] { - ("up", upLimitPrices), - ("down", downLimitPrices) - }; - - foreach (var price in prices) - { - foreach (var addVolRateDic in new[] { null, tradeVolRateDic }) - { - var key = $"{price.Item1}_{(addVolRateDic == null ? 0 : 1)}"; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: req.tradeList, - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: addVolRateDic, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - - if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) - { - foreach (var item in tradeRiskResult.Results) - { - var client = helper.GetClient(item.Trade); - var clientRatio = client?.Ratio ?? 1.0; - - var pv = item.ValueResult.Pv; - - //if (item.Trade.TradeType == "收益互换") - //{ - // var getclosePrice = req.PriceProvider.GetPrice(item.Trade.trade_swap.GetUnderlyingCode); - // UpdownLimit getprice = helper.GetUpDownLimit(item.Trade.trade_swap.GetUnderlyingCode, getclosePrice); - - // var payclosePrice = req.PriceProvider.GetPrice(item.Trade.trade_swap.PayUnderlyingCode); - // UpdownLimit payprice = helper.GetUpDownLimit(item.Trade.trade_swap.PayUnderlyingCode, payclosePrice); - - // TradeValueResult optionValue = null; - - // if (key == "up_0") - // { - // var priceProvidr = new ManualPriceProvider(); - // priceProvidr.SetPrice(item.Trade.trade_swap.GetUnderlyingCode, getprice.UpLimitPrice); - // priceProvidr.SetPrice(item.Trade.trade_swap.PayUnderlyingCode, payprice.UpLimitPrice); - - // optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, null, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin); - - // optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, priceProvidr, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin); - // } - // else if (key == "down_0") - // { - // var priceProvidr = new ManualPriceProvider(); - // priceProvidr.SetPrice(item.Trade.trade_swap.GetUnderlyingCode, getprice.DownLimitPrice); - // priceProvidr.SetPrice(item.Trade.trade_swap.PayUnderlyingCode, payprice.DownLimitPrice); - // optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, priceProvidr, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin); - // } - // pv = optionValue == null ? 0 : optionValue.Pv; - //} - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) - { - value = item.Trade.InitialMargin ?? 0; - } - else - { - value = GetMargin(item.Trade, item.ValueResult, clientRatio); - } - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - - var value2 = (double)tempTradeSpan.WorstCastClientPayable; - - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - value2 = item.Trade.BuySell == "卖出" ? 0 : Math.Max(value2, 0); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保) - { - value2 = item.Trade.BuySell == "卖出" ? Math.Min(value2, 0) : 0; - } - tempTradeSpan.WorstCastClientPayable = value2; - - } - } - } - } - } - - return resultMap.Values.ToList(); - } - } - - private double GetMargin(trade trade, TradeValueResult valueResult, double clientRatio) - { - var value = 0.0; - - //预付金不再传入结构化主交易数据 - //if (trade.TradeType == "结构化交易") - //{ - // if (trade.StructureType != null && trade.StructureType.Contains("跨式")) - // { - // value = valueResult.MaxAbsPv; - // } - // else - // { - // value = valueResult.SellPv; - // } - //} - - if (trade.TradeType != "自定义交易") - { - value = valueResult.Pv; - } - - return (double.IsNaN(value) ? 0 : value) * clientRatio; - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); - foreach (var clientGroup in clientGroups) - { - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - Spv1 = -clientGroup.Sum(g => g.Spv1), - Spv2 = -clientGroup.Sum(g => g.Spv2), - Spv3 = -clientGroup.Sum(g => g.Spv3), - Spv4 = -clientGroup.Sum(g => g.Spv4), - WorstCastClientPayable = -clientGroup.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 - }; - clientSpanNews.Add(clientSpan); - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - - - if (clientSpanNews.Count > 0) - { MySqlBulkExtensions.BulkInsert(db, clientSpanNews); } - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - - if (trade.TradeType == "结构化交易" && trade.id > 0) - { - using (var db = new YLContext()) - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ChangJiangMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ChangJiangMarginCalculation.cs deleted file mode 100644 index 94e02960..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ChangJiangMarginCalculation.cs +++ /dev/null @@ -1,1369 +0,0 @@ -using Qdp.Foundation.Implementations; -using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix; -using Qdp.Pricing.Library.Options.Products.Autocall.Snowball; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.BLL.Calculation.V2; -using YLErp.DBModels.Helpers; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Models; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.Modules.VolatilityModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - class ChangJiangMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly ChangJiangMarginCalculation Instance; - - static ChangJiangMarginCalculation() - { - Instance = new ChangJiangMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected ChangJiangMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - return RunMarginCalculationForCommodity(helper); - } - - //商品类预付金计算 - private static List RunMarginCalculationForCommodity(RunMarginCalculationHelper helper) - { - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - var resultMap = new Dictionary(); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - helper.GetTradVolRateDic(out var tradeVolRateDic); - - helper.GetMarginTradVolRateDic(out var tradeMarginVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string key, IPriceProvider priceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", helper.req.PriceProvider) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.key, - priceProvider = n.priceProvider, - addVolRateDic = m - })).ToArray(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: tradeMarginVolRateDic); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value, helper.req.forOtherSide)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "normal_0": - tempTradeSpan.Spv = pv; - tempTradeSpan.Delta = item.ValueResult.Delta; - tempTradeSpan.UnderlyingPrice = helper.req.PriceProvider.GetPrice(item.ValueResult.UnderlyingCode); - mpProvider.TryGetMarginRate(item.ValueResult.UnderlyingCode, out var marginRate); - tempTradeSpan.DeltaMargin = (Math.Abs(tempTradeSpan.Delta ?? 0) * (item.Trade.BuySell == "买入" ? 1 : -1) * tempTradeSpan.UnderlyingPrice * marginRate) ?? 0; - break; - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - - tempTradeSpan.IsSpanMargin = true; - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - //获取收盘日那天对应的预付金模板 - var tradeTemplates = db.trade_margin_template.AsNoTracking().Where(t => tradeIds.Contains(t.TradeId) && t.ValueDate <= req.settleDate); - var groupQuery = from tt in tradeTemplates - group tt by tt.TradeId into tts - select new - { - TradeId = tts.Key, - ValueDate = tts.Max(n => n.ValueDate) - }; - var groupTemplates = from gq in groupQuery - join tt in tradeTemplates - on new { gq.TradeId, gq.ValueDate } equals new { tt.TradeId, tt.ValueDate } - select tt; - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, tradetemplate }).ToList(); - - //商品类预付金计算 - if (!PS.Config.ErpElement.IsStockMargin) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var spans = req.tradeSpansOtherSide != null - ? req.tradeSpansOtherSide.Where(n => n != null).ToArray() : Enumerable.Empty(); - var tradeSpanInfoOtherSide = (from tradeSpan in spans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var clientTradeSpans = clientGroup.ToList(); - //交易员方向持仓盈亏 - var positionWinLoss = clientTradeSpans.Sum(x => (x.tradeSpan.Spv ?? 0) + (x.trade.TradePrice * x.trade.Notional / x.trade.OriginalNotional * ((x.trade.BuySell == "卖出") ? 1 : -1) ?? 0)); - - var underlyingGroupDefault = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).AsEnumerable().GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroupDefault) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - - #endregion - } - - var underlyingGroup = clientGroup.AsEnumerable().GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1) - }).ToList(); - - foreach (var item in underlyingGroup) - { - if (!HasTwoSideMargin(clientGroup.Key)) - { - item.DeltaMargin = Math.Min(item.DeltaMargin ?? 0, 0); - } - } - - //客户方向delta预付金 - var deltaMargin = underlyingGroup.Sum(g => (g.DeltaMargin ?? 0)) - positionWinLoss; - if (!HasTwoSideMargin(clientGroup.Key)) - { - deltaMargin = Math.Min(deltaMargin, 0); - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroupDefault.Sum(g => g.Spv1), - Spv2 = underlyingGroupDefault.Sum(g => g.Spv2), - Spv3 = underlyingGroupDefault.Sum(g => g.Spv3), - Spv4 = underlyingGroupDefault.Sum(g => g.Spv4), - //负数代表客户应缴预付金,正数代表客户应收预付金 - DeltaMargin = deltaMargin, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroupDefault.Sum(g => g.WorstCastClientPayable), - MySideMargin = underlyingGroupDefault.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroupDefault.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - clientSpanNews.Add(clientSpan); - } - - //处理从客户角度的预付金计算(将交易买卖方向反向处理) - var clientGroupsOtherSide = tradeSpanInfoOtherSide.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroupsOtherSide) - { - var underlyingGroup = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0 }.Min(); - } - var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate); - clientSpan.OtherSideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable); - - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.OtherSideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.OtherSideMargin = Math.Min(clientSpan.OtherSideMargin ?? 0, 0); - - if (HasTwoSideMargin(clientGroup.Key)) - { - clientSpan.WorstCastClientPayable = clientSpan.MySideMargin - clientSpan.OtherSideMargin; - } - } - } - } - //权益类预付金计算 - else - { - var defaultMarginTemplates = db.margin_template_v2.Where(x => x.IsDefault && !x.IsForClient).ToList(); - var groupMarginTemplates = db.margin_template_v2.Where(x => !x.IsDefault && x.MarginType == (int)MarginTypeV2Enum.多腿).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var clientTradeSpans = clientGroup.ToList(); - //交易员方向持仓盈亏 - var positionWinLoss = clientTradeSpans.Sum(x => (x.tradeSpan.Spv ?? 0) + (x.trade.TradePrice * x.trade.Notional / x.trade.OriginalNotional * ((x.trade.BuySell == "卖出") ? 1 : -1) ?? 0)); - - var clientGroupICIHIF = clientGroup.Where(x => x.tradeSpan.IsSpanMargin == true); - var clientGroupOther = clientGroup.Where(x => x.tradeSpan.IsSpanMargin != true); - - //交易员方向,正数代表交易员收预付金 - var worstCastClientPayable = 0.0; - var groupTradeIds = new List(); - - #region 默认组合的交易类型的交易处理 - - //客户级别默认预付金规则 - var clientMarginTemplates = (from cmt in db.client_margin_template.Where(x => x.ClientId == clientGroup.Key && x.ValueDate <= req.settleDate) - join mtv in db.margin_template_v2 - on cmt.MarginTemplateId equals mtv.id - select new { cmt, mtv }).ToList(); - - var defaultTradeTypesDone = new List(); - if (clientMarginTemplates.Any()) - { - var valueDate = clientMarginTemplates.Max(x => x.cmt.ValueDate); - clientMarginTemplates = clientMarginTemplates.Where(x => x.cmt.ValueDate == valueDate).ToList(); - clientMarginTemplates.ForEach(x => - { - var marginDetail = db.margin_template_detail.Where(y => y.MarginTemplateId == x.mtv.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null && (x.mtv.RuleType != (int)MarginRuleTypeEnum.无预付金 && x.mtv.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && x.mtv.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && x.mtv.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.mtv.Name)); - } - - if (x.mtv.RuleType == (int)MarginRuleTypeEnum.类香草预付金规则) - { - var groupRatio = marginDetail.GroupRatio ?? 0; - var stockEqvNotional = marginDetail.StockEqvNotional ?? 0; - var singleStockEqvNotional = marginDetail.SingleStockEqvNotional ?? 0; - var amount = marginDetail.PositionUnderlyingAmount ?? 0; - - //香草期权只考虑交易员买入的交易,卖出的交易不需要考虑预付金 - var tradeVanillaSpanInfo = clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin != true); - //自定义预付金 - var tradeVanillaSpanInfoSingle = clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin == true); - var umdStockEqvNotional = tradeVanillaSpanInfo.GroupBy(y => y.trade.UnderlyingId).Select(t => new - { - UnderlyingId = t.Key, - StockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor)), - PositionStockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor) * g.tradeSpan.UnderlyingPrice / g.trade.SpotPrice) - }).ToList(); - var underlyingIds = umdStockEqvNotional.Select(y => y.UnderlyingId); - var totalStockEqvNotional = umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional); - if (totalStockEqvNotional >= stockEqvNotional && umdStockEqvNotional.Any(y => y.PositionStockEqvNotional >= singleStockEqvNotional) && underlyingIds.Count() >= amount) - { - //获取组合持仓名义本金和初始名义本金的较高者 - var maxStockEqvNotional = Math.Max(umdStockEqvNotional.Sum(y => y.StockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.StockEqvNotional), umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.PositionStockEqvNotional ?? 0)); - - var groupMargins = maxStockEqvNotional * groupRatio + tradeVanillaSpanInfo.Sum(y => y.tradeSpan.PositionWin ?? 0); - worstCastClientPayable += groupMargins; - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeVanillaSpanInfo.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeVanillaSpanInfo.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else - { - worstCastClientPayable += tradeVanillaSpanInfo.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeVanillaSpanInfoSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroupOther.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2 && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroupOther.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if ((x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 || x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.指数) - { - //指数类交易 - var clientGroupIndex = clientGroupOther.Where(y => (y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - worstCastClientPayable += clientGroupIndex.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - //初始预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金比例 - var redeemRatio2 = marginDetail.MarginRatio3 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体涨跌跌幅时需要判断单个标的的涨跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax && marginDetail.PriceLimitType == 0 || (y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax && marginDetail.PriceLimitType == 1 ? (y.trade.SpotPrice * (1 + (marginDetail.PriceLimitType == 0 ? -1 : 1) * redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - if (groupStrikeWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupStrikeWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupStrikeWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - //不满足追加比例时,用初始预付金 - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else - { - worstCastClientPayable += clientGroupOther.Where(y => x.mtv.TradeTypes.Contains(y.trade.TradeType) && y.tradetemplate == null).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - defaultTradeTypesDone.AddRange(x.mtv.TradeTypes.Split(',')); - }); - } - - //系统默认预付金规则(客户级别有过默认规则的交易类型对应的默认交易需要被排除) - defaultMarginTemplates.ForEach(x => - { - var clientGroupOtherRemain = clientGroupOther.Where(y => !defaultTradeTypesDone.Contains(y.trade.TradeType)); - var marginDetail = db.margin_template_detail.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null && (x.RuleType != (int)MarginRuleTypeEnum.无预付金 && x.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && x.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && x.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.Name)); - } - - if (x.RuleType == (int)MarginRuleTypeEnum.类香草预付金规则) - { - var groupRatio = marginDetail.GroupRatio ?? 0; - var stockEqvNotional = marginDetail.StockEqvNotional ?? 0; - var singleStockEqvNotional = marginDetail.SingleStockEqvNotional ?? 0; - var amount = marginDetail.PositionUnderlyingAmount ?? 0; - - //香草期权只考虑交易员买入的交易,卖出的交易不需要考虑预付金 - var tradeVanillaSpanInfo = clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin != true); - //自定义预付金 - var tradeVanillaSpanInfoSingle = clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin == true); - var umdStockEqvNotional = tradeVanillaSpanInfo.GroupBy(y => y.trade.UnderlyingId).Select(t => new - { - UnderlyingId = t.Key, - StockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor)), - PositionStockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor) * g.tradeSpan.UnderlyingPrice / g.trade.SpotPrice) - }).ToList(); - var underlyingIds = umdStockEqvNotional.Select(y => y.UnderlyingId); - var totalStockEqvNotional = umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional); - if (totalStockEqvNotional >= stockEqvNotional && umdStockEqvNotional.Any(y => y.PositionStockEqvNotional >= singleStockEqvNotional) && underlyingIds.Count() >= amount) - { - //获取组合持仓名义本金和初始名义本金的较高者 - var maxStockEqvNotional = Math.Max(umdStockEqvNotional.Sum(y => y.StockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.StockEqvNotional), umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.PositionStockEqvNotional ?? 0)); - var groupMargins = maxStockEqvNotional * groupRatio + tradeVanillaSpanInfo.Sum(y => y.tradeSpan.PositionWin ?? 0); - worstCastClientPayable += groupMargins; - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeVanillaSpanInfo.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeVanillaSpanInfo.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else - { - worstCastClientPayable += tradeVanillaSpanInfo.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeVanillaSpanInfoSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroupOtherRemain.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroupOtherRemain.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if ((x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 || x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.指数) - { - //指数类交易 - var clientGroupIndex = clientGroupOtherRemain.Where(y => (y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - worstCastClientPayable += clientGroupIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - //初始预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金比例 - var redeemRatio2 = marginDetail.MarginRatio3 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体涨跌跌幅时需要判断单个标的的涨跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax && marginDetail.PriceLimitType == 0 || (y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax && marginDetail.PriceLimitType == 1 ? (y.trade.SpotPrice * (1 + (marginDetail.PriceLimitType == 0 ? -1 : 1) * redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - if (groupStrikeWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupStrikeWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupStrikeWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else - { - worstCastClientPayable += clientGroupOtherRemain.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.tradetemplate == null).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - }); - - #endregion - - #region 自定义组合预付金规则 - - groupMarginTemplates.ForEach(x => - { - var marginDetail = db.margin_template_detail.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - //非自定义预付金的交易 - var tradeSpanInfoGroup = clientGroupOther.Where(y => y.tradetemplate != null && y.tradetemplate.MarginTemplateId == x.id && y.tradeSpan.IsSingleMargin != true); - if (marginDetail == null && tradeSpanInfoGroup.Any()) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.Name)); - } - //自定义预付金的交易 - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => y.tradetemplate != null && y.tradetemplate.MarginTemplateId == x.id && y.tradeSpan.IsSingleMargin == true); - groupTradeIds.AddRange(tradeSpanInfoGroup.Select(y => y.trade.id)); - groupTradeIds.AddRange(tradeSpanInfoGroupSingle.Select(y => y.trade.id)); - if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1) - { - double groupMargins = 0; - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) - { - double groupMargins = 0; - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax ? (y.trade.SpotPrice * (1 - redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - double groupMargins = 0; - //初始预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金比例 - var redeemRatio2 = marginDetail.MarginRatio3 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体涨跌跌幅时需要判断单个标的的涨跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax && marginDetail.PriceLimitType == 0 || (y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax && marginDetail.PriceLimitType == 1 ? (y.trade.SpotPrice * (1 + (marginDetail.PriceLimitType == 0 ? -1 : 1) * redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (groupStrikeWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupStrikeWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupStrikeWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = db.trade_span.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else - { - worstCastClientPayable += tradeSpanInfoGroup.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - }); - - #endregion - - //自定义单腿规则的预付金加总 - worstCastClientPayable += clientGroupOther.Where(x => x.tradetemplate != null && !groupTradeIds.Contains(x.trade.id)).Sum(x => x.tradeSpan.WorstCastClientPayable ?? 0); - - //IC,IH,IF用span算法合计预付金 - if (clientGroupICIHIF.Any()) - { - var underlyingGroupICIHIF = clientGroupICIHIF.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - }).ToList(); - foreach (var item in underlyingGroupICIHIF) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - worstCastClientPayable += -(item.WorstCastClientPayable ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - - #endregion - } - } - - var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1) - }).ToList(); - foreach (var item in underlyingGroup) - { - if (!HasTwoSideMargin(clientGroup.Key)) - { - item.DeltaMargin = Math.Min(item.DeltaMargin ?? 0, 0); - } - } - - //客户方向delta预付金 - var deltaMargin = underlyingGroup.Sum(g => (g.DeltaMargin ?? 0)) - positionWinLoss; - if (!HasTwoSideMargin(clientGroup.Key)) - { - deltaMargin = Math.Min(deltaMargin, 0); - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = -worstCastClientPayable, - DeltaMargin = deltaMargin, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }; - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - if (marginReq.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - foreach (var item in marginReq.tradeList) - { - item.id = 0; - } - } - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongWu/PriceProviderFactory.cs b/YLErpDAL/BLL/MarginCalculation/DongWu/PriceProviderFactory.cs deleted file mode 100644 index be6522ab..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongWu/PriceProviderFactory.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using YLErp.Abstract.DataProviders; -using YLErp.Modules.DataProviderModule; - -namespace YLErp.BLL.MarginCalculation.DongWu -{ - public class PriceFactory : IPriceFactory - { - private IUpDownLimitProvider upDownLimitProvider; - private InnerUpDownLimit innerUpDownLimit; - private DateTime settleDate; - private double? realSettlePricePrice; - private string underlyingCode; - - private PriceFactory() { } - public PriceFactory(DateTime settleDate, double? realSettlePricePrice, string underlyingCode, IUpDownLimitProvider upDownLimitProvider) - { - this.settleDate = settleDate; - this.realSettlePricePrice = realSettlePricePrice; - this.underlyingCode = underlyingCode; - this.upDownLimitProvider = upDownLimitProvider; - this.innerUpDownLimit = upDownLimitProvider.GetUpDownLimit(); - } - - public PriceProviderWrap Generate(int priceCount, string preName) - { - var settlementDayEodPrice = EodPriceQueryService.GetEodPrice(settleDate, underlyingCode); - var settlePrice = realSettlePricePrice ?? (settlementDayEodPrice?.SettlePrice??0); - var prices = GeneratePrices(priceCount, settlePrice); - PriceProviderWrap priceProviderWrap = new PriceProviderWrap() - { - Name = preName, - SettlePrice= settlePrice, - UpLimitRate= innerUpDownLimit.UplimitRate, - DownLimitRate= innerUpDownLimit.DownLimitRate, - IsCover= innerUpDownLimit.IsCover, - IsTouch= innerUpDownLimit.IsTouch, - priceProviders=new Dictionary(), - }; - int index = 1; - foreach (var price in prices) - { - priceProviderWrap.priceProviders.Add(GenerateName(preName,index, price), new ManulPriceProvider(price)); - index++; - } - return priceProviderWrap; - } - - private List GeneratePrices(int priceCount,double settlePrice) - { - var upLimitRate = innerUpDownLimit.UplimitRate; - var downLimitRate = innerUpDownLimit.DownLimitRate; - - var upLimitPrice = settlePrice * (1+ Math.Abs(upLimitRate)); - var downPrice = settlePrice * (1-Math.Abs(downLimitRate)); - if (downPrice < 0) - { - // 最低价为0 - downPrice = 0; - } - double step = (upLimitPrice - downPrice) / (priceCount-1); - List prices = new List(); - for (int i = 0; i < priceCount; i++) - { - prices.Add(downPrice + (step * i)); - } - return prices; - } - private string GenerateName(string preName,int index,double price) - { - return $"{preName}_{index}_{price}"; - } - } - - public interface IPriceFactory - { - PriceProviderWrap Generate(int priceCount,string preName); - } - - public class PriceProviderWrap - { - public string Name { get; set; } - public double SettlePrice { get; set; } - public double UpLimitRate { get; set; } - public double DownLimitRate { get; set; } - public bool IsCover { get; set; } - public bool IsTouch { get; set; } - public Dictionary priceProviders { get; set; } - } - - public class ManulPriceProvider : IPriceProvider - { - private double _price; - - public ManulPriceProvider(double price) - { - this._price = price; - } - - public double GetPrice(string instrumentCode) - { - return _price; - } - - public bool TryGetPrice(string instrumentCode, out double price) - { - price = _price; - return true; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin1Provider.cs b/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin1Provider.cs deleted file mode 100644 index 54997837..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin1Provider.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using YLErp.Abstract.DataProviders; -using YLErp.Models; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; - -namespace YLErp.BLL.MarginCalculation.DongWu -{ - public class UpDownLimitMargin1Provider : IUpDownLimitProvider - { - private DateTime settleDate; - private string underlyingCode; - readonly IUnderlyingDataProvider underlyingDataProvider; - readonly MarginParamProviderManager marginParamProviderManager; - - public UpDownLimitMargin1Provider(DateTime settleDate, string underlyingCode, - MarginParamProviderManager marginParamProviderManager) - { - this.settleDate = settleDate; - this.underlyingCode = underlyingCode; - this.marginParamProviderManager = marginParamProviderManager; - this.underlyingDataProvider = new UnderlyingDataProvider(); - } - - /// - /// 计算Margin1涨跌幅 - /// 1、当天涨停板的定义:每天可以从交易所获得今天的涨跌停版,举例:设当天的涨跌停是10%,那么day1幅度=-12%到12% - /// 2、封板的定义,获取涨停价、跌停价当天涨跌停版范围使用结算价算出来的,封板:收盘价-当日涨停价价/跌停价的绝对值小于等于2个tick - /// ---------------------------------------- - /// T日 T-1日 T-2日 所属情景 Limit(day1幅度) - /// 封板 封板 - 连续封板的第二天 当天涨跌停板+0.02 - /// 封板 未封板 - 首日封板 当天涨跌停板+0.03 - /// 未封板 封板 封板 封板两天后恢复 当天涨跌停板-0.05 - /// 未封板 封板 未封板 昨日封板后恢复 当天涨跌停板-0.03 - /// 未封板 未封板 封板/未封板 正常 当天涨停板 - /// - /// - public virtual InnerUpDownLimit GetUpDownLimit() - { - var t0innerUnderlying = GetInnerUnlyingCode(settleDate); - var t1innerUnderlying = GetInnerUnlyingCode(settleDate.AddDays(-1)); - var t2innerUnderlying = GetInnerUnlyingCode(settleDate.AddDays(-2)); - var marginRate= new MarginRateManager().GetMarginRate(t0innerUnderlying?.IsCover, t1innerUnderlying?.IsCover, t2innerUnderlying?.IsCover); - var limitRate = t0innerUnderlying.OriginUpDownLimitRate + marginRate; - var innerUnderlying = new InnerUpDownLimit() - { - UnderlyingCode= t0innerUnderlying.UnderlyingCode, - //ClosePrice = t0innerUnderlying.ClosePrice, - IsCover= t0innerUnderlying.IsCover, - IsTouch = t0innerUnderlying.IsTouch, - OriginUpDownLimitRate = t0innerUnderlying.OriginUpDownLimitRate, - UplimitRate = limitRate, - DownLimitRate = -limitRate - }; - return innerUnderlying; - } - - /// - /// 查询标的信息(涨跌幅、是否封板,收盘价) - /// ------------------------------------------------------------------- - /// - /// - /// - /// - /// - protected InnerUpDownLimit GetInnerUnlyingCode(DateTime date) - { - var um = underlyingDataProvider.GetUnderlying(underlyingCode); - - // 查询t0结算价 - var t0EodPrice = GetEodPrice(date, underlyingCode); - //var t0SettlePrice = closePrice ?? (t0EodPrice == null ? 0.00 : t0EodPrice.SettlePrice); - var t0HighPrice= t0EodPrice == null ? 0.00 : t0EodPrice.HighPrice??0; - var t0LowPrice = t0EodPrice == null ? 0.00 : t0EodPrice.LowPrice??0; - var t0ClosePrice = t0EodPrice == null ? 0.00 : t0EodPrice.ClosePrice; - - // 查询t-1结算价 - var t1EodPrice = GetEodPrice(date.AddDays(-1), underlyingCode); - var t1SettlePrice = t1EodPrice == null ? 0.00d : t1EodPrice.SettlePrice; - - // 查询t0的涨跌停幅度(t-1结算价*t0涨跌停率) - var limitPrice = GetLimit(date, underlyingCode, t1SettlePrice, out double limitRate); - - // t0的涨停价=t-1结算价+t0涨跌停幅度 - double upLimitPrice = t1SettlePrice + limitPrice; - double downLimitPrice = t1SettlePrice - limitPrice; - - // 是否封板: - // 1.找不到t-1结算价或找不到t0收盘价,则认为未封板 - // 2.t0结算价-(t0涨停价/t0跌停价)的绝对值小于等于2个tick,则为封板 - var isCover = t0EodPrice == null || t1EodPrice == null ? false : IsCover(t0ClosePrice, upLimitPrice, downLimitPrice, um.PriceTick); - var isTouch = t0EodPrice == null || t1EodPrice == null ? false : IsTouch(t0HighPrice, t0LowPrice, upLimitPrice, downLimitPrice); - var innerUnderlying = new InnerUpDownLimit() - { - UnderlyingCode = underlyingCode, - IsCover = isCover, - IsTouch= isTouch, - OriginUpDownLimitRate = limitRate - }; - return innerUnderlying; - } - - /// - /// 获取日终价 - /// - /// - /// - /// - private EodPrice GetEodPrice(DateTime date, string underlyingCode) - { - return EodPriceQueryService.GetEodPrice(date, underlyingCode); - } - - /// - /// 查询涨跌榜 - /// - /// - /// - /// - /// - /// - private double GetLimit(DateTime date, string underlyingCode, double preClosePrice, out double limitRate) - { - var mpProvider = marginParamProviderManager.GetMpProvider(date); - double limitPrice = 0d; - if (mpProvider.TryGetUpdownLimit(underlyingCode, out limitRate, out var isFixed)) - { - if (!isFixed) - { - limitPrice = limitRate * preClosePrice; - } - } - return limitPrice; - } - - /// - /// 是否封板:收盘价-当日涨停价价/跌停价的绝对值小于等于2个tick - /// - /// - /// - /// - /// - /// - /// - private bool IsCover(double closePrice, double upLimitPrice, double downLimitPrice, double tick) - { - bool isCover= Math.Abs(closePrice - upLimitPrice) <= 2 * tick || Math.Abs(closePrice - downLimitPrice) <= 2 * tick; - if (!isCover) - { - return closePrice >= upLimitPrice || closePrice <= downLimitPrice; - } - return isCover; - } - - /// - /// 是否触板:最高价>=涨停价或者最低价<=跌停价 - /// - /// 最高价 - /// 最低价 - /// 涨停价 - /// 跌停价 - /// - private bool IsTouch(double highPrice,double lowerPrice, double upLimitPrice, double downLimitPrice) - { - return highPrice>= upLimitPrice || lowerPrice <= downLimitPrice; - } - - /// - /// 东吴涨跌涨跌幅度管理 - /// - internal class MarginRateManager - { - #region - private const string YesYesYes = "111"; - private const string YesYesNo = "110"; - - private const string YesNONo = "100"; - private const string YesNOYes = "101"; - - - private const string NoYesYes = "011"; - private const string NoYesNo = "010"; - private const string NoNoNo = "000"; - private const string NoNoYes = "001"; - #endregion - - private static readonly Dictionary MarginRates = new Dictionary() - { - { YesYesYes, 0.02d }, - { YesYesNo, 0.02d }, - - { YesNONo, 0.03d }, - { YesNOYes, 0.03d }, - - { NoYesYes, -0.05d }, - { NoYesNo, -0.03d }, - { NoNoNo, 0d }, - { NoNoYes, 0d } - }; - private int ConvertToEnum(bool isCover) - { - return isCover ? 1 : 0; - } - public enum CoverEnum - { - Yes = 0, - No = 1, - } - - public double GetMarginRate(bool? t0IsCover, bool? t1IsCover, bool? t2IsCover) - { - string key = $"{ConvertToEnum(t0IsCover??false)}{ConvertToEnum(t1IsCover??false)}{ConvertToEnum(t2IsCover??false)}"; - return MarginRates[key]; - } - } - } - - /// - /// 预付金参数提供管理类 - /// - public class MarginParamProviderManager - { - private HashSet umCodeSet; - private Dictionary marginParamProviders=new Dictionary(); - public MarginParamProviderManager(HashSet umCodeSet) - { - this.umCodeSet = umCodeSet; - } - - public void Initial(RunMarginCalculationReq req) - { - var t0MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate); - t0MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit); - marginParamProviders.Add(req.settleDate, t0MpProvider); - - var t1MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate.AddDays(-1)); - t1MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit); - marginParamProviders.Add(req.settleDate.AddDays(-1), t1MpProvider); - - var t2MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate.AddDays(-2)); - t2MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit); - marginParamProviders.Add(req.settleDate.AddDays(-2), t2MpProvider); - } - - public MarginParamProvider GetMpProvider(DateTime date) - { - if (marginParamProviders.ContainsKey(date)) - { - return marginParamProviders[date]; - } - return null; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin3Provider.cs b/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin3Provider.cs deleted file mode 100644 index 61e189b5..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin3Provider.cs +++ /dev/null @@ -1,95 +0,0 @@ -using NPOI.SS.Formula.Functions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using YLErp.Abstract.DataProviders; -using YLErp.Models; -using YLErp.Modules.DataProviderModule; - -namespace YLErp.BLL.MarginCalculation.DongWu -{ - public class UpDownLimitMargin3Provider : IUpDownLimitProvider - { - private DateTime settleDate; - private string underlyingCode; - readonly IUnderlyingDataProvider underlyingDataProvider; - public UpDownLimitMargin3Provider(DateTime settleDate, string underlyingCode) - { - this.settleDate = settleDate; - this.underlyingCode = underlyingCode; - this.underlyingDataProvider = new UnderlyingDataProvider(); - } - - - /// - /// 获取连续两日最大涨跌幅的95分位和5分位 - /// --------------------------------------------------------------------- - /// 例如,对于CF209合约,选取CFFI.WI过去600天内的价格序列,对于任意日T, - /// 其两日最大涨幅=Max(T+1最高价,T+2最高价)/T日收盘价 - /// 两日最大跌幅 = Min(T + 1最低价,T + 2最低价) / T日收盘价 - /// 得到最大涨跌幅的序列后,取95分位和5分位的百分比作为连续两日最大涨跌幅的95分位数值。 - /// - /// - public InnerUpDownLimit GetUpDownLimit() - { - var startDate = settleDate.AddDays(-600); - var mainUnderlyingCode = underlyingCode; - - var um = underlyingDataProvider.GetUnderlying(underlyingCode); - if (um.IsFutures()) - { - // 如果是期货类型的,需要获取到主合约 - // 忽略大小写,将字母后的数字替换为00,获取到主合约Code - Regex myRegex = new Regex(@"^([a-zA-Z]*)(\d*)$", RegexOptions.IgnoreCase); - mainUnderlyingCode = myRegex.Replace(underlyingCode, "$1") + "00"; - } - var eodPrices = EodPriceQueryService.GetEodPriceByUnserialDateRange(startDate, settleDate, mainUnderlyingCode).OrderBy(b => b.ValueDate).ToList(); - - - int lastIndex = eodPrices.Count - 1; - List innerCodes = new List(); - for (int i = 0; i < eodPrices.Count; i++) - { - if (i == lastIndex - 1) - { - // 最后两天没有T+1和T+2,不放到列表中统计95分位和5分位; - break; - } - EodPrice t0 = eodPrices[i]; - EodPrice t1 = (i + 1) > lastIndex ? null : eodPrices[i + 1]; - EodPrice t2 = (i + 2) > lastIndex ? null : eodPrices[i + 2]; - var uplimitRate = Math.Max(t1?.HighPrice ?? 0, t2?.HighPrice ?? 0) / t0.ClosePrice; - var downLimitRate = Math.Min(t1?.LowPrice ?? 0, t2?.LowPrice ?? 0) / t0.ClosePrice; - InnerUpDownLimit innerCode = new InnerUpDownLimit() - { - UnderlyingCode = t0.UnderlyingCode, - //ClosePrice = t0.ClosePrice, - UplimitRate = uplimitRate, - DownLimitRate = downLimitRate - }; - innerCodes.Add(innerCode); - } - - //最大涨幅95分位和5分位 - List priceList = new List(); - priceList.AddRange(innerCodes.Select(g => g.UplimitRate)); - priceList.AddRange(innerCodes.Select(g => g.DownLimitRate)); - - var OrderPriceList = priceList.OrderBy(g => g); - var totalCount = OrderPriceList.Count(); - var uplimitRatePercent95 = totalCount == 0 ? 0 : Math.Abs(1-OrderPriceList.ElementAt((int)(totalCount * 0.95))); - var downLimitRatePercent5 = totalCount == 0 ? 0 : Math.Abs(1-OrderPriceList.ElementAt((int)(totalCount * 0.05))); - - - return new InnerUpDownLimit() - { - UnderlyingCode = underlyingCode, - UplimitRate = totalCount == 0 ? 0 : uplimitRatePercent95, - DownLimitRate = totalCount == 0 ? 0 : downLimitRatePercent5 - }; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitProvider.cs b/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitProvider.cs deleted file mode 100644 index e126e678..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace YLErp.BLL.MarginCalculation.DongWu -{ - public interface IUpDownLimitProvider - { - //string Unlyingcode { get; set; } - //double GetUplimitRate(); - //double GetDownlimitRate(); - InnerUpDownLimit GetUpDownLimit(); - } - - public class InnerUpDownLimit - { - public string UnderlyingCode { get; set; } - public double UplimitRate { get; set; } - /// - /// 跌停幅度 - /// - public double DownLimitRate { get; set; } - /// - /// 是否封板 - /// - public bool IsCover { get; set; } - /// - /// 是否触板 - /// - public bool IsTouch { get; set; } - ///// - ///// 收盘价 - ///// - //public double ClosePrice { get; set; } - /// - /// 涨跌停幅度 - /// - public double OriginUpDownLimitRate { get; set; } = 0d; - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongWuMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/DongWuMarginCalculation.cs deleted file mode 100644 index fcf5bfab..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongWuMarginCalculation.cs +++ /dev/null @@ -1,507 +0,0 @@ -using Qdp.Pricing.Base.Implementations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Dynamic.Core; -using System.Text; -using System.Threading.Tasks; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.BLL.MarginCalculation.DongWu; -using YLErp.DBModels; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model; -using YLErp.Model.Enum; -using YLErp.Models; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 东吴预付金计算 - /// TODO :东吴预付金计算待解决问题: - /// 1.接入收盘测试并测试 - /// 2.接入定价预付金计算并测试 - /// 3.接入实时预付金计算并测试 - /// - public class DongWuMarginCalculation : MarginCalculationBase - { - private const string ExtensionNodeName = "DongWu_Margin"; - private const string Margin1PreName = "Margin1"; - private const string Margin3PreName = "Margin3"; - private const int PriceCount = 21; - private const double CoverMarginRate = 1.4; - - // 定义一个静态变量来保存类的实例 - public static readonly DongWuMarginCalculation Instance; - - static DongWuMarginCalculation() - { - Instance = new DongWuMarginCalculation(); - } - - protected DongWuMarginCalculation() - { - - } - - #region Override Base Method - /// - /// 计算交易预付金 - /// - /// - /// - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - // 交易预付金计算结果 - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - // 为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - // 设置期权详情 - helper.SetFieldsByTradeType(); - - //标的集合 - helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - var umCodeSet = helper.GetUnderlyingCodes(); - - // 预付金参数管理 - var marginParamProviderManager = new MarginParamProviderManager(umCodeSet); - marginParamProviderManager.Initial(req); - - // 创建价格 - var priceProviders = new Dictionary>(); - foreach (var underlyingCode in umCodeSet) - { - // 生成Margin1 价格 - double? settlePrice = null; - if (req.CalcMarginType != CalcMarginTypeEnum.EodMargin) - { - // 如果是实时预付金计算,用前一天的结算价 - var settlementDayEodPrice = EodPriceQueryService.GetEodPrice(req.settleDate.AddDays(-1), underlyingCode); - settlePrice = settlementDayEodPrice?.SettlePrice ?? 0; - } - IPriceFactory priceProviderFactory1 = new PriceFactory(req.settleDate, settlePrice, underlyingCode, new UpDownLimitMargin1Provider(req.settleDate, underlyingCode, marginParamProviderManager)); - var unPriceProviders1 = priceProviderFactory1.Generate(priceCount: PriceCount, preName: Margin1PreName); - - // 生成Margin3 价格 - IPriceFactory priceProviderFactory3 = new PriceFactory(req.settleDate, settlePrice, underlyingCode, new UpDownLimitMargin3Provider(req.settleDate, underlyingCode)); - var unPriceProviders3 = priceProviderFactory3.Generate(priceCount: PriceCount, preName: Margin3PreName); - - priceProviders.Add(underlyingCode, new List() { unPriceProviders1, unPriceProviders3 }); - } - - foreach (var trade in req.tradeList) - { - // 获取标的价格 - if (!priceProviders.TryGetValue(trade.UnderlyingCode, out List priceProviderWraps)) - { - continue; - } - - // 计算交易PV结果 - var pVJsons = new List(); - - //计算pv方法 - Action> calcPv = (unPriceProviders) => - { - foreach (var priceProvider in unPriceProviders) - { - var cloneTrade = trade.Clone(); - var tradeRiskResult = CalculateRisksForTrades(req, priceProvider.Value, cloneTrade); - - var pVJson = new PVJson(); - pVJson.TradeId = trade.id; - pVJson.UnderlyingId = trade.UnderlyingId; - var un = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); - pVJson.VarietyId = un.UnderlyingTypeId; - pVJson.Name = priceProvider.Key; - pVJson.ClientId = trade.ClientId; - pVJson.Value = tradeRiskResult.Results.FirstOrDefault().ValueResult.Pv; - pVJsons.Add(pVJson); - } - }; - - // 计算 Margin1 trade pv - var priceProviderWrap1 = priceProviderWraps.FirstOrDefault(g => g.Name == Margin1PreName); - calcPv(priceProviderWrap1.priceProviders); - - // 计算 Margin3 trade pv - var priceProviderWrap3 = priceProviderWraps.FirstOrDefault(g => g.Name == Margin3PreName); - calcPv(priceProviderWrap3.priceProviders); - - // Create TradeSpan - var contains = resultMap.TryGetValue(trade.id, out var tempTradeSpan); - if (!contains) - { - resultMap[trade.id] = tempTradeSpan = helper.CreateTradeSpan(trade); - } - tempTradeSpan.WorstCastClientPayable = pVJsons.Max(l => l.Value); - PriceJson priceJson = new PriceJson() - { - Pvs = pVJsons, - UpLimitRate = priceProviderWrap1.UpLimitRate, - DownLimitRate = priceProviderWrap1.DownLimitRate, - UpLimitRate3 = priceProviderWrap3.UpLimitRate, - DownLimitRate3 = priceProviderWrap3.DownLimitRate, - IsCover = priceProviderWrap1.IsCover, - IsTouch = priceProviderWrap1.IsTouch - }; - tempTradeSpan.SetExtensions(ExtensionNodeName, priceJson); - } - - return resultMap.Values.ToList(); - } - /// - /// 计算客户预付金 - /// - /// - /// - public override List CalcClientMargin(CalcClientMarginReq req) - { - // 客户预付金计算结果 - var clientSpanNews = new List(); - var updateTradeSpans = new List(); - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = GetTrades(tradeIds); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - //2023-02-24:排除掉现金流交易,现金流交易应该不需要预付金 - where tradeSpan.ValueDate == req.settleDate && trade.TradeType != "现金流交易" - select new - { - PriceJson = tradeSpan.GetFromExtensions(ExtensionNodeName), - trade, - tradeSpan - }).ToList(); - - var varietyCoverStatus = tradeSpanInfo.GroupBy(g => g.tradeSpan.VarietyId ?? 0).ToDictionary(g => g.Key, g => g.Any(b => b.PriceJson != null && b.PriceJson.IsCover)); - var varietyTouchStatus = tradeSpanInfo.GroupBy(g => g.tradeSpan.VarietyId ?? 0).ToDictionary(g => g.Key, g => g.Any(b => b.PriceJson != null && b.PriceJson.IsTouch)); - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var pVJsons1 = new List(); - var pVJsons3 = new List(); - foreach (var tradeInfo in clientGroup) - { - if (tradeInfo.PriceJson != null) - { - // margin1 - pVJsons1.AddRange(tradeInfo.PriceJson.Pvs.Where(b => b.Name.StartsWith(Margin1PreName)).Select( - g => new DongwuPVJson - { - TradeSpanId = tradeInfo.tradeSpan.id, - ClientId = g.ClientId, - Describe = g.Describe, - Name = g.Name, - TradeId = g.TradeId, - UnderlyingId = g.UnderlyingId, - Value = g.Value, - VarietyId = g.VarietyId - }).ToList()); - - // margin3 - pVJsons3.AddRange(tradeInfo.PriceJson.Pvs.Where(b => b.Name.StartsWith(Margin3PreName)).Select( - g => new DongwuPVJson - { - TradeSpanId = tradeInfo.tradeSpan.id, - ClientId = g.ClientId, - Describe = g.Describe, - Name = g.Name, - TradeId = g.TradeId, - UnderlyingId = g.UnderlyingId, - Value = g.Value, - VarietyId = g.VarietyId - }).ToList()); - } - } - - // 计算单个客户预付金 - var clientPv = CalcClientMargin(clientGroup.Key, pVJsons1, pVJsons3, (int varietyId) => - { - varietyCoverStatus.TryGetValue(varietyId, out bool isCover); - return isCover; - }, (int varietyId) => - { - varietyTouchStatus.TryGetValue(varietyId, out bool isTouch); - return isTouch; - }, (List UpdatePVJsons) => - { - updateTradeSpans.AddRange(UpdatePVJsons.Select(g => new trade_span() { id = g.TradeSpanId, WorstCastClientPayable = g.Value })); - }); - - // 计算客户维度预付金 - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = tradeSpanInfo.Where(g => g.trade.ClientId == clientGroup.Key).Sum(g => g.tradeSpan.DeltaMargin * -1), - // 负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = -clientPv, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - - clientSpan.PVJsonList = new List(); - clientSpan.PVJsons = JsonHelper.ToJson(clientSpan.PVJsonList); - clientSpanNews.Add(clientSpan); - } - } - - SaveClientSpan(req, clientSpanNews, updateTradeSpans); - - return req.tradeSpans; - } - /// - /// 获取交易预付金计算结果 - /// - /// - /// - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin && tradeMargin.FirstOrDefault() != null) - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - - return Math.Max(margin, 0); - } - return 0.0; - } - #endregion - - #region - /// - /// 东吴-计算客户预付金逻辑 - /// - /// - /// - /// - private double CalcClientMargin(int clientId, List pVJsons1, List pVJsons3, Func isCoverFunc, Func isTouchFunc, Action> updateTradespansAction) - { - /* - 计算客户预付金: - 1.计算标的预付金 - 2.计算品种预付金 - 3.计算客户预付金 - */ - - // 计算品种维度预付金方法 - var calcVarietyMargin = (List pVJsons) => - { - var varietyMarginDic = pVJsons - .GroupBy(g => new { g.VarietyId, g.UnderlyingId, g.Name }).Select(g => new - { - // 同品种、同标的、同价格合计pv - UnderlyingId = g.Key.UnderlyingId, - VarietyId = g.Key.VarietyId, - Name = g.Key.Name, // 前缀+价格,例如:Margin1_3.00 - UnPriceSumPv = g.Sum(b => b.Value), - Tradespans = g.ToList() - }) - .GroupBy(g => new { g.VarietyId, g.UnderlyingId }).Select(g => new - { - // 同品种、同标的取最大pv - UnderlyingId = g.Key.UnderlyingId, - VarietyId = g.Key.VarietyId, - UnPv = g.Max(g => g.UnPriceSumPv), - Tradespans = g.Where(a => a.UnPriceSumPv == g.Max(g => g.UnPriceSumPv)).First().Tradespans - }) - .GroupBy(g => g.VarietyId).Select(g => new - { - // 同品种轧差pv - VarietyId = g.Key, - VarietyPv = g.Sum(b => b.UnPv), - Tradespans = g.SelectMany(a => a.Tradespans).ToList() - }).ToDictionary(g => g.VarietyId, g => g); - return varietyMarginDic; - }; - - // 计算品种维度margin1预付金 - var varietyMargin1Dic = calcVarietyMargin(pVJsons1); - - // 计算品种维度margin3预付金 - var varietyMargin3Dic = calcVarietyMargin(pVJsons3); - - // 品种Pv=Max(Margin1,Margin3),如果有触板的品种需要乘1.4 - Dictionary varietyPv = new Dictionary(); - foreach (var varietyId in varietyMargin1Dic.Keys) - { - var clientMargin1 = varietyMargin1Dic[varietyId]; - var clientMargin3 = varietyMargin3Dic[varietyId]; - var maxPv = 0.00; - List updatePvJsons; - if (clientMargin1.VarietyPv > clientMargin3.VarietyPv) - { - maxPv = clientMargin1.VarietyPv; - updatePvJsons = clientMargin1.Tradespans; - } - else - { - maxPv = clientMargin3.VarietyPv; - updatePvJsons = clientMargin3.Tradespans; - } - bool isCover = isCoverFunc(varietyId); - bool isTouch = isTouchFunc(varietyId); - if (!isCover && isTouch) - { - maxPv = CoverMarginRate * maxPv; - } - varietyPv.Add(varietyId, maxPv); - - // 回写trade_span预付金值 - updateTradespansAction(updatePvJsons); - } - - // 计算客户维度pv=合计所有品种的pv - var clientPv = varietyPv.Values.Sum(); - - var client = DataCacheProvider.GetClientDataSource().GetData(clientId); - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - // 单项预付金如果小于0,则显示0 - clientPv = Math.Max(clientPv, 0); - } - - return clientPv; - } - /// - /// 计算交易风险 - /// - /// - /// - /// - /// - private TradeRiskResult CalculateRisksForTrades(RunMarginCalculationReq req, IPriceProvider priceProvider, trade trade) - { - var reqConv = new CalculateRisksForTradesReq - { - valueDate = req.settleDate, - tradeList = new List() { trade }, - priceProvider = priceProvider, - pricingRequest = QdpPricingRequest.PV_ONLY, - volType = req.volType, - isUseTradeVol = PS.Config.IsTradeVol, - PreciseTimeMode = req.CalcMarginType != Enums.CalcMarginTypeEnum.EodMargin, - isAddVolPercent = true, - isMarginCalc = true - }; - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.EodMargin) - { - reqConv.calcScenario = Enums.CalcScenarioEnum.EodSettlement; - } - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin) - { - reqConv.calcScenario = Enums.CalcScenarioEnum.InitialMargin; - } - return CalculatorHelper.CalculateRisksForTrades(reqConv); - } - /// - /// 查询交易 - /// - /// - /// - private List GetTrades(List tradeIds) - { - using (var db = new YLContext()) - { - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - return tradeList; - } - } - /// - /// 批量保存客户预付金 - /// - /// - /// - private void SaveClientSpan(CalcClientMarginReq req, List clientSpanNews, List updateTradeSpans) - { - using (var db = new YLContext()) - { - // 回写更新交易预付金 - var tradespanids = updateTradeSpans.Select(t => t.id).ToList(); - var trade_spans = db.trade_span.Where(g => tradespanids.Contains(g.id)).ToList(); - var updatetradeSpanData = (from updatetradeSpan in updateTradeSpans - join tradeSpan in trade_spans on updatetradeSpan.id equals tradeSpan.id - select new - { - updatetradeSpan, - tradeSpan - }); - foreach (var item in updatetradeSpanData) - { - item.tradeSpan.WorstCastClientPayable = item.updatetradeSpan.WorstCastClientPayable; - } - - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - } - } - #endregion - } - - public class DongwuPVJson : PVJson - { - public int TradeSpanId { get; set; } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/DongZhengRunHeMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/DongZhengRunHeMarginCalculation.cs deleted file mode 100644 index adcf2cd0..00000000 --- a/YLErpDAL/BLL/MarginCalculation/DongZhengRunHeMarginCalculation.cs +++ /dev/null @@ -1,697 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.DBModels.Helpers; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Modules.VolatilityModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 东证润和预付金计算 - /// - public class DongZhengRunHeMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly DongZhengRunHeMarginCalculation Instance; - - static DongZhengRunHeMarginCalculation() - { - Instance = new DongZhengRunHeMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected DongZhengRunHeMarginCalculation() - { - - } - - private static Dictionary GetOverrideVols(RunMarginCalculationReq req) - { - Dictionary overrideVols = null; - - //东证润和使用日终价的波动率 - if (PS.Config.Company == Configuration.CompanyEnum.润和) - { - overrideVols = new Dictionary(); - - var voltype = req.volType == "对冲" || req.volType == "持仓" ? "交易" : req.volType; - var excludeTypes = new[] { ConsGlobal.TradeType.PayoffSwap, ConsGlobal.TradeType.CashFlow, ConsGlobal.TradeType.Forward }; - - foreach (var td in req.tradeList) - { - var underlyingVols = VolatilityHelper.GetVol(req.settleDate, voltype, td.UnderlyingCode, userGroup: null) - ?? throw new Exception($"未找到'{voltype}'波动率:{td.UnderlyingCode}"); - - var vol = VolatilityHelper.GetInterpolatedVol( - volConstructionType: VolConstructionType.Normal, - volSurface: underlyingVols, - valueDate: req.settleDate, - underlyingCode: td.UnderlyingCode, - exerciseDate: td.ExerciseDate.Value, - strike: td.Strike ?? 0, - isBuy: td.BuySell == "买入", - isCall: td.CallPut == "Call", - spotPrice: req.PriceProvider.GetPrice(td.UnderlyingCode), - isMoneynessOption: td.IsMoneynessOption == "是", - isEodCalc: req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - overrideVols[td.id] = td.Vol ?? vol; - } - else - { - if (!excludeTypes.Contains(td.TradeType)) - { - overrideVols[td.id] = vol; - } - } - } - } - - return overrideVols; - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - var resultMap = new Dictionary(); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - helper.GetTradVolRateDic(out var tradeVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - var overrideVols = GetOverrideVols(helper.req); - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.Item1, - priceProvider = n.Item2, - addVolRateDic = m - })).ToArray(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: overrideVols, isEodCalc: req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - case "normal_0": - tempTradeSpan.Spv5 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - } - } - - return resultMap.Values.ToList(); - } - - /// - /// 计算客户预付金 - /// 从国君预付金那里赋值过来的 - /// 逻辑和国君保持一致,唯一区别是商品类对手方预付金,正负值都需要 - /// - /// - /// - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList(); - var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList(); - //获取收盘日那天对应的预付金模板 - var tradeTemplates = db.trade_margin_template.AsNoTracking().Where(t => tradeIds.Contains(t.TradeId) && t.ValueDate <= req.settleDate); - var groupQuery = from tt in tradeTemplates - group tt by tt.TradeId into tts - select new - { - TradeId = tts.Key, - ValueDate = tts.Max(n => n.ValueDate) - }; - var groupTemplates = from gq in groupQuery - join tt in tradeTemplates - on new { gq.TradeId, gq.ValueDate } equals new { tt.TradeId, tt.ValueDate } - select tt; - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join um in underlyingList on trade.UnderlyingId equals um.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, tradetemplate, um.UnderlyingTypeId }).ToList(); - - //商品类预付金计算 - if (!PS.Config.ErpElement.IsStockMargin) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var spans = req.tradeSpansOtherSide != null - ? req.tradeSpansOtherSide.Where(n => n != null).ToArray() : Enumerable.Empty(); - - var tradeSpanInfoOtherSide = (from tradeSpan in spans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join um in underlyingList on trade.UnderlyingId equals um.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, um.UnderlyingTypeId }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var varietyGroups = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in varietyGroups) - { - item.WorstCastClientPayable = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0, item.Spv5 ?? 0 }.Min(); - item.TwoSideMargin = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0, item.Spv5 ?? 0 }.Min(); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Where(x => x.UnderlyingTypeId == item.VarietyId).Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - - #endregion - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = varietyGroups.Sum(g => g.Spv1), - Spv2 = varietyGroups.Sum(g => g.Spv2), - Spv3 = varietyGroups.Sum(g => g.Spv3), - Spv4 = varietyGroups.Sum(g => g.Spv4), - Spv5 = varietyGroups.Sum(g => g.Spv5), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable), - MySideMargin = varietyGroups.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = varietyGroups.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.Spv5 += singleMarginTrade.Sum(O => O.Spv5 * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - - //交易员不支付预付金 - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - clientSpanNews.Add(clientSpan); - } - - //处理从客户角度的预付金计算(将交易买卖方向反向处理) - var clientGroupsOtherSide = tradeSpanInfoOtherSide.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroupsOtherSide) - { - var varietyGroups = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in varietyGroups) - { - item.WorstCastClientPayable = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0, item.Spv5 ?? 0 }.Min(); - } - var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate); - clientSpan.OtherSideMargin = varietyGroups.Sum(g => g.WorstCastClientPayable); - - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.OtherSideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - } - } - } - //权益类预付金计算 - else - { - var defaultMarginTemplates = db.margin_template_v2.Where(x => x.IsDefault && !x.IsForClient).ToList(); - var groupMarginTemplates = db.margin_template_v2.Where(x => !x.IsDefault && x.MarginType == (int)MarginTypeV2Enum.多腿).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var worstCastClientPayable = 0.0; - var groupTradeIds = new List(); - - #region 默认组合的交易类型的交易处理 - - defaultMarginTemplates.ForEach(x => - { - var marginDetail = db.margin_template_detail.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null && (x.RuleType != (int)MarginRuleTypeEnum.无预付金 && x.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && x.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && x.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("YYYY-MM-DD"), x.Name)); - } - - if (x.RuleType == (int)MarginRuleTypeEnum.类香草预付金规则) - { - var groupRatio = marginDetail.GroupRatio ?? 0; - var stockEqvNotional = marginDetail.StockEqvNotional ?? 0; - var singleStockEqvNotional = marginDetail.SingleStockEqvNotional ?? 0; - var amount = marginDetail.PositionUnderlyingAmount ?? 0; - - //香草期权只考虑交易员买入的交易,卖出的交易不需要考虑预付金 - var tradeVanillaSpanInfo = clientGroup.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin != true); - //自定义预付金 - var tradeVanillaSpanInfoSingle = clientGroup.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.tradetemplate == null && y.tradeSpan.IsSingleMargin == true); - var umdStockEqvNotional = tradeVanillaSpanInfo.GroupBy(y => y.trade.UnderlyingId).Select(t => new - { - UnderlyingId = t.Key, - StockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor)), - PositionStockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor) * g.tradeSpan.UnderlyingPrice / g.trade.SpotPrice) - }).ToList(); - var underlyingIds = umdStockEqvNotional.Select(y => y.UnderlyingId); - var totalStockEqvNotional = umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional); - if (totalStockEqvNotional >= stockEqvNotional && umdStockEqvNotional.Any(y => y.PositionStockEqvNotional >= singleStockEqvNotional) && underlyingIds.Count() >= amount) - { - //获取组合持仓名义本金和初始名义本金的较高者 - var maxStockEqvNotional = Math.Max(umdStockEqvNotional.Sum(y => y.StockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.StockEqvNotional), umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.PositionStockEqvNotional ?? 0)); - worstCastClientPayable += maxStockEqvNotional * groupRatio + tradeVanillaSpanInfo.Sum(y => y.tradeSpan.PositionWin ?? 0); - } - else - { - worstCastClientPayable += tradeVanillaSpanInfo.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeVanillaSpanInfoSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroup.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.tradeSpan.UnderlyingPrice * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - - if (groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio1; - worstCastClientPayable += groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - } - else - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - //排除指数类交易 - var clientGroupWithoutIndex = clientGroup.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.tradeSpan.UnderlyingPrice * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - - if (groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - worstCastClientPayable += groupStockEqvNotionalNow * redeemRatio1; - worstCastClientPayable += groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - } - else - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupWithoutIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - } - else if ((x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 || x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.指数) - { - //指数类交易 - var clientGroupIndex = clientGroup.Where(y => (y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.tradetemplate == null); - - worstCastClientPayable += clientGroupIndex.Where(y => x.TradeTypes.Contains(y.trade.TradeType)).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroup.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.tradetemplate == null).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - }); - - #endregion - - #region 自定义组合预付金规则 - - groupMarginTemplates.ForEach(x => - { - var marginDetail = db.margin_template_detail.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("YYYY-MM-DD"), x.Name)); - } - //非自定义预付金的交易 - var tradeSpanInfoGroup = clientGroup.Where(y => y.tradetemplate != null && y.tradetemplate.MarginTemplateId == x.id && y.tradeSpan.IsSingleMargin != true); - //自定义预付金的交易 - var tradeSpanInfoGroupSingle = clientGroup.Where(y => y.tradetemplate != null && y.tradetemplate.MarginTemplateId == x.id && y.tradeSpan.IsSingleMargin == true); - groupTradeIds.AddRange(tradeSpanInfoGroup.Select(y => y.trade.id)); - groupTradeIds.AddRange(tradeSpanInfoGroupSingle.Select(y => y.trade.id)); - if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1) - { - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.tradeSpan.UnderlyingPrice * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - - if (groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio1; - worstCastClientPayable += groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - } - else - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) - { - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.tradeSpan.UnderlyingPrice * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - - if (groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - worstCastClientPayable += groupStockEqvNotionalNow * redeemRatio1; - worstCastClientPayable += groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - } - else - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - //预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.tradeSpan.UnderlyingPrice * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupSpotPriceWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupSpotPriceWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (times >= 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - worstCastClientPayable += groupStockEqvNotional * rateTemp * redeemRatio; - } - else - { - //不满足追加比例时,用初始预付金 - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - } - else - { - worstCastClientPayable += groupStockEqvNotional * redeemRatio; - } - - if (groupSpotPriceWithNotional > 0 && marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStockEqvNotional * marginDetail.MarginRatio2.Value * times; - } - } - else - { - worstCastClientPayable += tradeSpanInfoGroup.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - }); - - #endregion - - //自定义单腿规则的预付金加总 - worstCastClientPayable += clientGroup.Where(x => x.tradetemplate != null && !groupTradeIds.Contains(x.trade.id)).Sum(x => x.tradeSpan.WorstCastClientPayable ?? 0); - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = -worstCastClientPayable, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }; - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/FDMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/FDMarginCalculation.cs deleted file mode 100644 index 8e97665d..00000000 --- a/YLErpDAL/BLL/MarginCalculation/FDMarginCalculation.cs +++ /dev/null @@ -1,674 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataCacheModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.Modules.UnderlyingModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 方顿 - /// - public class FDMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly FDMarginCalculation Instance; - - static FDMarginCalculation() - { - Instance = new FDMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private FDMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - //结果集 - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - helper.SetFieldsByTradeType(); - - GetPrices(req, out var TPrices1, out var TPrices2, out var TPrices3, out var TPrices4, out var TPrices5, out var TPrices6, out var TPrices7, out var TPrices8, out var TPrices9, out var TPrices10, out var TPrices11, out var TPrices12, out var TPrices13, out var TPrices14); - - var prices = new (string pId, IPriceProvider provider)[] { ("pr1", TPrices1), ("pr2", TPrices2), ("pr3", TPrices3), ("pr4", TPrices4), ("pr5", TPrices5), ("pr6", TPrices6), ("pr7", TPrices7), ("pr8", TPrices8), ("pr9", TPrices9), ("pr10", TPrices10), ("pr11", TPrices11), ("pr12", TPrices12), ("pr13", TPrices13), ("pr14", TPrices14) }; - - var priceProvider = new ManualPriceProvider(); - - foreach (var price in prices) - { - var key = $"{price.Item1}"; - var Results = req.tradeList.SelectMany(t => - { - priceProvider.SetPrice(t.UnderlyingCode, price.provider.GetPrice(t.id.ToString())); - var tradeRiskResult1 = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: new[] { t }, - priceProvider: priceProvider, - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: null, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - return (tradeRiskResult1.Results?.AsEnumerable()) ?? Enumerable.Empty(); - }); - - if (!Results.Any()) - { - continue; - } - - foreach (var item in Results) - { - var client = helper.GetClient(item.Trade.ClientId); - - var clientRatio = client == null ? 1.0 : client?.Ratio ?? 1.0; - var clientRatio1 = client == null ? 1.0 : client?.Ratio1 ?? 1.0; - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio1; - } - else - { - value = double.IsNaN(pv) ? 0 : pv; - } - } - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "pr1": - tempTradeSpan.Spv1 = value; break; - case "pr2": - tempTradeSpan.Spv2 = value; break; - case "pr3": - tempTradeSpan.Spv3 = value; break; - case "pr4": - tempTradeSpan.Spv4 = value; break; - case "pr5": - tempTradeSpan.Spv5 = value; break; - case "pr6": - tempTradeSpan.Spv6 = value; break; - case "pr7": - tempTradeSpan.Spv7 = value; break; - case "pr8": - tempTradeSpan.Spv8 = value; break; - case "pr9": - tempTradeSpan.Spv9 = value; break; - case "pr10": - tempTradeSpan.Spv10 = value; break; - case "pr11": - tempTradeSpan.Spv11 = value; break; - case "pr12": - tempTradeSpan.Spv12 = value; break; - case "pr13": - tempTradeSpan.Spv13 = value; break; - case "pr14": - tempTradeSpan.Spv14 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - } - } - - return resultMap.Values.ToList(); - } - - /// - /// 获取T0,T1涨跌停价格字典 ----方顿 - /// 涨跌停板幅度 T0 d1 T1 涨停 (1+d1)*(1+d1)-1 跌停 1-(1-d1)*(1-d1) - /// - public void GetPrices(RunMarginCalculationReq req, out IPriceProvider TPrices1, out IPriceProvider TPrices2, out IPriceProvider TPrices3, out IPriceProvider TPrices4, out IPriceProvider TPrices5, out IPriceProvider TPrices6, out IPriceProvider TPrices7, out IPriceProvider TPrices8, out IPriceProvider TPrices9, out IPriceProvider TPrices10, out IPriceProvider TPrices11, out IPriceProvider TPrices12, out IPriceProvider TPrices13, out IPriceProvider TPrices14) - { - - var _TPrices1 = new ManualPriceProvider(); - var _TPrices2 = new ManualPriceProvider(); - var _TPrices3 = new ManualPriceProvider(); - var _TPrices4 = new ManualPriceProvider(); - var _TPrices5 = new ManualPriceProvider(); - var _TPrices6 = new ManualPriceProvider(); - var _TPrices7 = new ManualPriceProvider(); - var _TPrices8 = new ManualPriceProvider(); - var _TPrices9 = new ManualPriceProvider(); - var _TPrices10 = new ManualPriceProvider(); - var _TPrices11 = new ManualPriceProvider(); - var _TPrices12 = new ManualPriceProvider(); - var _TPrices13 = new ManualPriceProvider(); - var _TPrices14 = new ManualPriceProvider(); - - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - foreach (var item in req.tradeList) - { - var code = item.UnderlyingCode; - - var price = req.PriceProvider.GetPrice(code); - - var pricenow = GetUnderlyingPrice(code, req.UserInfo, req.settleDate); - - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - price = pricenow; - } - else if (req.CalcMarginType == CalcMarginTypeEnum.None) - { - if (item.TradeDate?.ToString("yyyyMMdd") == req.settleDate.ToString("yyyyMMdd")) - { - price = pricenow; - } - else - { - price = (price + pricenow) / 2; - } - } - - var _mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate); - if (_mpProvider.TryGetUpdownLimit(code, out var limit, out var isFixed)) - { - if (isFixed) - { - limit /= price; - } - } - else - { - limit = 0.05; - } - - //注意:price价格可能为负值 - limit = Math.Abs(limit); - - double upPrice; - double downPrice; - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var client = helper.GetClient(item.ClientId); - - if (client == null) - { - upPrice = price * (1 + limit); - downPrice = price * (1 - limit); - } - else - { - if (string.IsNullOrWhiteSpace(client.RuleT0orT1) || client.RuleT0orT1 == "T+0") - { - upPrice = price * (1 + limit); - downPrice = price * (1 - limit); - } - else - { - var a1 = (1 + limit) * (1 + limit) - 1; - var a2 = 1 - (1 - limit) * (1 - limit); - upPrice = price * (1 + a1); - downPrice = price * (1 - a2); - } - } - - var p1 = downPrice + (upPrice - downPrice) * 1 / 13; - var p2 = downPrice + (upPrice - downPrice) * 2 / 13; - var p3 = downPrice + (upPrice - downPrice) * 3 / 13; - var p4 = downPrice + (upPrice - downPrice) * 4 / 13; - var p5 = downPrice + (upPrice - downPrice) * 5 / 13; - var p6 = downPrice + (upPrice - downPrice) * 6 / 13; - var p7 = downPrice + (upPrice - downPrice) * 7 / 13; - var p8 = downPrice + (upPrice - downPrice) * 8 / 13; - var p9 = downPrice + (upPrice - downPrice) * 9 / 13; - var p10 = downPrice + (upPrice - downPrice) * 10 / 13; - var p11 = downPrice + (upPrice - downPrice) * 11 / 13; - var p12 = downPrice + (upPrice - downPrice) * 12 / 13; - - _TPrices1.SetPrice(item.id.ToString(), downPrice); - _TPrices2.SetPrice(item.id.ToString(), p1); - _TPrices3.SetPrice(item.id.ToString(), p2); - _TPrices4.SetPrice(item.id.ToString(), p3); - _TPrices5.SetPrice(item.id.ToString(), p4); - _TPrices6.SetPrice(item.id.ToString(), p5); - _TPrices7.SetPrice(item.id.ToString(), p6); - _TPrices8.SetPrice(item.id.ToString(), p7); - _TPrices9.SetPrice(item.id.ToString(), p8); - _TPrices10.SetPrice(item.id.ToString(), p9); - _TPrices11.SetPrice(item.id.ToString(), p10); - _TPrices12.SetPrice(item.id.ToString(), p11); - _TPrices13.SetPrice(item.id.ToString(), p12); - _TPrices14.SetPrice(item.id.ToString(), upPrice); - } - - TPrices1 = _TPrices1; - TPrices2 = _TPrices2; - TPrices3 = _TPrices3; - TPrices4 = _TPrices4; - TPrices5 = _TPrices5; - TPrices6 = _TPrices6; - TPrices7 = _TPrices7; - TPrices8 = _TPrices8; - TPrices9 = _TPrices9; - TPrices10 = _TPrices10; - TPrices11 = _TPrices11; - TPrices12 = _TPrices12; - TPrices13 = _TPrices13; - TPrices14 = _TPrices14; - } - - /// - /// 获取标的现价 - /// - /// - /// - /// - /// - public static double GetUnderlyingPrice(string underlyingCode, OptUserInfo CurUser, DateTime? tradeDate = null) - { - double price = 0; - - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); - - SyntheticPriceModel synthetic = null; - - if (udm != null) - { - if (udm.CommodityCode == "组合标的") - { - synthetic = new SyntheticUnderlyingPriceService(CurUser).GetPriceModel(underlyingCode); - price = synthetic.Price; - } - else - { - price = udm.Price ?? 0; - } - if (tradeDate != null && tradeDate != valuedateBLL.ValueDate) - { - if (EodPriceQueryService.TryGetEodPrice(Convert.ToDateTime(tradeDate), underlyingCode, out var eodPrice)) - { - price = eodPrice.ClosePrice; - } - } - } - - return price; - } - - - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); - - foreach (var clientGroup in clientGroups) - { - var underlyingGroup = clientGroup.GroupBy(t => t.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - Spv1 = -t.Sum(g => g.Spv1), - Spv2 = -t.Sum(g => g.Spv2), - Spv3 = -t.Sum(g => g.Spv3), - Spv4 = -t.Sum(g => g.Spv4), - Spv5 = -t.Sum(g => g.Spv5), - Spv6 = -t.Sum(g => g.Spv6), - Spv7 = -t.Sum(g => g.Spv7), - Spv8 = -t.Sum(g => g.Spv8), - Spv9 = -t.Sum(g => g.Spv9), - Spv10 = -t.Sum(g => g.Spv10), - Spv11 = -t.Sum(g => g.Spv11), - Spv12 = -t.Sum(g => g.Spv12), - Spv13 = -t.Sum(g => g.Spv13), - Spv14 = -t.Sum(g => g.Spv14), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - }).ToList(); - - foreach (var item in underlyingGroup) - { - item.SetWorstCastClientPayableMin(); - item.WorstCastClientPayable = Math.Min((double)item.WorstCastClientPayable, 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else if (item.WorstCastClientPayable == item.Spv7) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - else if (item.WorstCastClientPayable == item.Spv8) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8); - } - else if (item.WorstCastClientPayable == item.Spv9) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv9); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv9); - } - else if (item.WorstCastClientPayable == item.Spv10) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv10); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv10); - } - else if (item.WorstCastClientPayable == item.Spv11) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv11); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv11); - } - else if (item.WorstCastClientPayable == item.Spv12) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv12); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv12); - } - else if (item.WorstCastClientPayable == item.Spv13) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv13); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv13); - } - else if (item.WorstCastClientPayable == item.Spv14) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv14); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv14); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - #endregion - } - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - Spv5 = underlyingGroup.Sum(g => g.Spv5), - Spv6 = underlyingGroup.Sum(g => g.Spv6), - Spv7 = underlyingGroup.Sum(g => g.Spv7), - Spv8 = underlyingGroup.Sum(g => g.Spv8), - Spv9 = underlyingGroup.Sum(g => g.Spv9), - Spv10 = underlyingGroup.Sum(g => g.Spv10), - Spv11 = underlyingGroup.Sum(g => g.Spv11), - Spv12 = underlyingGroup.Sum(g => g.Spv12), - Spv13 = underlyingGroup.Sum(g => g.Spv13), - Spv14 = underlyingGroup.Sum(g => g.Spv14), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 - }; - clientSpanNews.Add(clientSpan); - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - db.client_span.AddRange(clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - - - /// - /// 获取初始预付金率 - /// - /// - /// - public double? GetInitialMarginRatio(trade trade) - { - if (trade == null) - { - return 0; - } - if (!trade.VarietyId.HasValue || trade.VarietyId <= 0) - { - return 0; - } - if (trade.StockEqvNotional == 0) - { - return 0; - } - var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0); - if (variety == null) - { - return 0; - } - - //OTC-8856 Start - var UpLimitValue = variety.UpLimitValue; - //var UpLimitValue =((Math.Abs(trade.Underlying.UpDownLimitValue) > 1e-5) ? trade.Underlying.UpDownLimitValue : variety.UpLimitValue); - //End - - if (trade.StockEqvNotional <= 5000000) - { - return 2 * UpLimitValue; - } - else if (trade.StockEqvNotional <= 10000000) - { - return 2.5 * UpLimitValue; - } - else if (trade.StockEqvNotional <= 20000000) - { - return 3 * UpLimitValue; - } - return null; - } - - /// - /// 获取维持预付金率 - /// - /// - /// - public double? GetPositionMarginRatio(trade trade) - { - if (trade == null) - { - return 0; - } - if (!trade.VarietyId.HasValue || trade.VarietyId <= 0) - { - return 0; - } - if (trade.StockEqvNotional == 0) - { - return 0; - } - - //underlying_manager - - - var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0); - if (variety == null) - { - return 0; - } - if (trade.StockEqvNotional <= 5000000) - { - return 1.5 * variety.UpLimitValue; - } - else if (trade.StockEqvNotional <= 10000000) - { - return 2 * variety.UpLimitValue; - } - else if (trade.StockEqvNotional <= 20000000) - { - return 2.5 * variety.UpLimitValue; - } - return null; - } - - /// - /// 获取初始预付金 - /// - /// - /// - //public double GetInitialMargin(trade trade) - //{ - // return DoInitialMarginCalculationV2(trade); - //} - - //public double DoInitialMarginCalculationV2(trade trade) - //{ - // if (trade.BuySell == "卖出") - // { - // return 0; - // } - - // var underlying = DataCacheManager.GetUnderlyingDataSource().GetData(trade.UnderlyingId); - // underlying.QuotationDate = trade.TradeDate; - - // var spotPrices = new double[] { trade.SpotPrice ?? 0 }; - - // string userGroup = UserBLL.GetUserGroup(trade.TraderId ?? 0); - // var volSurfaceData = VolatilityHelper.GetVol(underlying.QuotationDate.Value, "交易", underlying.UnderlyingCode, userGroup); - - // var vol = OptionCalculator.GetInterpolatedVol( - // VolConstructionType.Normal, - // trade.OptId.ToString(), - // volSurfaceData, - // underlying.QuotationDate?.ToString("yyyy-MM-dd"), - // underlying.UnderlyingCode, - // trade.ExerciseDate?.ToString("yyyy-MM-dd"), - // trade.Strike ?? 0.0, - // isBuy: true, - // isCall: trade.CallPut == "Call", - // spotPrice: spotPrices[0], - // isMoneynessOption: trade.IsMoneynessOptionData, - // timeToMaturityDays: trade.TTMDays ?? double.NaN); - - // if (!trade.NoRiskRate.HasValue) - // { - // trade.NoRiskRate = (valuedateBLL.SystemDate.RiskFreeRate ?? 0) * 0.01; - // } - - // string fixing = null; - // //亚式期权 - // if (trade.TradeType == "亚式期权" || trade.StructureType == "亚式熊市价差") - // { - // fixing = TradeCalcHelper.GetFixingStringForAsianOption(trade, trade.TradeDate); - // } - // var optionValue = ValueCalculator.GetOptionValueResultV2( - // trade.OptId.ToString(), - // underlying, - // trade, - // new double[] { vol }, - // spotPrices, - // fixing, - // preciseTimeMode: true); - // //预付金初始价值=期初期权价值+CashDelta(t)*预付金初始比例(预付金初始比例) - // return (trade.TradePrice ?? 0) + ((optionValue == null) ? 0 : Math.Abs(optionValue.DeltaCash)) * (trade.InitialMarginRatio ?? 0); - //} - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GDGZMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GDGZMarginCalculation.cs deleted file mode 100644 index 54fd21e1..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GDGZMarginCalculation.cs +++ /dev/null @@ -1,513 +0,0 @@ -using Qdp.Pricing.Base.Implementations; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class GDGZMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例(单例模式) - public static readonly GDGZMarginCalculation Instance; - - static GDGZMarginCalculation() - { - Instance = new GDGZMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private GDGZMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(0); - } - - return new InnerRunMarginCalculation(req, _underlyingDataProvider).CalcMargin(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); - foreach (var clientGroup in clientGroups) - { - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = -clientGroup.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 - }; - clientSpanNews.Add(clientSpan); - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - db.client_span.AddRange(clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - - /// - /// 内部计算交易预付金类 - /// - class InnerRunMarginCalculation - { - readonly RunMarginCalculationReq _req; - readonly List _tradeSpans; - readonly bool _isInitialMargin; - readonly RunMarginCalculationHelper _helper; - - MarginParamProvider _mpProvider; - - public InnerRunMarginCalculation(RunMarginCalculationReq req, UnderlyingDataProvider underlyingDataProvider) - { - _req = req; - _tradeSpans = new List(); - _isInitialMargin = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin; - _helper = new RunMarginCalculationHelper(_req, underlyingDataProvider); - } - - public List CalcMargin() - { - _tradeSpans.Clear(); - - if (_req.tradeList == null || !_req.tradeList.Any()) - { - return _tradeSpans; - } - - //设置详细信息 - _helper.SetFieldsByTradeType(); - - //计算一组数据的交易风险指标 - var calcReq = _helper.GetCalculateRisksForTradesReq( - priceProvider: _req.PriceProvider, - addVolRateDic: null, overrideVols: null, - pricingRequest: PricingRequest.Pv | PricingRequest.Delta | PricingRequest.Gamma); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results.Count < 1) - { - return _tradeSpans; - } - - //跨式组合 - var tradeStraddleList = new List(); - - //结构化交易组合 - var tradeStructureList = new List(); - - //这个循环只处理最简单的情况 - foreach (var item in tradeRiskResult.Results) - { - if (item.Trade.StructureType == "跨式组合" || item.Trade.StructureType == "宽跨式组合") - { - tradeStraddleList.Add(item); - } - else if (item.Trade.StructureType == "结构化交易") - { - tradeStructureList.Add(item); - } - else - { - ProcessSingleTrade(item); - } - } - - //处理跨式交易 - var groups = tradeStraddleList.GroupBy(n => n.Trade.ParentTradeId); - foreach (var grp in groups) - { - ProcessStraddleTrades(grp.ToArray()); - } - - //处理结构化组合交易 - groups = tradeStructureList.GroupBy(n => n.Trade.ParentTradeId); - foreach (var grp in groups) - { - ProcessStructureTrades(grp.ToArray()); - } - - return _tradeSpans; - } - - /// - /// 处理单个交易 - /// - private void ProcessSingleTrade(TradeRiskResultRecord item) - { - var margin = GetUpDownEffectValue(item.ValueResult, out var updownLimit); - - if (!_isInitialMargin) - { - margin += item.ValueResult.Pv; - margin = GetRealMargin(margin, item.Trade.BuySell, item.Trade.ClientId, out _); - } - else if (item.Trade.BuySell == "卖出") - { - margin = -margin; - } - - var tradeSpan = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(margin); - - tradeSpan.Comment = GetComment(item.ValueResult, updownLimit); - - _tradeSpans.Add(tradeSpan); - } - - /// - /// 处理跨式交易 - /// - private void ProcessStraddleTrades(TradeRiskResultRecord[] items) - { - var firstItem = items[0]; - - //组内只有一条交易 - if (items.Length == 1) - { - ProcessSingleTrade(firstItem); - return; - } - - //初始预付金:两腿初始预付金平分 - //跨式组合的两腿交易方向是一致的 - if (_isInitialMargin) - { - var spans1 = items.Select(n => - { - var tradeSpan = _helper.CreateTradeSpan(n.Trade); - tradeSpan.WorstCastClientPayable = n.ValueResult.Pv + GetUpDownEffectValue(n.ValueResult, out var updownLimit); - tradeSpan.Comment = GetComment(n.ValueResult, updownLimit); - return tradeSpan; - }).ToArray(); - - var margin = spans1.Average(n => n.WorstCastClientPayable ?? 0); - - if (firstItem.Trade.BuySell == "卖出") - { - margin = -margin; - } - - foreach (var span in spans1) - { - span.SetAllSpvAndWorst(margin); - } - - _tradeSpans.AddRange(spans1); - - return; - } - - //持仓预付金 - //一腿预付金为期末结算收支 - //另一腿预付金为期末结算收支+两腿标的涨跌停造成期权价值变化孰大者 - - var maxEffectVal = 0d; - var lastItem = items.Last(); - InnerClient client = null; - - var spans2 = items.Select(n => - { - var effectVal = GetUpDownEffectValue(n.ValueResult, out var updownLimit); - - maxEffectVal = Math.Max(maxEffectVal, effectVal); - - var tradeSpan = _helper.CreateTradeSpan(n.Trade); - - tradeSpan.Comment = GetComment(n.ValueResult, updownLimit); - - var margin = n == lastItem ? n.ValueResult.Pv + maxEffectVal : n.ValueResult.Pv; - - if (client != null && client.ClientId == n.Trade.ClientId) - { - margin = GetRealMargin(margin, n.Trade.BuySell, (MarginOptionEnum)client.MarginOptionType); - } - else - { - margin = GetRealMargin(margin, n.Trade.BuySell, n.Trade.ClientId, out client); - } - - //设置预付金 - tradeSpan.SetAllSpvAndWorst(margin); - - return tradeSpan; - }); - - _tradeSpans.AddRange(spans2); - } - - /// - /// 处理结构化组合交易 - /// - private void ProcessStructureTrades(TradeRiskResultRecord[] items) - { - var firstItem = items[0]; - InnerClient client = null; - client = _helper.GetClient(firstItem.Trade.ClientId); - double margin = 0d, updownLimit = 0; - //远期:光子买的腿,初始预付金为期初权利金*2,持仓预付金计算公式与香草一致 - if (firstItem.Trade.TradeNumber.Contains("FWD")) - { - foreach (var item in items) - { - if (_isInitialMargin) - { - if (item.Trade.BuySell == "买入") - { - updownLimit = 0; - margin = item.ValueResult.Pv * 2; - } - else - { - margin = -GetUpDownEffectValue(item.ValueResult, out updownLimit); - } - } - else - { - margin = item.ValueResult.Pv + GetUpDownEffectValue(item.ValueResult, out updownLimit); - if (client != null && client.ClientId == item.Trade.ClientId) - { - margin = GetRealMargin(margin, item.Trade.BuySell, (MarginOptionEnum)client.MarginOptionType); - } - else - { - margin = GetRealMargin(margin, item.Trade.BuySell, item.Trade.ClientId, out client); - } - } - - var tradeSpan = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(margin); - - tradeSpan.Comment = GetComment(item.ValueResult, updownLimit); - - _tradeSpans.Add(tradeSpan); - } - - return; - } - - //价差 - if (firstItem.Trade.TradeNumber.Contains("SPD")) - { - //行权价 K1=4000,K2=4500,Notional=10: - //单向追保: - //1.交易员买入,预付金5000 - //2.交易员卖出,预付金0 - //双向追保: - //1.交易员买入,预付金5000 - //2.交易员卖出,预付金 - 5000 - //对手方单向追保: - //1.交易员买入,预付金0 - //2.交易员卖出,预付金 - 5000 - //双向追保 交易员买入 买入 + 卖出 0 - // 卖出 买入 0 卖出 - - - var sumBuy = items.Sum(n => n.Trade.BuySell == "买入" ? (n.Trade.TradePrice ?? 0) : 0); - var sumSell = items.Sum(n => n.Trade.BuySell == "买入" ? 0 : (n.Trade.TradePrice ?? 0)); - - //行权价之差的绝对值,因为取得时总和的绝对值所以在任何方向取负值都没问题 - var strikeDiff = Math.Abs(items.Sum(n => (n.Trade.BuySell == "买入" ? -1 : 1) * (n.Trade.Strike ?? 0) * n.Trade.TradeAmount)); - - //交易员买入价差 - if (sumBuy > sumSell) - { - if ((MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.对手方单向追保) - { - margin = 0; - } - else - { - margin = strikeDiff; - } - //最后一笔交易员买入 - var lastItem = items.LastOrDefault(n => n.Trade.BuySell == "买入"); - - var spans = items.Select(n => - { - var tradeSpan = _helper.CreateTradeSpan(n.Trade); - if (n == lastItem) - { - tradeSpan.SetAllSpvAndWorst(margin); - tradeSpan.Comment = "客户卖出价差LAST"; - } - else - { - tradeSpan.Comment = "客户卖出价差"; - } - return tradeSpan; - }).ToArray(); - _tradeSpans.AddRange(spans); - - } - else - { - //最后一笔客户卖出腿/交易员买入 - var lastItem = items.LastOrDefault(n => n.Trade.BuySell == "买入"); - if ((MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.单向追保) - { - margin = 0; - } - else - { - margin = -strikeDiff; - } - var spans = items.Select(n => - { - var tradeSpan = _helper.CreateTradeSpan(n.Trade); - if ((n == lastItem && (MarginOptionEnum)client.MarginOptionType != MarginOptionEnum.双向追保) || (n != lastItem && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.双向追保)) - { - tradeSpan.SetAllSpvAndWorst(margin); - tradeSpan.Comment = "客户卖出价差LAST"; - } - else - { - tradeSpan.Comment = "客户卖出价差"; - } - return tradeSpan; - }).ToArray(); - - _tradeSpans.AddRange(spans); - } - } - else - { - foreach (var item in items) - { - ProcessSingleTrade(item); - } - } - } - - /// - /// 获取涨跌停造成期权价值变化 - /// - private double GetUpDownEffectValue(TradeValueResult ValueResult, out double updownLimit) - { - if (_mpProvider == null) - { - _mpProvider = new MarginParamProvider(_req.UserInfo, _req.settleDate); - } - - if (!_mpProvider.TryGetUpdownLimit(ValueResult.UnderlyingCode, out updownLimit, out _)) - { - return 0; - } - - var spotPrice = ValueResult.SpotPrice ?? 0; - - var spotPriceLimit = spotPrice * updownLimit; - - return Math.Abs(ValueResult.Delta * spotPriceLimit) + Math.Abs(ValueResult.Gamma * spotPriceLimit * spotPriceLimit) / 2; - } - - /// - /// 根据买卖方向和客户追保方向获取预付金实际取值(只用于持仓预付金) - /// - private double GetRealMargin(double margin, string buysell, int clientId, out InnerClient client) - { - client = _helper.GetClient(clientId); - - if (client != null) - { - return GetRealMargin(margin, buysell, (MarginOptionEnum)client.MarginOptionType); - } - - return margin; - } - - /// - /// 根据买卖方向和客户追保方向获取预付金实际取值(只用于持仓预付金) - /// - private static double GetRealMargin(double margin, string buysell, MarginOptionEnum marginOptionType) - { - if (marginOptionType == MarginOptionEnum.单向追保) - { - return buysell == "卖出" ? 0 : Math.Max(margin, 0); - } - - if (marginOptionType == MarginOptionEnum.对手方单向追保) - { - return buysell == "卖出" ? Math.Min(margin, 0) : 0; - } - - return margin; - } - - /// - /// 获取交易预付金备注 - /// - private static string GetComment(TradeValueResult ValueResult, double updownLimit) - { - return $"Delta:{ValueResult.Delta},closePrice:{ValueResult.SpotPrice},Gamma:{ValueResult.Gamma},updownLimit:{updownLimit:0.00%}"; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GFSMMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GFSMMarginCalculation.cs deleted file mode 100644 index 5f0df182..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GFSMMarginCalculation.cs +++ /dev/null @@ -1,906 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules; -using YLErp.Modules.ClientModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.UnderlyingModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 广发商贸 - /// - public class GFSMMarginCalculation : MarginCalculationBase - { - /// - /// 定义一个静态变量保存类的实例 - /// - public static readonly GFSMMarginCalculation Instance; - static GFSMMarginCalculation() - { - Instance = new GFSMMarginCalculation(); - } - /// - /// 定义私有结构函数,使外界不能创建该类实例 - /// - public GFSMMarginCalculation() - { - - } - /// - /// 单交易维持预付金(初始预付金) - /// - /// - /// - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var result = new List(); - var clientIds = req.tradeList.Select(s => s.ClientId); - - var marginFactorDict = new ClientMarginTemplateService(OptUserInfo.SystemUser).GetMarginFactorDict(req.settleDate, clientIds, true); - - clientIds = marginFactorDict.Where(m => m.Value.SpanRateType == DetailSpanRateTypeEnum.Span涨跌幅度2) - .Select(m => m.Key).ToList(); - - //} - //客户id和标的代码 - var span2Dict = - req.tradeList - .Where(O => clientIds.Contains(O.ClientId)) - .GroupBy(O => O.ClientId) - .ToDictionary( - K => K.Key, - V => V.Select(O => O.UnderlyingCode).ToList()); - //初始预付金在维持预付金的基础上*1.05 - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin) - { - result = calcInitialMargin(req, span2Dict, marginFactorDict); - } - else - { - result = calcPositionMargin(req, span2Dict); - } - return result; - } - /// - /// 初始预付金 - /// - /// - /// - private List calcInitialMargin(RunMarginCalculationReq req, Dictionary> span2Dict, Dictionary marginFactorDict) - { - var resultMap = new Dictionary(); - var service = new UnderlyingSpanTwoService(OptUserInfo.SystemUser); - var preValueDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - //结算价格为当前日期前一个 - req.PriceProvider = new EodPriceProvider(preValueDate).GetPriceProvider(SettlementTypeEnum.SettlePrice); - //收盘价为前一天的收盘价 - var closePriceProvider = new EodPriceProvider(preValueDate).GetPriceProvider(SettlementTypeEnum.ClosePrice); - var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - //获取涨跌停价格字典 - _helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - //获取波动率价格字典 - _helper.GetUpDownVolRateDic(out var tradeVolRateDicUp, out var tradeVolRateDicDown); - LogFactory.GetLogger().Info($"广发商贸计算初始波动率为涨:{tradeVolRateDicUp} 跌{tradeVolRateDicDown} "); - //TradeId - var clientGroup = req.tradeList.GroupBy(O => new { O.ClientId, O.UnderlyingCode }).ToDictionary(K => K.Key, V => V.ToList()); - //客户分组 - foreach (var item in clientGroup) - { - var span2rateDict = new Dictionary(); - if (span2Dict.ContainsKey(item.Key.ClientId)) - { - var undelyingCodes = span2Dict[item.Key.ClientId];//标的代码 - span2rateDict = - service.GetLatestList(undelyingCodes, req.settleDate).ToDictionary(K => K.UnderlyingCode, V => V.SpanRate ?? 0); - } - var prices = new Dictionary>(); - var pricesY = new Dictionary>(); - var umCodeList = item.Value.Select(O => O.UnderlyingCode).ToHashSet(); - foreach (var code in umCodeList) - { - double upPrice; - var downPrice = downLimitPrices.GetPrice(code); - if (span2rateDict.ContainsKey(code)) - { - var price = req.PriceProvider.GetPrice(code); - var obj = _helper.GetUpDownLimitByRate(price, span2rateDict[code]); - upPrice = obj.UpLimitPrice; - downPrice = obj.DownLimitPrice; - } - else - { - upPrice = upLimitPrices.GetPrice(code); - downPrice = downLimitPrices.GetPrice(code); - } - - var interval = (upPrice - downPrice) / 6; - LogFactory.GetLogger().Info($"广发商贸计算初始涨跌价格:{upPrice} {downPrice} 涨跌取均值所以a为涨-跌/6:{interval}"); - var closePricePrice = closePriceProvider.GetPrice(code);//收盘价 - var settlePrice = req.PriceProvider.GetPrice(code);//结算价 - LogFactory.GetLogger().Info($"广发商贸计算初始结算价格S(i,n){settlePrice}和收盘价 {closePricePrice}都为前一个交易日的"); - var forword = item.Value.Where(s => s.TradeType == "远期" || s.TradeType == "收益互换"); - var tradeRiskResult_forword = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: forword, - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: true); - foreach (var tResult in tradeRiskResult_forword.Results) - { - var t = tResult.Trade; - closePricePrice = t.SpotPrice ?? 0;//#OTC-8565 广发-远期预付金 P(T)修改为期初价格 - var initialMargin = marginFactorDict.TryGetValue(t.ClientId, out var spanConfig) ? spanConfig.InitialMarginFactor : 1.05; - //根据交易编号输出spv - if (!resultMap.TryGetValue(t.id, out var tradeSpan)) - { - resultMap[t.id] = tradeSpan = _helper.CreateTradeSpan(t); - } - if (t.TradeType == "收益互换") - { - tradeSpan.SetAllSpvAndWorst(0); - continue; - } - if (t.OptionType == "看跌") - { - tradeSpan.Spv1 = -t.TradeAmount * (settlePrice + (interval * 3) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景一和八为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+𝑎)-P(T)]={tradeSpan.Spv1}={-t.TradeAmount}* ({settlePrice} + {interval}*3)-{closePricePrice})"); - tradeSpan.Spv2 = -t.TradeAmount * (settlePrice + (interval * 2) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景二和九为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+2/3𝑎)-P(T)]={tradeSpan.Spv2}={-t.TradeAmount}* ({settlePrice} + {interval}* 2-{closePricePrice})"); - tradeSpan.Spv3 = -t.TradeAmount * (settlePrice + (interval * 1) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景三和十为:空头方向*持仓数量*" + $"[(𝑆(𝑖,𝑛)×(1+1/3𝑎)-P(T)]={tradeSpan.Spv3}={-t.TradeAmount}* ({settlePrice} + {interval * 1}-{closePricePrice})"); - tradeSpan.Spv4 = -t.TradeAmount * (settlePrice - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景四和十一为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(𝑎)-P(T)]={tradeSpan.Spv4}={-t.TradeAmount}* ({settlePrice}-{closePricePrice})"); - tradeSpan.Spv5 = -t.TradeAmount * (settlePrice - (interval * 1) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景五和十二为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-1/3𝑎)-P(T)]={tradeSpan.Spv5}={-t.TradeAmount}* ({settlePrice}-{interval}*1-{closePricePrice})"); - tradeSpan.Spv6 = -t.TradeAmount * (settlePrice - (interval * 2) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景六和十三为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-2/3𝑎)-P(T)]={tradeSpan.Spv6}={-t.TradeAmount}* ({settlePrice} - {interval}*2-{closePricePrice})"); - tradeSpan.Spv7 = -t.TradeAmount * (settlePrice - (interval * 3) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景七和十四为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-𝑎)-P(T)]={tradeSpan.Spv7}={-t.TradeAmount}* ({settlePrice} - {interval}*3)-{closePricePrice})"); - tradeSpan.Spv8 = tradeSpan.Spv1; - tradeSpan.Spv9 = tradeSpan.Spv2; - tradeSpan.Spv10 = tradeSpan.Spv3; - tradeSpan.Spv11 = tradeSpan.Spv4; - tradeSpan.Spv12 = tradeSpan.Spv5; - tradeSpan.Spv13 = tradeSpan.Spv6; - tradeSpan.Spv14 = tradeSpan.Spv7; - tradeSpan.SetWorstCastClientPayable(); - tradeSpan.Spv15 = tResult.ValueResult.Pv;//用收盘价算的持仓市值 - var variety = DataCacheProvider.GetVariety(tResult.Trade.UnderlyingCode); - var rate = variety.Margin ?? 1; - tradeSpan.Delta = t.Notional * closePricePrice * rate;//detalCash - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金持仓市值用收盘价为:{tradeSpan.Spv15}"); - } - else - { - tradeSpan.Spv1 = t.TradeAmount * (settlePrice - (interval * 3) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景一和八为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+𝑎)-P(T)]={tradeSpan.Spv1}={t.TradeAmount}* ({settlePrice}- {interval}*3) )-{closePricePrice}"); - tradeSpan.Spv2 = t.TradeAmount * (settlePrice - (interval * 2) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景二和九为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+2/3𝑎)-P(T)]={tradeSpan.Spv2}={t.TradeAmount}* ({settlePrice}- {interval} * 2-{closePricePrice})"); - tradeSpan.Spv3 = t.TradeAmount * (settlePrice - (interval * 1) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景三和十为:多头方向*持仓数量*" + $"[(𝑆(𝑖,𝑛)×(1+1/3𝑎)-P(T)]={tradeSpan.Spv3}={t.TradeAmount}* ({settlePrice}- {interval * 1}-{closePricePrice})"); - tradeSpan.Spv4 = t.TradeAmount * (settlePrice - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景四和十一为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(𝑎)-P(T)]={tradeSpan.Spv4}={t.TradeAmount}* ({settlePrice} -{closePricePrice})"); - tradeSpan.Spv5 = t.TradeAmount * (settlePrice + (interval * 1) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景五和十二为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-1/3𝑎)-P(T)]={tradeSpan.Spv5}={t.TradeAmount}* ({settlePrice}-{interval}*1-{closePricePrice})"); - tradeSpan.Spv6 = t.TradeAmount * (settlePrice + (interval * 2) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景六和十三为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-2/3𝑎)-P(T)]={tradeSpan.Spv6}={t.TradeAmount}* ({settlePrice} - {interval}*2-{closePricePrice})"); - tradeSpan.Spv7 = t.TradeAmount * (settlePrice + (interval * 3) - closePricePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金情景七和十四为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-𝑎)-P(T)]={tradeSpan.Spv7}={t.TradeAmount}* ({settlePrice} - {interval}*3)-{closePricePrice})"); - tradeSpan.Spv8 = tradeSpan.Spv1; - tradeSpan.Spv9 = tradeSpan.Spv2; - tradeSpan.Spv10 = tradeSpan.Spv3; - tradeSpan.Spv11 = tradeSpan.Spv4; - tradeSpan.Spv12 = tradeSpan.Spv5; - tradeSpan.Spv13 = tradeSpan.Spv6; - tradeSpan.Spv14 = tradeSpan.Spv7; - tradeSpan.SetWorstCastClientPayable(); - tradeSpan.Spv15 = tResult.ValueResult.Pv;//用收盘价算的持仓市值 - var variety = DataCacheProvider.GetVariety(tResult.Trade.UnderlyingCode); - var rate = variety.Margin ?? 1; - tradeSpan.Delta = t.Notional * closePricePrice * rate;//detalCash - LogFactory.GetLogger().Info($"广发商贸远期计算初始预付金持仓市值用收盘价为:{tradeSpan.Spv15}"); - - } - - tradeSpan.SetWorstCastClientPayable(); - var Margin1 = tradeSpan.WorstCastClientPayable ?? 0; - LogFactory.GetLogger().Info($"广发商贸远期初始预付金Mdetal为十四情景种最大的:{Margin1}"); - var Margin2 = (tradeSpan.Delta ?? 0) * t.MarginRate; - LogFactory.GetLogger().Info($"广发商贸远期初始预付金Mdeta2为N个合约是否则为0:{Margin2}"); - //标的持仓时值(用收盘价计算) - var presentValue = tradeSpan.Spv15 ?? 0; - LogFactory.GetLogger().Info($"广发商贸远期初始预付金标的持仓时值presentValue用收盘价计算{presentValue}"); - //判断最终应该缴纳初始预付金 - if (Margin1 > 0 && presentValue > 0) - { - tradeSpan.WorstCastClientPayable = Math.Max(Margin1, Margin2) * initialMargin; - LogFactory.GetLogger().Info($"最终预付金在Margin1和Margin2中取最大存入数据库:{tradeSpan.WorstCastClientPayable} = Math.Max({Margin1}, {Margin2})* {initialMargin};"); - } - if (Margin1 > 0 && presentValue < 0) - { - tradeSpan.WorstCastClientPayable = Margin1 * initialMargin; - LogFactory.GetLogger().Info($"判断应该缴纳初始预付金如Margin1>0&&presentValue<0))则为{tradeSpan.WorstCastClientPayable}={Margin1}结果*{initialMargin}"); - } - else - { - tradeSpan.WorstCastClientPayable = 0; - } - } - var tradeTypes = new List() { "远期", "收益互换" }; - var option = item.Value.Where(o => !tradeTypes.Contains(o.TradeType)).ToList(); - if (option.Any()) - { - prices[1] = new Dictionary(); - prices[2] = new Dictionary(); - prices[3] = new Dictionary(); - prices[4] = new Dictionary(); - prices[5] = new Dictionary(); - prices[6] = new Dictionary(); - prices[7] = new Dictionary(); - prices[8] = new Dictionary(); - prices[9] = new Dictionary(); - prices[10] = new Dictionary(); - prices[11] = new Dictionary(); - prices[12] = new Dictionary(); - prices[13] = new Dictionary(); - prices[14] = new Dictionary(); - prices[15] = new Dictionary(); - //该detal存入PV15用收盘价来计算 - prices[1][code] = settlePrice + (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景一为:𝑆(𝑖,𝑛)×(1+𝑎):{prices[1][code]}={settlePrice}+({interval}*3)"); - prices[2][code] = settlePrice + (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景二为:𝑆(𝑖,𝑛)×( 1+2/3𝑎):{prices[2][code]}={settlePrice}+({interval}*2)"); - prices[3][code] = settlePrice + (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景三为:𝑆(𝑖,𝑛)×(1+1/3𝑎):{prices[3][code]}={settlePrice}+({interval}*1)"); - prices[4][code] = settlePrice; - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景四为:𝑆(𝑖,𝑛):{prices[4][code]}={settlePrice}"); - prices[5][code] = settlePrice - (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景五为:𝑆(𝑖,𝑛)×(1–1/3 𝑎):{prices[5][code]}={settlePrice}-{interval}*1"); - prices[6][code] = settlePrice - (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景六为:𝑆(𝑖,𝑛)×(1–2/3𝑎):{prices[6][code]}={settlePrice}-{interval}*2"); - prices[7][code] = settlePrice - (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景七为:𝑆(𝑖,𝑛)×(1−𝑎):{prices[7][code]}={settlePrice}-{interval}*3"); - prices[8][code] = settlePrice + (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景八为:𝑆(𝑖,𝑛)×(1+𝑎):{prices[8][code]}={settlePrice}+({interval}*3)"); - prices[9][code] = settlePrice + (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景九为:𝑆(𝑖,𝑛)×( 1+2/3𝑎):{prices[9][code]}={settlePrice}+{interval}*2)"); - prices[10][code] = settlePrice + (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十为:𝑆(𝑖,𝑛)×(1+1/3𝑎):{prices[10][code]}={settlePrice}+{interval}*1)"); - prices[11][code] = settlePrice; - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十一为:𝑆(𝑖,𝑛):{prices[11][code]}={settlePrice}"); - prices[12][code] = settlePrice - (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十二为:𝑆(𝑖,𝑛)×(1–1/3 𝑎):{prices[12][code]}={settlePrice}-{interval}*1"); - prices[13][code] = settlePrice - (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十三为:𝑆(𝑖,𝑛)×(1–2/3𝑎):{prices[13][code]}={settlePrice}-{interval}*2"); - prices[14][code] = settlePrice - (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十四为:𝑆(𝑖,𝑛)×(1−𝑎):{prices[14][code]}={settlePrice}-{interval}*3"); - prices[15][code] = closePriceProvider.GetPrice(code); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十五收盘价算detal:{prices[15][code] = closePriceProvider.GetPrice(code)}"); - foreach (var p in prices) - { - Dictionary tradeVolRateDic = null; - if (p.Key <= 7) - { - tradeVolRateDic = tradeVolRateDicUp; - } - else if (p.Key <= 14) - { - tradeVolRateDic = tradeVolRateDicDown; - } - //var overrideVol = new Dictionary(); - //foreach (var t in option) - //{ - // overrideVol[t.id] = t.Vol ?? 0.3; - //} - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: option, - priceProvider: new ManualPriceProvider(p.Value), - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: tradeVolRateDic, - volType: valuedateBLL.SystemDate.EodSettleVolMode ?? req.volType, - //overrideVolsForTrade: overrideVol, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: true); - foreach (var risk in tradeRiskResult.Results) - { - var initialMargin = marginFactorDict.TryGetValue(risk.Trade.ClientId, out var spanConfig) ? spanConfig.InitialMarginFactor : 1.05; - //根据交易编号输出spv - if (!resultMap.TryGetValue(risk.Trade.id, out var tradeSpan)) - { - resultMap[risk.Trade.id] = tradeSpan = _helper.CreateTradeSpan(risk.Trade); - } - - LogFactory.GetLogger().Info($"期权初始预付金场景{p.Key},pv:{risk.ValueResult.Pv},price:{risk.ValueResult.SpotPrice},vol:{risk.ValueResult.Vol},t:{risk.ValueResult.PricingT},delta:{risk.ValueResult.Delta}"); - - switch (p.Key) - { - case 1: - tradeSpan.Spv1 = risk.ValueResult.Pv; - break; - case 2: - tradeSpan.Spv2 = risk.ValueResult.Pv; - break; - case 3: - tradeSpan.Spv3 = risk.ValueResult.Pv; - break; - case 4: - tradeSpan.Spv4 = risk.ValueResult.Pv; - break; - case 5: - tradeSpan.Spv5 = risk.ValueResult.Pv; - break; - case 6: - tradeSpan.Spv6 = risk.ValueResult.Pv; - break; - case 7: - tradeSpan.Spv7 = risk.ValueResult.Pv; - break; - case 8: - tradeSpan.Spv8 = risk.ValueResult.Pv; - break; - case 9: - tradeSpan.Spv9 = risk.ValueResult.Pv; - break; - case 10: - tradeSpan.Spv10 = risk.ValueResult.Pv; - break; - case 11: - tradeSpan.Spv11 = risk.ValueResult.Pv; - break; - case 12: - tradeSpan.Spv12 = risk.ValueResult.Pv; - break; - case 13: - tradeSpan.Spv13 = risk.ValueResult.Pv; - break; - case 14: - tradeSpan.Spv14 = risk.ValueResult.Pv; - break; - //pv用收盘价来结算detal - case 15: - tradeSpan.Spv15 = risk.ValueResult.Pv;//持仓市值 - var variety = DataCacheProvider.GetVariety(risk.Trade.UnderlyingCode); - var rate = variety?.Margin ?? 1; - tradeSpan.Delta = risk.ValueResult.DeltaCash * rate;//magrin2 - break; - default: - break; - } - - tradeSpan.SetWorstCastClientPayable(); - var Margin1 = tradeSpan.WorstCastClientPayable ?? 0; - LogFactory.GetLogger().Info($"广发商贸初始预付金Mdetal为十四情景种最大的:{Margin1}"); - var Margin2 = tradeSpan.Delta ?? 0; - LogFactory.GetLogger().Info($"广发商贸初始预付金Mdeta2为N个合约是:{Margin2}"); - //标的持仓时值(用收盘价计算) - var presentValue = tradeSpan.Spv15 ?? 0; - LogFactory.GetLogger().Info($"广发商贸初始预付金标的持仓时值presentValue用收盘价计算{presentValue}"); - //判断最终应该缴纳初始预付金 - if (Margin1 > 0 && presentValue > 0) - { - tradeSpan.WorstCastClientPayable = Math.Max(Margin1, Margin2) * initialMargin; - LogFactory.GetLogger().Info($"判断初始预付金Margin1 > 0 && presentValue > 0在Margin1和Margin2中取最大存入数据库:{tradeSpan.WorstCastClientPayable} = Math.Max({Margin1}, {Margin2})*{initialMargin};"); - } - else if (Margin1 > 0 && presentValue < 0) - { - tradeSpan.WorstCastClientPayable = Margin1 * initialMargin; - LogFactory.GetLogger().Info($"判断初始预付金如果(Margin1>0&&presentValue<0)则为Margin1:{tradeSpan.WorstCastClientPayable}={Margin1}*{initialMargin}"); - } - else - { - tradeSpan.WorstCastClientPayable = 0; - } - - } - } - } - } - } - return resultMap.Values.ToList(); - } - /// - /// 维持预付金 - /// - /// - /// - private List calcPositionMargin(RunMarginCalculationReq req, Dictionary> span2Dict) - { - var resultMap = new Dictionary(); - var service = new UnderlyingSpanTwoService(OptUserInfo.SystemUser); - //结算价格为 - req.PriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.SettlePrice); - //收盘 - var closePriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.ClosePrice); - var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - //获取涨跌停价格字典 - _helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - //获取波动率价格字典 - _helper.GetUpDownVolRateDic(out var tradeVolRateDicUp, out var tradeVolRateDicDown); - //TradeId - var clientGroup = req.tradeList.GroupBy(O => new { O.ClientId, O.UnderlyingCode }).ToDictionary(K => K.Key, V => V.ToList()); - //客户分组 - foreach (var item in clientGroup) - { - var span2rateDict = new Dictionary(); - if (span2Dict.ContainsKey(item.Key.ClientId)) - { - var undelyingCodes = span2Dict[item.Key.ClientId];//标的代码 - span2rateDict = - service.GetLatestList(undelyingCodes, req.settleDate).ToDictionary(K => K.UnderlyingCode, V => V.SpanRate ?? 0); - } - var prices = new Dictionary>(); - var pricesY = new Dictionary>(); - var umCodeList = item.Value.Select(O => O.UnderlyingCode).ToHashSet(); - foreach (var code in umCodeList) - { - double upPrice; - var downPrice = downLimitPrices.GetPrice(code); - if (span2rateDict.ContainsKey(code)) - { - var settlePrices = req.PriceProvider.GetPrice(code); - var obj = _helper.GetUpDownLimitByRate(settlePrices, span2rateDict[code]); - upPrice = obj.UpLimitPrice; - downPrice = obj.DownLimitPrice; - } - else - { - upPrice = upLimitPrices.GetPrice(code); - downPrice = downLimitPrices.GetPrice(code); - } - var interval = (upPrice - downPrice) / 6; - LogFactory.GetLogger().Info($"广发商贸计算维持涨跌价格:{upPrice} {downPrice} 涨跌取均值所以a为:{interval}"); - var closePrice = closePriceProvider.GetPrice(code);//收盘价 - var settlePrice = req.PriceProvider.GetPrice(code);//结算价 - LogFactory.GetLogger().Info($"广发商贸计算维持结算价格S(i,n)为:{settlePrice} "); - var forword = item.Value.Where(s => s.TradeType == "远期" || s.TradeType == "收益互换");//分组后的交易 - var tradeRiskResult_forword = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: forword, - priceProvider: closePriceProvider, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: true); - foreach (var tResult in tradeRiskResult_forword.Results) - { - var t = tResult.Trade; - closePrice = t.SpotPrice ?? 0;//#OTC-8565 广发-远期预付金 P(T)修改为期初价格 - //根据交易编号输出spv - if (!resultMap.TryGetValue(t.id, out var tradeSpan)) - { - resultMap[t.id] = tradeSpan = _helper.CreateTradeSpan(t); - } - if (t.TradeType == "收益互换") - { - tradeSpan.SetAllSpvAndWorst(0); - continue; - } - if (t.OptionType == "看跌") - { - tradeSpan.Spv1 = -t.TradeAmount * (settlePrice + (interval * 3) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景一和八为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+𝑎)-P(T)]={tradeSpan.Spv1}={-t.TradeAmount}* ({settlePrice} + {interval}*3)-{closePrice})"); - tradeSpan.Spv2 = -t.TradeAmount * (settlePrice + (interval * 2) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景二和九为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+2/3𝑎)-P(T)]={tradeSpan.Spv2}={-t.TradeAmount}* ({settlePrice} + {interval} * 2-{closePrice})"); - tradeSpan.Spv3 = -t.TradeAmount * (settlePrice + (interval * 1) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景三和十为:空头方向*持仓数量*" + $"[(𝑆(𝑖,𝑛)×(1+1/3𝑎)-P(T)]={tradeSpan.Spv3}={-t.TradeAmount}* ({settlePrice} + {interval * 1}-{closePrice})"); - tradeSpan.Spv4 = -t.TradeAmount * (settlePrice - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景四和十一为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(𝑎)-P(T)]={tradeSpan.Spv4}={-t.TradeAmount}* ({settlePrice}-{closePrice})"); - tradeSpan.Spv5 = -t.TradeAmount * (settlePrice - (interval * 1) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景五和十二为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-1/3𝑎)-P(T)]={tradeSpan.Spv5}={-t.TradeAmount}* ({settlePrice}-{interval}*1-{closePrice})"); - tradeSpan.Spv6 = -t.TradeAmount * (settlePrice - (interval * 2) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景六和十三为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-2/3𝑎)-P(T)]={tradeSpan.Spv6}={-t.TradeAmount}* ({settlePrice} - {interval}*2-{closePrice})"); - tradeSpan.Spv7 = -t.TradeAmount * (settlePrice - (interval * 3) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景七和十四为:空头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-𝑎)-P(T)]={tradeSpan.Spv7}={-t.TradeAmount}* ({settlePrice} - {interval}*3)-{closePrice})"); - tradeSpan.Spv8 = tradeSpan.Spv1; - tradeSpan.Spv9 = tradeSpan.Spv2; - tradeSpan.Spv10 = tradeSpan.Spv3; - tradeSpan.Spv11 = tradeSpan.Spv4; - tradeSpan.Spv12 = tradeSpan.Spv5; - tradeSpan.Spv13 = tradeSpan.Spv6; - tradeSpan.Spv14 = tradeSpan.Spv7; - tradeSpan.SetWorstCastClientPayable(); - tradeSpan.Spv15 = tResult.ValueResult.Pv;//用收盘价算的持仓市值 - var variety = DataCacheProvider.GetVariety(tResult.Trade.UnderlyingCode); - var rate = variety.Margin ?? 1; - tradeSpan.Delta = t.Notional * closePrice * rate;//detalCash - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金持仓市值用收盘价为:{tradeSpan.Spv15}"); - - } - else - { - tradeSpan.Spv1 = t.TradeAmount * (settlePrice - (interval * 3) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景一和八为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+𝑎)-P(T)]={tradeSpan.Spv1}={t.TradeAmount}* ({settlePrice}- {interval}*3) -{closePrice})"); - tradeSpan.Spv2 = t.TradeAmount * (settlePrice - (interval * 2) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景二和九为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1+2/3𝑎)-P(T)]={tradeSpan.Spv2}={t.TradeAmount}* ({settlePrice}- {interval}* 2-{closePrice})"); - tradeSpan.Spv3 = t.TradeAmount * (settlePrice - (interval * 1) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景三和十为:多头方向*持仓数量*" + $"[(𝑆(𝑖,𝑛)×(1+1/3𝑎)-P(T)]={tradeSpan.Spv3}={t.TradeAmount}* ({settlePrice}- {interval * 1}-{closePrice})"); - tradeSpan.Spv4 = t.TradeAmount * (settlePrice - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景四和十一为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(𝑎)-P(T)]={tradeSpan.Spv4}={t.TradeAmount}* ({settlePrice}-{closePrice})"); - tradeSpan.Spv5 = t.TradeAmount * (settlePrice + (interval * 1) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景五和十二为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-1/3𝑎)-P(T)]={tradeSpan.Spv5}={t.TradeAmount}* ({settlePrice}-{interval}*1)-{closePrice}"); - tradeSpan.Spv6 = t.TradeAmount * (settlePrice + (interval * 2) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景六和十三为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-2/3𝑎)-P(T)]={tradeSpan.Spv6}={t.TradeAmount}* ({settlePrice} - {interval}*2)-{closePrice}"); - tradeSpan.Spv7 = t.TradeAmount * (settlePrice + (interval * 3) - closePrice); - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金情景七和十四为:多头方向*持仓数量*[(𝑆(𝑖,𝑛)×(1-𝑎)-P(T)]={tradeSpan.Spv7}={t.TradeAmount}* ({settlePrice} - {interval}*3)-{closePrice})"); - tradeSpan.Spv8 = tradeSpan.Spv1; - tradeSpan.Spv9 = tradeSpan.Spv2; - tradeSpan.Spv10 = tradeSpan.Spv3; - tradeSpan.Spv11 = tradeSpan.Spv4; - tradeSpan.Spv12 = tradeSpan.Spv5; - tradeSpan.Spv13 = tradeSpan.Spv6; - tradeSpan.Spv14 = tradeSpan.Spv7; - tradeSpan.SetWorstCastClientPayable(); - tradeSpan.Spv15 = tResult.ValueResult.Pv;//用收盘价算的持仓市值 - var variety = DataCacheProvider.GetVariety(tResult.Trade.UnderlyingCode); - var rate = variety.Margin ?? 1; - tradeSpan.Delta = t.Notional * closePrice * rate;//detalCash - - LogFactory.GetLogger().Info($"广发商贸远期计算维持预付金持仓市值用收盘价为:{tradeSpan.Spv15}"); - - } - } - var tradeTypes = new List() { "远期", "收益互换" }; - var option = item.Value.Where(o => !tradeTypes.Contains(o.TradeType)).ToList(); - if (option.Any()) - { - prices[1] = new Dictionary(); - prices[2] = new Dictionary(); - prices[3] = new Dictionary(); - prices[4] = new Dictionary(); - prices[5] = new Dictionary(); - prices[6] = new Dictionary(); - prices[7] = new Dictionary(); - prices[8] = new Dictionary(); - prices[9] = new Dictionary(); - prices[10] = new Dictionary(); - prices[11] = new Dictionary(); - prices[12] = new Dictionary(); - prices[13] = new Dictionary(); - prices[14] = new Dictionary(); - prices[15] = new Dictionary(); - //该detal存入PV15用收盘价来计算 - prices[1][code] = settlePrice + (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算维持预付金情景一为:𝑆(𝑖,𝑛)×(1+𝑎):{prices[1][code]}={settlePrice}+({interval}*3)"); - prices[2][code] = settlePrice + (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算维持预付金情景二为:𝑆(𝑖,𝑛)×( 1+2/3𝑎):{prices[2][code]}={settlePrice}+({interval}*2)"); - prices[3][code] = settlePrice + (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景三为:𝑆(𝑖,𝑛)×(1+1/3𝑎):{prices[3][code]}={settlePrice}+({interval}*1)"); - prices[4][code] = settlePrice; - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景四为:𝑆(𝑖,𝑛):{prices[4][code]}={settlePrice}"); - prices[5][code] = settlePrice - (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景五为:𝑆(𝑖,𝑛)×(1–1/3 𝑎):{prices[5][code]}={settlePrice}-{interval}*1"); - prices[6][code] = settlePrice - (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景六为:𝑆(𝑖,𝑛)×(1–2/3𝑎):{prices[6][code]}={settlePrice}-{interval}*2"); - prices[7][code] = settlePrice - (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景七为:𝑆(𝑖,𝑛)×(1−𝑎):{prices[7][code]}={settlePrice}-{interval}*3"); - prices[8][code] = settlePrice + (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景八为:𝑆(𝑖,𝑛)×(1+𝑎):{prices[8][code]}={settlePrice}+({interval}*3)"); - prices[9][code] = settlePrice + (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景九为:𝑆(𝑖,𝑛)×( 1+2/3𝑎):{prices[9][code]}={settlePrice}+{interval}*2)"); - prices[10][code] = settlePrice + (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十为:𝑆(𝑖,𝑛)×(1+1/3𝑎):{prices[10][code]}={settlePrice}+{interval}*1)"); - prices[11][code] = settlePrice; - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十一为:𝑆(𝑖,𝑛):{prices[11][code]}={settlePrice}"); - prices[12][code] = settlePrice - (interval * 1); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十二为:𝑆(𝑖,𝑛)×(1–1/3 𝑎):{prices[12][code]}={settlePrice}-{interval}*1"); - prices[13][code] = settlePrice - (interval * 2); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十三为:𝑆(𝑖,𝑛)×(1–2/3𝑎):{prices[13][code]}={settlePrice}-{interval}*2"); - prices[14][code] = settlePrice - (interval * 3); - LogFactory.GetLogger().Info($"广发商贸期权计算初始预付金情景十四为:𝑆(𝑖,𝑛)×(1−𝑎):{prices[14][code]}={settlePrice}-{interval}*3"); - prices[15][code] = closePriceProvider.GetPrice(code); - LogFactory.GetLogger().Info($"广发商贸期权计算维持预付金情景十五收盘价算detal:{prices[15][code] = closePriceProvider.GetPrice(code)}"); - foreach (var p in prices) - { - Dictionary tradeVolRateDic = null; - if (p.Key <= 7) - { - tradeVolRateDic = tradeVolRateDicUp; - } - else if (p.Key <= 14) - { - tradeVolRateDic = tradeVolRateDicDown; - } - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - calcScenario: req.GetCalcScenario(), - tradeList: option, - priceProvider: new ManualPriceProvider(p.Value), - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: tradeVolRateDic, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: true); - foreach (var risk in tradeRiskResult.Results) - { - var pric = p.Value[risk.Trade.UnderlyingCode]; - LogFactory.GetLogger().Info($"广发商贸持仓计算维持预付金该交易编号:{risk.Trade.TradeNumber} id:{risk.Trade.id}标的:{code} 交易价格为:{pric}"); - //根据交易编号输出spv - if (!resultMap.TryGetValue(risk.Trade.id, out var tradeSpan)) - { - resultMap[risk.Trade.id] = tradeSpan = _helper.CreateTradeSpan(risk.Trade); - } - switch (p.Key) - { - case 1: - tradeSpan.Spv1 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv1为:{tradeSpan.Spv1}"); - break; - case 2: - tradeSpan.Spv2 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv2为:{tradeSpan.Spv2}"); - break; - case 3: - tradeSpan.Spv3 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv3为:{tradeSpan.Spv3}"); - break; - case 4: - tradeSpan.Spv4 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv4为:{tradeSpan.Spv4}"); - break; - case 5: - tradeSpan.Spv5 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv5为:{tradeSpan.Spv5}"); - break; - case 6: - tradeSpan.Spv6 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv6为:{tradeSpan.Spv6}"); - break; - case 7: - tradeSpan.Spv7 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv7为:{tradeSpan.Spv7}"); - break; - case 8: - tradeSpan.Spv8 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv8为:{tradeSpan.Spv8}"); - break; - case 9: - tradeSpan.Spv9 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv9为:{tradeSpan.Spv9}"); - break; - case 10: - tradeSpan.Spv10 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv10为:{tradeSpan.Spv10}"); - break; - case 11: - tradeSpan.Spv11 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv11为:{tradeSpan.Spv11}"); - break; - case 12: - tradeSpan.Spv12 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv12为:{tradeSpan.Spv12}"); - break; - case 13: - tradeSpan.Spv13 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv13为:{tradeSpan.Spv13}"); - break; - case 14: - tradeSpan.Spv14 = risk.ValueResult.Pv; - LogFactory.GetLogger().Info($"广发商贸计算维持预付金pv14为:{tradeSpan.Spv14}"); - break; - //pv用收盘价来结算detal - case 15: - tradeSpan.Spv15 = risk.ValueResult.Pv;//持仓市值收盘价 - LogFactory.GetLogger().Info($"广发商贸计算维持情景十五用收盘价计算detal因此不参与计算为:{tradeSpan.Spv15}"); - var variety = DataCacheProvider.GetVariety(risk.Trade.UnderlyingCode); - var rate = variety.Margin ?? 1; - tradeSpan.Delta = risk.ValueResult.DeltaCash * rate;//用detal计算 - LogFactory.GetLogger().Info($"广发商贸计算维持期权Margin2为:{tradeSpan.Delta}"); - break; - default: - break; - } - //spv15不参与所以为0 - if (p.Key < 15) - { - tradeSpan.SetWorstCastClientPayable(); - } - } - } - } - } - } - return resultMap.Values.ToList(); - } - - - /// - /// 同客户预付金占用 - /// - /// - /// - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using var db = new YLContext(); - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - //客户分组 - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - var worstCastClientPayable_option = 0d; - foreach (var clientGroup in clientGroups) - { - var client = DataCacheProvider.GetClientDataSource().GetData(clientGroup.Key); - //同标的加总 - var varietyGroup = clientGroup.GroupBy(d => DataCacheProvider.GetVariety(d.trade.UnderlyingCode ?? "")?.VarietyCode ?? ""); - var pmList = new List(); - foreach (var item in varietyGroup) - { - var list = new List() - { - item.Sum(s=>s.tradeSpan.Spv1??0), - item.Sum(s=>s.tradeSpan.Spv2??0), - item.Sum(s=>s.tradeSpan.Spv3??0), - item.Sum(s=>s.tradeSpan.Spv4??0), - item.Sum(s=>s.tradeSpan.Spv5??0), - item.Sum(s=>s.tradeSpan.Spv6??0), - item.Sum(s=>s.tradeSpan.Spv7??0), - item.Sum(s=>s.tradeSpan.Spv8??0), - item.Sum(s=>s.tradeSpan.Spv9??0), - item.Sum(s=>s.tradeSpan.Spv10??0), - item.Sum(s=>s.tradeSpan.Spv11??0), - item.Sum(s=>s.tradeSpan.Spv12??0), - item.Sum(s=>s.tradeSpan.Spv13??0), - item.Sum(s=>s.tradeSpan.Spv14??0), - }; - //magrin1十四PV总和最大 - var pmi = list.Max(s => s); - LogFactory.GetLogger().Info($"广发商贸维持预付金14 种情形下客户持仓值为:" + - $"pv1{item.Sum(O => O.tradeSpan.Spv1 ?? 0)}" + - "pv2:" + $"{item.Sum(O => O.tradeSpan.Spv2 ?? 0)}" + - "pv3:" + $"{item.Sum(O => O.tradeSpan.Spv3 ?? 0)}" + - "pv4:" + $"{item.Sum(O => O.tradeSpan.Spv4 ?? 0)}" + - "pv5:" + $"{item.Sum(O => O.tradeSpan.Spv5 ?? 0)}" + - "pv6:" + $"{item.Sum(O => O.tradeSpan.Spv6 ?? 0)}" + - "pv7:" + $"{item.Sum(O => O.tradeSpan.Spv7 ?? 0)}" + - "pv8:" + $"{item.Sum(O => O.tradeSpan.Spv8 ?? 0)}" + - "pv9:" + $"{item.Sum(O => O.tradeSpan.Spv9 ?? 0)}" + - "pv10:" + $"{item.Sum(O => O.tradeSpan.Spv10 ?? 0)}" + - "pv11:" + $"{item.Sum(O => O.tradeSpan.Spv11 ?? 0)}" + - "pv12:" + $"{item.Sum(O => O.tradeSpan.Spv12 ?? 0)}" + - "pv13:" + $"{item.Sum(O => O.tradeSpan.Spv13 ?? 0)}" + - "pv14:" + $"{item.Sum(O => O.tradeSpan.Spv14 ?? 0)}取最大所以广发商贸该客户magrin1为:{pmi}"); - //magrin2为detal - var pmMargin2 = item.Sum(s => s.tradeSpan.Delta ?? 0); - LogFactory.GetLogger().Info($"广发商贸该客户magrin2为:{pmMargin2}"); - //持仓市值为Pv十五加总 - var pmt = item.Sum(s => s.tradeSpan.Spv15 ?? 0); - LogFactory.GetLogger().Info($"广发商贸该客户持仓市值为:{pmt}"); - double endMoney = 0; - if (pmi > 0 && pmt > 0) - { - endMoney = Math.Max(pmi, pmMargin2); - LogFactory.GetLogger().Info($"广发商贸该客户14PV持仓市值都大于0两者取最大为:{endMoney}"); - } - else if (pmi > 0 && pmt < 0) - { - endMoney = pmi; - LogFactory.GetLogger().Info($"广发商贸该客户14PV大于0和持仓市值小于0则取最大pv为:{endMoney}"); - } - else - { - endMoney = 0; - } - LogFactory.GetLogger().Info($"广发商贸该客户相比结果最后为:{endMoney}"); - - if (endMoney < 0 && client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - endMoney = 0; - } - pmList.Add(endMoney); - } - //期权汇总 - var pml = pmList.Sum(); - LogFactory.GetLogger().Info($"广发商贸该客户预付金期权+远期(多标的汇总一起有可能为负所以加总也有可能会变小):{pml}"); - //该客户该日期的总交易为:期权+远期 - worstCastClientPayable_option = pml; - //产品确认暂不分配 - //var tradeSpansUpdate = db.trade_span.Where(x => tradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - //var tradeSpansReq = req.tradeSpans.Where(x => tradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - //var sumDelta = clientGroup.Sum(O => Math.Max(O.tradeSpan.Delta ?? 0, 0)); - //tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = worstCastClientPayable_option * Math.Max(x.Delta ?? 0, 0) / sumDelta); - //tradeSpansReq.ForEach(x => x.WorstCastClientPayable = worstCastClientPayable_option * Math.Max(x.Delta ?? 0, 0) / sumDelta); - worstCastClientPayable_option *= -1; - LogFactory.GetLogger().Info($"广发商贸未分配前期权远期:{worstCastClientPayable_option}"); - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key,//客户名称 - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = worstCastClientPayable_option,//期权和远期同标的加总一起 - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(1, out var dd) ? dd : 0 - }; - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable.Value, 0); - LogFactory.GetLogger().Info($"广发商贸单向追保时与0相比取最小:{clientSpan.WorstCastClientPayable}"); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - clientSpan.WorstCastClientPayable = clientSpan.WorstCastClientPayable.Value; - LogFactory.GetLogger().Info($"广发商贸双向追保时汇总为(正/负):{clientSpan.WorstCastClientPayable}"); - } - clientSpanNews.Add(clientSpan); - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}={req.SpanType}"); - } - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - //MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - db.client_span.AddRange(clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - /// - /// 结构化交易特殊处理 - /// - /// - /// - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin && tradeMargin.FirstOrDefault() != null) - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - - return margin; - } - return 0.0; - } - } -} \ No newline at end of file diff --git a/YLErpDAL/BLL/MarginCalculation/GQMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GQMarginCalculation.cs deleted file mode 100644 index 068e64ff..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GQMarginCalculation.cs +++ /dev/null @@ -1,333 +0,0 @@ -using Qdp.Pricing.Library.Base.Utilities; -using System.Linq; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules.ApiModule; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 广期资本 - /// - public class GQMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly GQMarginCalculation Instance; - - static GQMarginCalculation() - { - Instance = new GQMarginCalculation(); - } - // 定义私有构造函数,使外界不能创建该类实例 - protected GQMarginCalculation() - { - - } - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var resultMap = new List(); - resultMap.AddRange(marginCalculation(req)); - return resultMap; - } - /// - /// 计算同一交易 - /// - /// - /// - private List marginCalculation(RunMarginCalculationReq req) - { - //结果集 - var resultMap = new Dictionary(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - //var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - helper.SetFieldsByTradeType(); - //取出张跌停价格 - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - //up涨停价 //down跌停价 //normal期权价 - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) };//期初价格 - - foreach (var price in prices) - { - var key = $"{price.Item1}"; - //计算交易风险指标 计算Pv - var tradeRiskResult2 = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: req.tradeList, - calcScenario: req.GetCalcScenario(),//日终持仓预付金 - priceProvider: price.Item2,//计算接口期初价格 - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: null, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - - if (tradeRiskResult2.Results == null || tradeRiskResult2.Results.Count < 1) - { - continue; - } - foreach (var item in tradeRiskResult2.Results) - { - //var client= helper.GetClient(item.Trade.ClientId); - //获取交易值和span - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - var value = item.ValueResult.Pv; - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - switch (key) - { - //算出三个pv - case "up": - tempTradeSpan.Spv1 = value; - break; - case "normal": - tempTradeSpan.Spv2 = value; - tempTradeSpan.Comment += " normal:" + item.ValueResult.Pv.ToString() + " ;"; - break; - case "down": - tempTradeSpan.Spv3 = value; - tempTradeSpan.Comment += " down:" + item.ValueResult.Pv.ToString() + " ;"; - break; - } - // tempTradeSpan.Spv4 = item.Trade.TradePrice; - double key_up = 0; - double key_down = 0; - //该笔交易涨跌停盈亏为卖出并且期初权利金为0 - if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0) - { - key_up = Math.Max((tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0); - logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}"); - } - else - { - key_up = (tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0); - logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}"); - } - //跌停盈亏 - if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0) - { - key_down = Math.Max((tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0); - logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} "); - } - else - { - key_down = (tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0); - logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} "); - } - tempTradeSpan.WorstCastClientPayable = Math.Max(key_up, key_down); - LogFactory.GetLogger("涨跌盈亏最大").Info(tempTradeSpan.WorstCastClientPayable.ToString()); - } - } - return resultMap.Values.ToList(); - - } - /// - /// 计算同一客户 - /// - /// - /// - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var trades = req.tradeSpans; - var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId); - foreach (var clientGroup in clientGroups) - { - var underlyingMarginDic = new Dictionary(); - var vIds = clientGroup.Select(o => o.VarietyId).Distinct();//所有品种 - //计算出所有标的pv - foreach (var ts in clientGroup) - { - var td = trades.FirstOrDefault(o => o.id == ts.TradeId); - var key = ts.UnderlyingCode + "_" + ts.VarietyId.ToString();// + "_" + td.BuySell;标的 ///VarietyId品种ID - if (!underlyingMarginDic.ContainsKey(key)) - { - underlyingMarginDic.Add(key, new double?[3] { ts.Spv1, ts.Spv2, ts.Spv3 }); - } - else - { - var us = underlyingMarginDic[key]; - us[0] += ts.Spv1; - us[1] += ts.Spv2; - us[2] += ts.Spv3; - } - } - //标的层面的盈亏 - var underlyingMargins = new Dictionary(); - var VarietyMarginsByUpDown = new Dictionary(); - var VarietyMargins = new Dictionary(); - foreach (var item in underlyingMarginDic) - { - var uvCode = item.Key; - var key_up = uvCode + "_up"; - //uvCode.Split('_')[0] + "_" + uvCode.Split('_')[1] - var key_down = uvCode + "_down"; - if (!underlyingMargins.ContainsKey(key_up)) - { - //与0相比取最大 - underlyingMargins.Add(key_up, Math.Max((item.Value[0] ?? 0) - (item.Value[1] ?? 0), 0)); - LogFactory.GetLogger("标的合约下所有的盈利合计= pv1-pv").Info($"{underlyingMargins.Values.ToString()}={(item.Value[0] ?? 0)} -{(item.Value[1] ?? 0)},0)"); - } - if (!underlyingMargins.ContainsKey(key_down)) - { - //与0相比 - underlyingMargins.Add(key_down, Math.Max((item.Value[2] ?? 0) - (item.Value[1] ?? 0), 0)); - LogFactory.GetLogger("标的合约下所有的亏损合计= pv-pv2").Info($"{underlyingMargins.Values.ToString()}={(item.Value[1] ?? 0)} -{(item.Value[2] ?? 0)},0)"); - } - } - //计算同一客户单品标的合约盈亏累计的和 A00_Id_up/down - foreach (var item in underlyingMargins) - { - //品种 标的id盈亏 - var uvCode = item.Key; - var vId = uvCode.Split('_')[1]; - var upDown = uvCode.Split('_')[2]; - vId = vId + upDown; - if (VarietyMarginsByUpDown.ContainsKey(vId)) - { - //所有盈亏累加 - VarietyMarginsByUpDown[vId] += item.Value; - LogFactory.GetLogger("计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString()); - } - else - { - VarietyMarginsByUpDown.Add(vId, item.Value); - LogFactory.GetLogger("1计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString()); - } - } - //根据客户涨跌停品种取出合计 - foreach (var item in vIds) - { - var upCode = item.ToString() + "up"; - var downCode = item.ToString() + "down"; - try - { - var upMargin = VarietyMarginsByUpDown[upCode]; - var downMargin = VarietyMarginsByUpDown[downCode]; - if (!VarietyMargins.ContainsKey(item.ToString())) - { - //取最大 - VarietyMargins.Add(item.ToString(), Math.Max(upMargin, downMargin)); - LogFactory.GetLogger("客户涨跌停盈亏分别为:").Info($"{upMargin},{downMargin}"); - LogFactory.GetLogger("根据客户涨跌停品种判断取出合计").Info(VarietyMargins.Values.ToString()); - } - } - catch (Exception) - { - VarietyMargins.Add(item.ToString(), 0); - } - } - - foreach (var item in VarietyMargins) - { - if (int.TryParse(item.Key, out int varietyId)) - { - //根据品种 - var varietyGroup = clientGroup.Where(o => o.VarietyId == varietyId); - //var tradePricedic = trades.GroupBy(l => new { l.ClientId }).(tradePricedic.Where(t => t.kv == ts.VarietyId && t.kc == ts.ClientId).FirstOrDefault()?.v) ?item.Value : 0; - //Select(s => new { kc = s.Key.ClientId, v = Math.Min(s.Sum(item.Key) ?? 0,0) }); - var t = 0; - foreach (var ts in varietyGroup) - { - //所有单客户品种所有标的期初取最小 //因为不与单客户收支比较因此取客户涨停盈亏合计 - // var sh = Math.Max(varietyGroup.Sum(s => s.Spv4) ?? 0, 0); - //单品种维持预付金 - var aa = item.Value; //> sh ? item.Value : 0; - var dbts = db.trade_span.FirstOrDefault(o => o.id == ts.id); - if (dbts != null) - { - dbts.WorstCastClientPayable = t == 0 ? aa : 0;//将多笔交易放到一笔交易 - logger.Info($"单客户涨跌停品种盈亏合计为{aa}"); - } - var dbts1 = req.tradeSpans.FirstOrDefault(o => o.id == ts.id); - dbts1.WorstCastClientPayable = t == 0 ? aa : 0; - t++; - } - } - } - //所有品种维持预付金加总 - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key ?? 0, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = req.tradeSpans.Where(O => O.ClientId == (clientGroup.Key ?? 0)).Sum(O => O.WorstCastClientPayable ?? 0) * -1, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 - }; - LogFactory.GetLogger("该客户当日维持预付金所有预付金总和:").Info(clientSpan.ToString()); - LogFactory.GetLogger("该客户当日维持预付金所有预付金VarietyMargins总和:").Info(clientSpan.VariationMargin.ToString()); - clientSpanNews.Add(clientSpan); - } - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - db.client_span.AddRange(clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GTJAMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GTJAMarginCalculation.cs deleted file mode 100644 index 79d420b1..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GTJAMarginCalculation.cs +++ /dev/null @@ -1,2718 +0,0 @@ -using Qdp.Foundation.Implementations; -using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix; -using Qdp.Pricing.Library.Options.Products.Autocall.Snowball; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.BLL.Calculation.V2; -using YLErp.DBModels.Helpers; -using YLErp.Enums; -using YLErp.Models; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.Modules.VolatilityModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 国泰君安预付金计算 - /// - public class GTJAMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly GTJAMarginCalculation Instance; - - static GTJAMarginCalculation() - { - Instance = new GTJAMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected GTJAMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - //剔除收益互换交易 - req.tradeList = req.tradeList.Where(t => t.TradeType != "收益互换").ToList(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - //商品类预付金计算 - if (!PS.Config.ErpElement.IsStockMargin) - { - return RunMarginCalculationForCommodity(helper, mpProvider); - } - //权益类预付金计算 - else - { - return new GTJAStockMarginCalculation(req, helper).Calculate(mpProvider); - } - } - - //商品类预付金计算 - private static List RunMarginCalculationForCommodity(RunMarginCalculationHelper helper, MarginParamProvider mpProvider, double extendLimitRate = 1, bool isUsePriceLimit = true, double? overrideVolRate = null) - { - var resultMap = new Dictionary(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices, extendLimitRate: extendLimitRate, isUsePriceLimit: isUsePriceLimit); - - helper.GetTradVolRateDic(out var tradeVolRateDic); - if (overrideVolRate != null) - { - tradeVolRateDic = helper.req.tradeList.Select(t => new - { - tradeId = t.id, - volRate = overrideVolRate.Value - }).ToDictionary(d => d.tradeId, d => d.volRate); - } - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string key, IPriceProvider priceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", helper.req.PriceProvider) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.key, - priceProvider = n.priceProvider, - addVolRateDic = m - })).ToArray(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value, helper.req.forOtherSide)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "normal_0": - tempTradeSpan.Spv = pv; - tempTradeSpan.Delta = item.ValueResult.Delta; - tempTradeSpan.UnderlyingPrice = helper.req.PriceProvider.GetPrice(item.ValueResult.UnderlyingCode); - mpProvider.TryGetMarginRate(item.ValueResult.UnderlyingCode, out var marginRate); - tempTradeSpan.DeltaMargin = (Math.Abs(tempTradeSpan.Delta ?? 0) * (item.Trade.BuySell == "买入" ? 1 : -1) * tempTradeSpan.UnderlyingPrice * marginRate) ?? 0; - break; - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - - tempTradeSpan.IsSpanMargin = true; - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - //获取收盘日那天对应的预付金模板 - var tradeTemplates = db.trade_margin_template.AsNoTracking().Where(t => tradeIds.Contains(t.TradeId) && t.ValueDate <= req.settleDate); - var groupQuery = from tt in tradeTemplates - group tt by tt.TradeId into tts - select new - { - TradeId = tts.Key, - ValueDate = tts.Max(n => n.ValueDate) - }; - var groupTemplates = from gq in groupQuery - join tt in tradeTemplates - on new { gq.TradeId, gq.ValueDate } equals new { tt.TradeId, tt.ValueDate } - select tt; - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new TradeSpanTemplate { trade = trade, tradeSpan = tradeSpan, marginTemplateId = tradetemplate == null ? 0 : tradetemplate.MarginTemplateId }).ToList(); - - var tradeSpanInfoOtherSide = (from tradeSpan in req.tradeSpansOtherSide - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new TradeSpanTemplate { trade = trade, tradeSpan = tradeSpan, marginTemplateId = tradetemplate == null ? 0 : tradetemplate.MarginTemplateId }).ToList(); - - //商品类预付金计算 - if (!PS.Config.ErpElement.IsStockMargin) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = tradeSpanInfo.Where(g => (g.trade.TradeType != "收益互换" || (g.trade.TradeType == "收益互换" && g.trade.IsGroup != 2))).GroupBy(t => t.trade.ClientId); - var tradeIdListAll = tradeSpanInfo.Select(x => x.trade.id).ToArray(); - var tradeSpans = db.trade_span.Where(x => tradeIdListAll.Contains(x.TradeId)).ToList(); - foreach (var clientGroup in clientGroups) - { - var clientTradeSpans = clientGroup.ToList(); - //交易员方向持仓盈亏 - var positionWinLoss = clientTradeSpans.Sum(x => (x.tradeSpan.Spv ?? 0) + (x.trade.TradePrice * x.trade.Notional / x.trade.OriginalNotional * ((x.trade.BuySell == "卖出") ? 1 : -1) ?? 0)); - - var underlyingGroupDefault = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroupDefault) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - - #endregion - } - - var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1) - }).ToList(); - - foreach (var item in underlyingGroup) - { - if (!HasTwoSideMargin(clientGroup.Key)) - { - item.DeltaMargin = Math.Min(item.DeltaMargin ?? 0, 0); - } - } - - //客户方向delta预付金 - var deltaMargin = underlyingGroup.Sum(g => (g.DeltaMargin ?? 0)) - positionWinLoss; - if (!HasTwoSideMargin(clientGroup.Key)) - { - deltaMargin = Math.Min(deltaMargin, 0); - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroupDefault.Sum(g => g.Spv1), - Spv2 = underlyingGroupDefault.Sum(g => g.Spv2), - Spv3 = underlyingGroupDefault.Sum(g => g.Spv3), - Spv4 = underlyingGroupDefault.Sum(g => g.Spv4), - //负数代表客户应缴预付金,正数代表客户应收预付金 - DeltaMargin = deltaMargin, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroupDefault.Sum(g => g.WorstCastClientPayable), - MySideMargin = underlyingGroupDefault.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroupDefault.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - //收益互换单独计算 剔除多空组合子交易 - clientSpan.SwapWorstCastClientPayable = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(g => g.tradeSpan.WorstCastClientPayable) * (-1);//收益互换预付金 - clientSpan.SwapInitMargin = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(g => g.tradeSpan.SwapInitMargin) * (-1);//收益互换预付金 - clientSpan.SwapWinLoss = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(g => g.tradeSpan.SwapWinLoss) * (-1);//收益互换预付金 - //互换容忍部分预付金(此部分不占用预付金) - clientSpan.SwapUnMargin = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2) && g.tradeSpan.Margin == 0).Sum(g => Math.Max(g.tradeSpan.SwapWinLoss ?? 0.0, 0)) * (-1); - - clientSpanNews.Add(clientSpan); - } - - //处理从客户角度的预付金计算(将交易买卖方向反向处理) - var clientGroupsOtherSide = tradeSpanInfoOtherSide.Where(g => (g.trade.TradeType != "收益互换" || (g.trade.TradeType == "收益互换" && g.trade.IsGroup != 2))).GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroupsOtherSide) - { - var underlyingGroup = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0 }.Min(); - } - var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate); - clientSpan.OtherSideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable); - - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.OtherSideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.OtherSideMargin = Math.Min(clientSpan.OtherSideMargin ?? 0, 0); - - if (HasTwoSideMargin(clientGroup.Key)) - { - clientSpan.WorstCastClientPayable = clientSpan.MySideMargin - clientSpan.OtherSideMargin; - } - } - } - } - //权益类预付金计算 - else - { - clientSpanNews = CalcEquityClientMargin(db, tradeSpanInfo, req, false); - if (tradeSpanInfoOtherSide.Any()) - { - var clientSpanOthers = CalcEquityClientMargin(db, tradeSpanInfoOtherSide, req, true); - - clientSpanNews.ForEach(clientSpan => - { - var clientSpanOther = clientSpanOthers.FirstOrDefault(x => x.ClientId == clientSpan.ClientId); - clientSpan.OtherSideMargin = clientSpanOther.WorstCastClientPayable; - if (HasTwoSideMargin(clientSpan.ClientId)) - { - clientSpan.WorstCastClientPayable = clientSpan.MySideMargin - clientSpan.OtherSideMargin; - } - }); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate, ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate }); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - - return req.tradeSpans; - } - } - - private List CalcEquityClientMargin(YLContext db, List tradeSpanInfo, CalcClientMarginReq req, bool isForOtherSide) - { - var clientSpanNews = new List(); - var defaultMarginTemplates = db.margin_template_v2.Where(x => x.IsDefault && !x.IsForClient && (x.MarginScenarios & MarginScenarioEnum.Position) > 0 && x.ValueDate <= req.settleDate).OrderByDescending(x => x.ValueDate).ToList(); - var defaultMarginTemplateIds = defaultMarginTemplates.Select(x => x.id).ToArray(); - var defaultMarginTemplateDetails = db.margin_template_detail.Where(x => defaultMarginTemplateIds.Contains(x.MarginTemplateId)).ToList(); - var groupMarginTemplates = db.margin_template_v2.Where(x => !x.IsDefault && x.MarginType == (int)MarginTypeV2Enum.多腿 && !isForOtherSide && (x.MarginScenarios & MarginScenarioEnum.Position) > 0).ToList(); - var groupMarginTemplateIds = groupMarginTemplates.Select(x => x.id).ToArray(); - var groupMarginTemplateDetails = db.margin_template_detail.Where(x => groupMarginTemplateIds.Contains(x.MarginTemplateId)).ToList(); - - var clientGroups = tradeSpanInfo.Where(g => (g.trade.TradeType != "收益互换" || (g.trade.TradeType == "收益互换" && g.trade.IsGroup != 2))).GroupBy(t => t.trade.ClientId); - var clientIds = clientGroups.Select(x => x.Key).ToArray(); - var tradeIdListAll = tradeSpanInfo.Select(x => x.trade.id).ToArray(); - var tradeSpans = db.trade_span.Where(x => tradeIdListAll.Contains(x.TradeId) && x.ValueDate == req.settleDate).ToList(); - var cmts = db.client_margin_template.Where(x => clientIds.Contains(x.ClientId) && x.ValueDate <= req.settleDate).ToList(); - var cmtIds = cmts.Select(x => x.MarginTemplateId).ToArray(); - var cMarginTemplates = db.margin_template_v2.Where(x => cmtIds.Contains(x.id) && (x.MarginScenarios & MarginScenarioEnum.Position) > 0).ToList(); - var cMarginTemplateDetails = db.margin_template_detail.Where(x => cmtIds.Contains(x.MarginTemplateId)).ToList(); - - foreach (var clientGroup in clientGroups) - { - var clientTradeSpans = clientGroup.ToList(); - //交易员方向持仓盈亏 - var positionWinLoss = clientTradeSpans.Sum(x => (x.tradeSpan.Spv ?? 0) + (x.trade.TradePrice * x.trade.Notional / x.trade.OriginalNotional * ((x.trade.BuySell == "卖出") ? 1 : -1) ?? 0)); - - var clientGroupSpan = clientGroup.Where(x => x.tradeSpan.IsSpanMargin == true); - var clientGroupOther = clientGroup.Where(x => x.tradeSpan.IsSpanMargin != true).ToList(); - - //交易员方向,正数代表交易员收预付金 - var worstCastClientPayable = 0.0; - var groupTradeIds = new List(); - - #region 默认组合的交易类型的交易处理 - - //客户级别默认预付金规则 - var clientMarginTemplates = (from cmt in cmts.Where(x => x.ClientId == clientGroup.Key) - join mtv in cMarginTemplates - on cmt.MarginTemplateId equals mtv.id - select new { cmt, mtv }).ToList(); - - if (clientMarginTemplates.Any()) - { - var valueDate = clientMarginTemplates.Max(x => x.cmt.ValueDate); - clientMarginTemplates = clientMarginTemplates.Where(x => x.cmt.ValueDate == valueDate).ToList(); - clientMarginTemplates.ForEach(x => - { - var clientGroupOtherBuySell = clientGroupOther.Where(y => ((y.trade.BuySell == "买入" ? BuySellEnum.Buy : BuySellEnum.Sell) & x.mtv.BuySellType) > 0 && y.marginTemplateId == 0 && x.mtv.TradeTypes.Contains(y.trade.TradeType)); - - var marginDetail = cMarginTemplateDetails.Where(y => y.MarginTemplateId == x.mtv.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null && (x.mtv.RuleType != (int)MarginRuleTypeEnum.无预付金 && x.mtv.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && x.mtv.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && x.mtv.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.mtv.Name)); - } - - if (x.mtv.RuleType == (int)MarginRuleTypeEnum.类香草预付金规则) - { - clientGroupOtherBuySell = clientGroupOtherBuySell.Where(y => y.trade.BuySell == "买入"); - var tradeIds = clientGroupOtherBuySell.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcVanillaGroup(tradeSpans, marginDetail, req, clientGroupOtherBuySell, x.mtv); - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - clientGroupOtherBuySell = clientGroupOtherBuySell.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC"))); - var tradeIds = clientGroupOtherBuySell.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup(tradeSpans, marginDetail, req, clientGroupOtherBuySell, x.mtv); - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2 && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - clientGroupOtherBuySell = clientGroupOtherBuySell.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC"))); - var tradeIds = clientGroupOtherBuySell.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup2(tradeSpans, marginDetail, req, clientGroupOtherBuySell, x.mtv); - } - else if ((x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 || x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) && x.mtv.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.指数) - { - //指数类交易 - var clientGroupIndex = clientGroupOtherBuySell.Where(y => (y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC"))); - var tradeIds = clientGroupIndex.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - - worstCastClientPayable += clientGroupIndex.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.mtv.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - var tradeIds = clientGroupOtherBuySell.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup3(tradeSpans, marginDetail, req, clientGroupOtherBuySell, x.mtv); - } - else - { - var tradeIds = clientGroupOtherBuySell.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += clientGroupOtherBuySell.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - }); - } - - //系统默认预付金规则 - defaultMarginTemplates.ForEach(x => - { - var marginDetail = defaultMarginTemplateDetails.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (marginDetail == null && (x.RuleType != (int)MarginRuleTypeEnum.无预付金 && x.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && x.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && x.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.Name)); - } - - if (x.RuleType == (int)MarginRuleTypeEnum.类香草预付金规则) - { - var clientGroupOtherFilter = clientGroupOther.Where(y => x.TradeTypes.Contains(y.trade.TradeType) && y.trade.BuySell == "买入" && y.marginTemplateId == 0); - var tradeIds = clientGroupOtherFilter.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - - worstCastClientPayable += CalcVanillaGroup(tradeSpans, marginDetail, req, clientGroupOtherFilter, x); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - var clientGroupOtherFilter = clientGroupOther.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.marginTemplateId == 0 && x.TradeTypes.Contains(y.trade.TradeType)); - var tradeIds = clientGroupOtherFilter.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup(tradeSpans, marginDetail, req, clientGroupOtherFilter, x); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2 && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.个股) - { - var clientGroupOtherFilter = clientGroupOther.Where(y => !(y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.marginTemplateId == 0 && x.TradeTypes.Contains(y.trade.TradeType)); - var tradeIds = clientGroupOtherFilter.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup2(tradeSpans, marginDetail, req, clientGroupOtherFilter, x); - } - else if ((x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1 || x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) && x.DefaultParameterType == (int)DefaultMarginParameterTypeEnum.指数) - { - //指数类交易 - var clientGroupOtherFilter = clientGroupOther.Where(y => (y.trade.UnderlyingCode.StartsWith("000") && y.trade.UnderlyingCode.EndsWith(".SH") || y.trade.UnderlyingCode.StartsWith("39") || y.trade.UnderlyingCode.StartsWith("IF") || y.trade.UnderlyingCode.StartsWith("IH") || y.trade.UnderlyingCode.StartsWith("IC")) && y.marginTemplateId == 0 && x.TradeTypes.Contains(y.trade.TradeType)); - var tradeIds = clientGroupOtherFilter.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += clientGroupOtherFilter.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - var clientGroupOtherFilter = clientGroupOther.Where(y => y.marginTemplateId == 0 && x.TradeTypes.Contains(y.trade.TradeType)); - var tradeIds = clientGroupOtherFilter.Select(x => x.trade.id); - clientGroupOther = clientGroupOther.Where(y => !tradeIds.Contains(y.trade.id)).ToList(); - worstCastClientPayable += CalcSellSnowBallAndAutoCallGroup3(tradeSpans, marginDetail, req, clientGroupOtherFilter, x); - } - }); - - worstCastClientPayable += clientGroupOther.Where(y => y.marginTemplateId == 0).Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - - #endregion - - #region 自定义组合预付金规则 - - groupMarginTemplates.ForEach(x => - { - var marginDetail = groupMarginTemplateDetails.Where(y => y.MarginTemplateId == x.id && y.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - //非自定义预付金的交易 - var tradeSpanInfoGroup = clientGroupOther.Where(y => y.marginTemplateId == x.id && y.tradeSpan.IsSingleMargin != true); - if (marginDetail == null && tradeSpanInfoGroup.Any()) - { - throw new Exception(string.Format("[{0}]不在{1}有效期内", req.settleDate.ToString("yyyy-MM-dd"), x.Name)); - } - //自定义预付金的交易 - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => y.marginTemplateId == x.id && y.tradeSpan.IsSingleMargin == true); - groupTradeIds.AddRange(tradeSpanInfoGroup.Select(y => y.trade.id)); - groupTradeIds.AddRange(tradeSpanInfoGroupSingle.Select(y => y.trade.id)); - if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则1) - { - double groupMargins = 0; - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax ? (y.trade.SpotPrice * (1 + redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (marginDetail.IsUseStrike && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else if (!marginDetail.IsUseStrike && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则2) - { - double groupMargins = 0; - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax ? (y.trade.SpotPrice * (1 + redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (marginDetail.IsUseStrike && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else if (!marginDetail.IsUseStrike && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else if (x.RuleType == (int)MarginRuleTypeEnum.触发条件预付金规则3) - { - double groupMargins = 0; - //初始预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金比例 - var redeemRatio2 = marginDetail.MarginRatio3 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体涨跌跌幅时需要判断单个标的的涨跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax && marginDetail.PriceLimitType == 0 || (1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax && marginDetail.PriceLimitType == 1 ? (y.trade.SpotPrice * (1 + (marginDetail.PriceLimitType == 0 ? 1 : -1) * redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (marginDetail.IsUseStrike && groupStrikeWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupStrikeWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupStrikeWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else if (!marginDetail.IsUseStrike && groupSpotPriceWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupSpotPriceWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupSpotPriceWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else - { - worstCastClientPayable += tradeSpanInfoGroup.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - }); - - #endregion - - //自定义单腿规则的预付金加总 - worstCastClientPayable += clientGroupOther.Where(x => x.marginTemplateId != 0 && !groupTradeIds.Contains(x.trade.id)).Sum(x => x.tradeSpan.WorstCastClientPayable ?? 0); - - //span算法合计预付金 - if (clientGroupSpan.Any()) - { - var clientSpanWorstSum = 0d; - var underlyingGroupSpan = clientGroupSpan.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - InitialMargin = t.Sum(g => g.tradeSpan.InitialMargin) * (-1) - }).ToList(); - foreach (var item in underlyingGroupSpan) - { - //客户角度 - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - if (!isForOtherSide) - { - item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable ?? 0, item.InitialMargin ?? 0); - } - - //交易员角度 - clientSpanWorstSum += -(item.WorstCastClientPayable ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - if(!isForOtherSide) - { - var tradeIdList = clientGroupSpan.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.InitialMargin) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.InitialMargin); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.InitialMargin); - } - } - - #endregion - } - - if (HasTwoSideMargin(clientGroup.Key)) - { - worstCastClientPayable += clientSpanWorstSum; - } - else - { - worstCastClientPayable += Math.Max(clientSpanWorstSum, 0); - } - } - - var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1) - }).ToList(); - foreach (var item in underlyingGroup) - { - if (!HasTwoSideMargin(clientGroup.Key)) - { - item.DeltaMargin = Math.Min(item.DeltaMargin ?? 0, 0); - } - } - - //客户方向delta预付金 - var deltaMargin = underlyingGroup.Sum(g => (g.DeltaMargin ?? 0)) - positionWinLoss; - if (!HasTwoSideMargin(clientGroup.Key)) - { - deltaMargin = Math.Min(deltaMargin, 0); - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = Math.Min(-worstCastClientPayable, 0), - MySideMargin = Math.Min(-worstCastClientPayable, 0), - DeltaMargin = deltaMargin, - SwapWorstCastClientPayable = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(t => t.tradeSpan.WorstCastClientPayable) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - SwapInitMargin = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(t => t.tradeSpan.SwapInitMargin) * (-1), - SwapWinLoss = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2)).Sum(t => t.tradeSpan.SwapWinLoss) * (-1), - //互换容忍部分预付金(此部分不占用预付金) - SwapUnMargin = clientGroup.Where(g => g.trade.TradeType == "收益互换" && (g.trade.IsGroup != 2) && g.tradeSpan.Margin == 0).Sum(g => Math.Max(g.tradeSpan.SwapWinLoss ?? 0.0, 0)) * (-1) - }; - - clientSpanNews.Add(clientSpan); - } - - return clientSpanNews; - } - - private double CalcVanillaGroup(List tradeSpans, margin_template_detail marginDetail, CalcClientMarginReq req, IEnumerable clientGroupOther, margin_template_v2 mtv) - { - double worstCastClientPayable = 0; - var groupRatio = marginDetail.GroupRatio ?? 0; - var stockEqvNotional = marginDetail.StockEqvNotional ?? 0; - var singleStockEqvNotional = marginDetail.SingleStockEqvNotional ?? 0; - var amount = marginDetail.PositionUnderlyingAmount ?? 0; - - //香草期权只考虑交易员买入的交易,卖出的交易不需要考虑预付金 - var tradeVanillaSpanInfo = clientGroupOther.Where(y => y.tradeSpan.IsSingleMargin != true); - //自定义预付金 - var tradeVanillaSpanInfoSingle = clientGroupOther.Where(y => y.tradeSpan.IsSingleMargin == true); - - var umdStockEqvNotional = tradeVanillaSpanInfo.GroupBy(y => y.trade.UnderlyingId).Select(t => new - { - UnderlyingId = t.Key, - StockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor)), - PositionStockEqvNotional = t.Sum(g => TradeHelper.GetStockEqvNotionalReal(g.trade.StockEqvNotional, g.trade.ParticipationRate, g.trade.AnnualizeFactor) * g.tradeSpan.UnderlyingPrice / g.trade.SpotPrice) - }).ToList(); - var underlyingIds = umdStockEqvNotional.Select(y => y.UnderlyingId); - var totalStockEqvNotional = umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional); - if (totalStockEqvNotional >= stockEqvNotional && umdStockEqvNotional.Any(y => y.PositionStockEqvNotional >= singleStockEqvNotional) && underlyingIds.Count() >= amount) - { - //获取组合持仓名义本金和初始名义本金的较高者 - var maxStockEqvNotional = Math.Max(umdStockEqvNotional.Sum(y => y.StockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.StockEqvNotional), umdStockEqvNotional.Sum(y => y.PositionStockEqvNotional >= singleStockEqvNotional ? singleStockEqvNotional : y.PositionStockEqvNotional ?? 0)); - var groupMargins = maxStockEqvNotional * groupRatio + tradeVanillaSpanInfo.Sum(y => y.tradeSpan.PositionWin ?? 0); - worstCastClientPayable += groupMargins; - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeVanillaSpanInfo.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeVanillaSpanInfo.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeVanillaSpanInfo.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - } - else - { - worstCastClientPayable += tradeVanillaSpanInfo.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - //自定义预付金处理的交易 - worstCastClientPayable += tradeVanillaSpanInfoSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - - return worstCastClientPayable; - } - - private double CalcSellSnowBallAndAutoCallGroup(List tradeSpans, margin_template_detail marginDetail, CalcClientMarginReq req, IEnumerable clientGroupOther, margin_template_v2 mtv) - { - double worstCastClientPayable = 0; - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupOther.Where(y => y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax ? (y.trade.SpotPrice * (1 + redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (marginDetail.IsUseStrike && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else if (!marginDetail.IsUseStrike && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotional * redeemRatio1 + groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupOther.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - return worstCastClientPayable; - } - - private double CalcSellSnowBallAndAutoCallGroup2(List tradeSpans, margin_template_detail marginDetail, CalcClientMarginReq req, IEnumerable clientGroupOther, margin_template_v2 mtv) - { - double worstCastClientPayable = 0; - - //初始预付金率 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金率 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupOther.Where(y => y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体跌跌幅时需要判断单个标的的跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax ? (y.trade.SpotPrice * (1 + redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStockEqvNotionalNow = tradeSpanInfoGroup.Sum(y => (TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) ?? 0); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (marginDetail.IsUseStrike && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStrikeStockEqvNotional * (1 - groupPriceWithNotional / groupStrikeWithNotional); - worstCastClientPayable += groupMargins; - } - else if (!marginDetail.IsUseStrike && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit)) - { - groupMargins = groupStockEqvNotionalNow * redeemRatio1 + groupStockEqvNotional * (1 - groupPriceWithNotional / groupSpotPriceWithNotional); - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupOther.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - return worstCastClientPayable; - } - - private double CalcSellSnowBallAndAutoCallGroup3(List tradeSpans, margin_template_detail marginDetail, CalcClientMarginReq req, IEnumerable clientGroupOther, margin_template_v2 mtv) - { - double worstCastClientPayable = 0; - - //初始预付金比例 - var redeemRatio = marginDetail.MarginRatio1 ?? 0; - //持仓预付金比例 - var redeemRatio2 = marginDetail.MarginRatio3 ?? 0; - //追加比例 - var redeemRatio1 = marginDetail.MarginRatio2 ?? 0; - var redeemPriceLimit = marginDetail.RedeemPriceLimit ?? 0; - var redeemPriceMax = marginDetail.RedeemPriceMax ?? 0; - var redeemAmount = marginDetail.PositionUnderlyingAmount ?? 0; - var tradeSpanInfoGroupSingle = clientGroupOther.Where(y => (y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin == true || y.trade.BuySell == "买入")); - var tradeSpanInfoGroup = clientGroupOther.Where(y => y.trade.BuySell == "卖出" && y.tradeSpan.IsSingleMargin != true); - var groupSpotPriceWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.SpotPrice * y.trade.Notional) ?? 0); - var groupStrikeWithNotional = tradeSpanInfoGroup.Sum(y => (y.trade.ActualStrike * y.trade.Notional) ?? 0); - //计算单一客户当日标的整体涨跌跌幅时需要判断单个标的的涨跌幅是否超过上限 - var groupPriceWithNotional = tradeSpanInfoGroup.Sum(y => (((y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice - 1) > redeemPriceMax && marginDetail.PriceLimitType == 0 || (1 - y.tradeSpan.UnderlyingPrice / y.trade.SpotPrice) > redeemPriceMax && marginDetail.PriceLimitType == 1 ? (y.trade.SpotPrice * (1 + (marginDetail.PriceLimitType == 0 ? 1 : -1) * redeemPriceMax)) : y.tradeSpan.UnderlyingPrice) * y.trade.Notional) ?? 0); - var groupStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor)); - var groupStrikeStockEqvNotional = tradeSpanInfoGroup.Sum(y => TradeHelper.GetStockEqvNotionalReal(y.trade.StockEqvNotional, y.trade.ParticipationRate, y.trade.AnnualizeFactor) * (y.trade.ActualStrike ?? 0) / y.trade.SpotPrice.Value); - - if (tradeSpanInfoGroup.Select(y => y.trade.UnderlyingId).Distinct().Count() >= redeemAmount) - { - double groupMargins = 0; - if (marginDetail.IsUseStrike && groupStrikeWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupStrikeWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupStrikeWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupStrikeWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupStrikeWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStrikeStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else if (!marginDetail.IsUseStrike && groupSpotPriceWithNotional > 0) - { - var times = 0.0; - if (marginDetail.MarginRatio2 > 0) - { - if (marginDetail.PriceLimitType == 0) - { - times = Math.Floor(((1 - groupPriceWithNotional / groupSpotPriceWithNotional) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((groupPriceWithNotional / groupSpotPriceWithNotional - 1) - redeemPriceLimit) / marginDetail.MarginRatio2.Value); - } - } - - if (marginDetail.UsePositionStockEqvNotional) - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (marginDetail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - groupMargins = groupStockEqvNotional * rateTemp * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - //不满足追加比例时,用初始预付金 - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - else - { - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - groupMargins = groupStockEqvNotional * redeemRatio2; - worstCastClientPayable += groupMargins; - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - } - - if (marginDetail.MarginRatio2 > 0 && groupPriceWithNotional / groupSpotPriceWithNotional <= (1 - redeemPriceLimit) && marginDetail.PriceLimitType == 0 || groupPriceWithNotional / groupSpotPriceWithNotional >= (1 + redeemPriceLimit) && marginDetail.PriceLimitType == 1) - { - worstCastClientPayable += groupStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - groupMargins += groupStockEqvNotional * (redeemPriceLimit + marginDetail.MarginRatio2.Value * times); - } - } - else - { - groupMargins = groupStockEqvNotional * redeemRatio; - worstCastClientPayable += groupMargins; - } - - #region 更新tradeSpan,使得每笔交易的持仓预付金和组合预付金保持一致 - - var tradeIdList = tradeSpanInfoGroup.Select(y => y.tradeSpan.TradeId); - var sumStockEqvNotional = tradeSpanInfoGroup.Sum(y => y.trade.StockEqvNotional); - var tradeSpansUpdate = tradeSpans.Where(y => tradeIdList.Contains(y.TradeId)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(y => tradeIdList.Contains(y.TradeId) && y.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - tradeSpansReq.ForEach(y => - { - y.WorstCastClientPayable = groupMargins * tradeSpanInfoGroup.FirstOrDefault(z => z.trade.id == y.TradeId).trade.StockEqvNotional / sumStockEqvNotional; - }); - - #endregion - - //卖出的保本雪球,指数类的凤凰雪球需要单独计算预付金,买入的期权,进行累加 - //以及自定义预付金处理的交易 - worstCastClientPayable += tradeSpanInfoGroupSingle.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - else - { - worstCastClientPayable += clientGroupOther.Sum(y => y.tradeSpan.WorstCastClientPayable ?? 0); - } - - return worstCastClientPayable; - } - - class TradeSpanTemplate - { - public trade trade { get; set; } - public trade_span tradeSpan { get; set; } - public int marginTemplateId { get; set; } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1 && req.trade.TradeType != "收益互换") - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - if (marginReq.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - foreach (var item in marginReq.tradeList) - { - item.id = 0; - } - } - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - - /// - /// 权益类预付金计算 - /// - class GTJAStockMarginCalculation - { - readonly RunMarginCalculationReq _req; - - readonly RunMarginCalculationHelper _helper; - - public GTJAStockMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper) - { - _req = req; - _helper = helper; - } - - //权益类预付金计算 - public List Calculate(MarginParamProvider mpProvider) - { - var tradeSpans = new List(_req.tradeList.Count); - - using (var db = new YLContext()) - { - var tradeIds = _req.tradeList.Select(x => x.id); - if (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - tradeIds = new List { _req.realTradeId }; - } - var tradeMarginTemplates = db.trade_margin_template.Where(x => tradeIds.Contains(x.TradeId)).ToList(); - var tradeMarginTemplateIds = tradeMarginTemplates.Select(x => x.MarginTemplateId).ToArray(); - var marginTemplates = db.margin_template_v2.Where(x => tradeMarginTemplateIds.Contains(x.id)).ToList(); - var marginTemplateDetails = db.margin_template_detail.Where(x => tradeMarginTemplateIds.Contains(x.MarginTemplateId)).ToList(); - - var clientIds = _req.tradeList.Select(x => x.ClientId).Distinct(); - var cmts = db.client_margin_template.Where(x => clientIds.Contains(x.ClientId) && x.ValueDate <= _req.settleDate).OrderByDescending(x => x.ValueDate).ToList(); - var cmtIds = cmts.Select(x => x.MarginTemplateId).ToArray(); - var cMarginTemplates = db.margin_template_v2.Where(x => cmtIds.Contains(x.id) && (x.MarginScenarios & (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? MarginScenarioEnum.Initial : MarginScenarioEnum.Position)) > 0 && x.IsValid).ToList(); - var cMarginTemplateDetails = db.margin_template_detail.Where(x => cmtIds.Contains(x.MarginTemplateId)).ToList(); - - var defaultMarginTemplates = db.margin_template_v2.Where(x => x.IsDefault && !x.IsForClient && x.ValueDate <= _req.settleDate && (x.MarginScenarios & (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? MarginScenarioEnum.Initial : MarginScenarioEnum.Position)) > 0 && x.IsValid).OrderByDescending(x => x.ValueDate).ToList(); - var defaultMarginTemplateIds = defaultMarginTemplates.Select(x => x.id).ToArray(); - var defaultMarginTemplateDetails = db.margin_template_detail.Where(x => defaultMarginTemplateIds.Contains(x.MarginTemplateId)).ToList(); - - List tradesICIHIF = new List(); - - foreach (var td in _req.tradeList) - { - var underlyingType = GetUnderlyingType(td); - var span = new trade_span(); - - if (_helper.GetSpecialMargin(td, 0, out var value)) - { - span = _helper.CreateTradeSpan(td, null); - span.WorstCastClientPayable = value; - span.IsSingleMargin = true; - } - else - { - //设置了特殊的规则 - var tradeMarginTemplate = tradeMarginTemplates.Where(x => x.TradeId == td.id && x.ValueDate <= _req.settleDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - - //由于初始预付金计算时,td.id会被置0,所以需要根据realTradeId找到对应的特殊模板 - if (tradeMarginTemplate == null && _req.tradeList.Count() == 1 && _req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - tradeMarginTemplate = db.trade_margin_template.Where(x => x.TradeId == _req.realTradeId && x.ValueDate <= _req.settleDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - } - - if (tradeMarginTemplate != null && !_req.forOtherSide) - { - var marginTemplate = marginTemplates.FirstOrDefault(x => x.id == tradeMarginTemplate.MarginTemplateId); - if (marginTemplate == null) - { - throw new Exception(string.Format("{0}未找到配置的预付金模板", td.TradeNumber)); - } - - var detail = marginTemplateDetails.Where(x => x.MarginTemplateId == tradeMarginTemplate.MarginTemplateId && x.ValueDate <= _req.settleDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - if (detail == null && (marginTemplate.RuleType != (int)MarginRuleTypeEnum.无预付金 && marginTemplate.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && marginTemplate.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && marginTemplate.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("{0}在{1}未找到有效的预付金参数", td.TradeNumber, _req.settleDate.ToString("yyyy-MM-dd"))); - } - - switch (marginTemplate.RuleType) - { - case (int)MarginRuleTypeEnum.无预付金: - span = CalcAsNo(td); - break; - case (int)MarginRuleTypeEnum.按固定利率: - span = CalcAsFixed(td, detail); - break; - case (int)MarginRuleTypeEnum.按浮动盈亏: - span = CalcAsFloat(td, detail); - break; - case (int)MarginRuleTypeEnum.类香草预付金规则: - span = CalcAsVanilla(td, detail); - break; - case (int)MarginRuleTypeEnum.自动赎回买入预付金规则: - span = CalcBuySnowBallAndAutoCall(td); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则1: - span = CalcSellSnowBallAndAutoCall(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则2: - span = CalcSellSnowBallAndAutoCall2(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则3: - span = CalcSellSnowBallAndAutoCall3(td, detail); - break; - case (int)MarginRuleTypeEnum.保底预付金规则: - span = CalcSingleSnowBallAndAutoCall(td); - break; - case (int)MarginRuleTypeEnum.含赔付预付金计算规则: - span = CalcBinary(td); - break; - case (int)MarginRuleTypeEnum.买入自动赎回规则1: - span = CalcBuyAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.卖出自动赎回规则1: - span = CalcSellAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.标准SPAN: - _helper.req.tradeList = new List { td }; - span = RunMarginCalculationForCommodity(_helper, mpProvider, detail.MarginRatio1 ?? 0, detail.IsUsePriceLimit, detail.MarginRatio2).FirstOrDefault(); - span.InitialMargin = td.InitialMargin * td.StockEqvNotional / td.OriginalStockEqvNotional * detail.ComparedInitialMarginRate; - if (_helper.req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && !_helper.req.forOtherSide) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, span.InitialMargin ?? 0); - } - else if (_helper.req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && !new GTJAMarginCalculation().HasTwoSideMargin(td.ClientId)) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, 0); - } - break; - } - } - //走默认规则 - else if (td.TradeType != "现金流交易") - { - var variety = DataCacheProvider.GetVariety(td.UnderlyingCode); - - var hasSpanTemplate = defaultMarginTemplates.Any(x => x.RuleType == (int)MarginRuleTypeEnum.标准SPAN); - //IC,IH,IF默认通过span算法 - if (variety != null && new List() { "IC", "IH", "IF" }.Contains(variety.VarietyCode) && !hasSpanTemplate) - { - tradesICIHIF.Add(td); - span = null; - } - else - { - var defaultParameterType = (int)DefaultMarginParameterTypeEnum.个股; - //指数 - if (td.UnderlyingCode != null && (td.UnderlyingCode.StartsWith("000") && td.UnderlyingCode.EndsWith(".SH") || td.UnderlyingCode.StartsWith("39") || td.UnderlyingCode.StartsWith("IF") || td.UnderlyingCode.StartsWith("IH") || td.UnderlyingCode.StartsWith("IC"))) - { - defaultParameterType = (int)DefaultMarginParameterTypeEnum.指数; - } - - var clientMarginTemplates = (from cmt in cmts.Where(x => x.ClientId == td.ClientId) - join mtv in cMarginTemplates.Where(x => x.TradeTypes.Contains(td.TradeType) && (x.BuySellType & (td.BuySell == "买入" ? BuySellEnum.Buy : BuySellEnum.Sell)) > 0 && (x.DefaultParameterType == 0 || x.DefaultParameterType == defaultParameterType)) - on cmt.MarginTemplateId equals mtv.id - select new { cmt, mtv }).ToList(); - //客户默认预付金 - if (clientMarginTemplates.Any()) - { - var clientMarginTemplate = clientMarginTemplates.OrderByDescending(x => x.cmt.ValueDate).First(); - - var detail = cMarginTemplateDetails.Where(x => x.MarginTemplateId == clientMarginTemplate.mtv.id && x.ValueDate <= _req.settleDate && ((x.UnderlyingType & underlyingType) > 0 || x.UnderlyingType == UnderlyingTypeEnum.None)).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - if (detail == null && (clientMarginTemplate.mtv.RuleType != (int)MarginRuleTypeEnum.无预付金 && clientMarginTemplate.mtv.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && clientMarginTemplate.mtv.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && clientMarginTemplate.mtv.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("{0}在{1}未找到有效的预付金参数", td.TradeNumber, _req.settleDate.ToString("yyyy-MM-dd"))); - } - - switch (clientMarginTemplate.mtv.RuleType) - { - case (int)MarginRuleTypeEnum.无预付金: - span = CalcAsNo(td); - break; - case (int)MarginRuleTypeEnum.按固定利率: - span = CalcAsFixed(td, detail); - break; - case (int)MarginRuleTypeEnum.按浮动盈亏: - span = CalcAsFloat(td, detail); - break; - case (int)MarginRuleTypeEnum.类香草预付金规则: - span = CalcAsVanilla(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则1: - span = CalcSnowBallAndAutoCall(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则2: - span = CalcSnowBallAndAutoCall2(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则3: - span = CalcSnowBallAndAutoCall3(td, detail); - break; - case (int)MarginRuleTypeEnum.含赔付预付金计算规则: - span = CalcBinary(td); - break; - case (int)MarginRuleTypeEnum.买入自动赎回规则1: - span = CalcBuyAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.卖出自动赎回规则1: - span = CalcSellAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.标准SPAN: - _helper.req.tradeList = new List { td }; - span = RunMarginCalculationForCommodity(_helper, mpProvider, detail.MarginRatio1 ?? 0, detail.IsUsePriceLimit, detail.MarginRatio2).FirstOrDefault(); - span.InitialMargin = td.InitialMargin * td.StockEqvNotional / td.OriginalStockEqvNotional * detail.ComparedInitialMarginRate; - if (_helper.req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && !_helper.req.forOtherSide) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, span.InitialMargin ?? 0); - } - else if (_helper.req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && !new GTJAMarginCalculation().HasTwoSideMargin(td.ClientId)) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, 0); - } - break; - } - } - //系统默认预付金 - else - { - var defaultMarginTemplate = defaultMarginTemplates.FirstOrDefault(x => x.TradeTypes.Contains(td.TradeType) && (x.BuySellType & (td.BuySell == "买入" ? BuySellEnum.Buy : BuySellEnum.Sell)) > 0 && (x.DefaultParameterType == 0 || x.DefaultParameterType == defaultParameterType)); - if (defaultMarginTemplate == null) - { - throw new Exception(string.Format("{0}未找到对应交易结构的默认预付金模板", td.TradeNumber)); - } - - var detail = defaultMarginTemplateDetails.Where(x => x.MarginTemplateId == defaultMarginTemplate.id && x.ValueDate <= _req.settleDate && ((x.UnderlyingType & underlyingType) > 0 || x.UnderlyingType == UnderlyingTypeEnum.None)).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - if (detail == null && (defaultMarginTemplate.RuleType != (int)MarginRuleTypeEnum.无预付金 && defaultMarginTemplate.RuleType != (int)MarginRuleTypeEnum.自动赎回买入预付金规则 && defaultMarginTemplate.RuleType != (int)MarginRuleTypeEnum.含赔付预付金计算规则 && defaultMarginTemplate.RuleType != (int)MarginRuleTypeEnum.保底预付金规则)) - { - throw new Exception(string.Format("{0}在{1}未找到有效的预付金参数", td.TradeNumber, _req.settleDate.ToString("yyyy-MM-dd"))); - } - - switch (defaultMarginTemplate.RuleType) - { - case (int)MarginRuleTypeEnum.无预付金: - span = CalcAsNo(td); - break; - case (int)MarginRuleTypeEnum.按固定利率: - span = CalcAsFixed(td, detail); - break; - case (int)MarginRuleTypeEnum.按浮动盈亏: - span = CalcAsFloat(td, detail); - break; - case (int)MarginRuleTypeEnum.类香草预付金规则: - span = CalcAsVanilla(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则1: - span = CalcSnowBallAndAutoCall(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则2: - span = CalcSnowBallAndAutoCall2(td, detail); - break; - case (int)MarginRuleTypeEnum.触发条件预付金规则3: - span = CalcSnowBallAndAutoCall3(td, detail); - break; - case (int)MarginRuleTypeEnum.含赔付预付金计算规则: - span = CalcBinary(td); - break; - case (int)MarginRuleTypeEnum.买入自动赎回规则1: - span = CalcBuyAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.卖出自动赎回规则1: - span = CalcSellAutoRedeem(td, detail); - break; - case (int)MarginRuleTypeEnum.标准SPAN: - _helper.req.tradeList = new List { td }; - span = RunMarginCalculationForCommodity(_helper, mpProvider, detail.MarginRatio1 ?? 0, detail.IsUsePriceLimit, detail.MarginRatio2).FirstOrDefault(); - span.InitialMargin = td.InitialMargin * td.StockEqvNotional / td.OriginalStockEqvNotional * detail.ComparedInitialMarginRate; - if (_helper.req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && !_helper.req.forOtherSide) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, span.InitialMargin ?? 0); - } - else if(_helper.req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && !new GTJAMarginCalculation().HasTwoSideMargin(td.ClientId)) - { - span.WorstCastClientPayable = Math.Max(span.WorstCastClientPayable ?? 0, 0); - } - break; - } - } - } - } - else - { - span = null; - } - } - - if (span != null) - { - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - udm.QuotationDate = _req.settleDate; - var positionVol = VolatilityHelper.GetTradeVol(td, _req.settleDate, _req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - - double closePrice; - if (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - closePrice = td.SpotPrice ?? 0; - } - else - { - new EodPriceProvider(_req.settleDate, false).TryGetEodPrice(td.UnderlyingCode, out var eodPrice); - - closePrice = eodPrice?.ClosePrice ?? udm.Price ?? 0; - } - - mpProvider.TryGetMarginRate(td.UnderlyingCode, out var marginRate); - - var optionValue = CalcTradeValueResult(td, udm, closePrice); - - span.Spv = optionValue.Pv; - span.Delta = optionValue.Delta; - span.UnderlyingPrice = closePrice; - span.DeltaMargin = (span.Delta * span.UnderlyingPrice * marginRate) ?? 0; - span.DeltaMargin = (Math.Abs(span.Delta ?? 0) * (td.BuySell == "买入" ? 1 : -1) * span.UnderlyingPrice * marginRate) ?? 0; - tradeSpans.Add(span); - } - } - - //IC,IH,IF走span算法 - if (tradesICIHIF.Any()) - { - _helper.req.tradeList = tradesICIHIF; - var commodityTradeSpans = RunMarginCalculationForCommodity(_helper, mpProvider); - if (commodityTradeSpans.Any()) - { - tradeSpans.AddRange(commodityTradeSpans); - } - } - } - - return tradeSpans; - } - - private UnderlyingTypeEnum GetUnderlyingType(trade td) - { - var startCode = td.UnderlyingCode.Substring(0, 3); - int startCodeNum = 0; - if (Int32.TryParse(startCode, out startCodeNum)) - { - //市场为SH+标的代码以000开头;市场为SZ+标的代码以399开头; - if (startCodeNum == 0 && td.UnderlyingCode.EndsWith(".SH") || startCodeNum == 399 && td.UnderlyingCode.EndsWith(".SZ")) - { - return UnderlyingTypeEnum.Index; - } - //市场为SH + 标的代码以600~605、510~518开头;(主板股票、指数类开放式基金) - //市场为SZ + 标的代码以000~004、159开头(主板股票、ETF) - else if (td.UnderlyingCode.EndsWith(".SH") && (startCodeNum >= 600 && startCodeNum <= 605 || startCodeNum >= 510 && startCodeNum <= 518) - || td.UnderlyingCode.EndsWith(".SZ") && (startCodeNum == 159 || startCodeNum >= 0 && startCodeNum <= 4)) - { - return UnderlyingTypeEnum.StockApproval; - } - //市场为SH + 标的代码以688、588开头;(科创板股票、科创板ETF) - //市场为SZ + 标的代码以300~309开头;(创业板股票) - else if (td.UnderlyingCode.EndsWith(".SH") && (startCodeNum == 688 || startCodeNum == 588) - || td.UnderlyingCode.EndsWith(".SZ") && startCodeNum >= 300 && startCodeNum <= 309) - { - return UnderlyingTypeEnum.StockNonApproval; - } - else - { - return UnderlyingTypeEnum.Other; - } - } - else - { - return UnderlyingTypeEnum.Other; - } - } - - /// - /// 按无预付金 - /// - /// - /// - private trade_span CalcAsNo(trade td) - { - var span = _helper.CreateTradeSpan(td, null); - span.WorstCastClientPayable = 0; - span.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - - return span; - } - - /// - /// 按固定利率计算 - /// - /// - /// - /// - private trade_span CalcAsFixed(trade td, margin_template_detail detail) - { - var span = _helper.CreateTradeSpan(td, null); - span.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - if (!detail.UsePositionStockEqvNotional) - { - span.WorstCastClientPayable = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * detail.MarginRatio2; - } - else - { - span.WorstCastClientPayable = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * span.UnderlyingPrice / (td.SpotPrice ?? 0) * detail.MarginRatio2; - } - - return span; - } - - /// - /// 按浮动盈亏 - /// - /// - /// - /// - private trade_span CalcAsFloat(trade td, margin_template_detail detail) - { - var span = _helper.CreateTradeSpan(td, null); - span.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - - var value = 0.0; - if (!detail.UsePositionStockEqvNotional) - { - value = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio2 ?? 0); - } - else - { - value = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (span.UnderlyingPrice ?? 0) / (td.SpotPrice ?? 0) * (detail.MarginRatio2 ?? 0); - } - - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: _req.settleDate, - tradeList: new[] { td }, - calcScenario: _req.GetCalcScenario(), - priceProvider: _req.PriceProvider, - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: null, - volType: _req.volType, isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: _req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) - { - LogFactory.GetLogger().Error("Pv计算失败:" + tradeRiskResult.ErrorMessage); - } - var tradePrice = (td.TradePrice * td.Notional / td.OriginalNotional) ?? 0; - double pnl = 0; - if (td.BuySell == "买入") - { - pnl = tradePrice - Math.Abs(tradeRiskResult.Results.First().ValueResult.Pv); - } - else - { - pnl = Math.Abs(tradeRiskResult.Results.First().ValueResult.Pv) - tradePrice; - } - value += pnl; - if (value < 0) - { value = 0; } - } - span.WorstCastClientPayable = value; - - return span; - } - - /// - /// 类似香草期权tradespan处理 - /// - /// - /// - /// - private trade_span CalcAsVanilla(trade td, margin_template_detail detail) - { - if (td.BuySell != "买入") - { - return null; - } - - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (udm == null) - { - udm = new underlying_manager(); - } - EodPrice eodPrice = null; - udm.QuotationDate = _req.settleDate; - double closePrice; - var underlyingStatus = underlying_manager.Status_Working; - if (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - closePrice = td.SpotPrice ?? 0; - } - else - { - new EodPriceProvider(_req.settleDate, false).TryGetEodPrice(td.UnderlyingCode, out eodPrice); - - closePrice = eodPrice?.ClosePrice ?? udm.Price ?? 0; - underlyingStatus = eodPrice?.UnderlyingStatus ?? udm.UnderlyingStatus; - } - - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(_req.settleDate.AddDays(-1)); - var preClosePrice = new EodPriceProvider(lastDate, true).GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice); - - double? positionWin = 0.0, baseMargin; - - var optionValue = CalcTradeValueResult(td, udm, closePrice); - - var pv = optionValue.Pv; - //默认取大的名义本金 - var stockEqvNotionalForMargin = (closePrice > td.SpotPrice ? closePrice / td.SpotPrice : 1) * TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); - if (detail.IsIntrinsicValue) - { - //交易员方向是赚钱的,客户需要补交预付金 - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && (td.OptionType == "看涨" && closePrice > td.ActualStrike || td.OptionType == "看跌" && closePrice < td.ActualStrike)) - { - //实值名义本金处理 - if (td.OptionType == "看涨") - { - //看涨取持仓名义本金 - stockEqvNotionalForMargin = closePrice / td.SpotPrice * TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); - } - else - { - //看跌取期初名义本金 - stockEqvNotionalForMargin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); - } - - baseMargin = stockEqvNotionalForMargin * detail.MarginRatio1; - - baseMargin += Math.Abs(closePrice - (td.ActualStrike ?? 0)) * td.Notional; - positionWin += Math.Abs(closePrice - (td.ActualStrike ?? 0)) * td.Notional; - } - //客户方向赚钱,客户可以抵扣预付金,最多抵扣值为期权费 - else if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && (td.OptionType == "看涨" && closePrice < td.ActualStrike || td.OptionType == "看跌" && closePrice > td.ActualStrike)) - { - //虚值名义本金处理 - if (td.OptionType == "看涨") - { - //看涨取期初名义本金 - stockEqvNotionalForMargin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); - } - else - { - //看跌取持仓名义本金 - stockEqvNotionalForMargin = closePrice / td.SpotPrice * TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); - } - - //虚值名义本金取小的 - baseMargin = stockEqvNotionalForMargin * detail.MarginRatio1; - - baseMargin -= Math.Min(Math.Abs(closePrice - (td.ActualStrike ?? 0)) * td.Notional, td.TradePrice * td.Notional / td.OriginalNotional ?? 0); - positionWin -= Math.Min(Math.Abs(closePrice - (td.ActualStrike ?? 0)) * td.Notional, td.TradePrice * td.Notional / td.OriginalNotional ?? 0); - } - else - { - baseMargin = stockEqvNotionalForMargin * detail.MarginRatio1; - } - } - else - { - baseMargin = stockEqvNotionalForMargin * detail.MarginRatio1; - - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && pv > td.TradePrice * td.Notional / td.OriginalNotional) - { - baseMargin += pv - td.TradePrice * td.Notional / td.OriginalNotional; - positionWin += pv - td.TradePrice * td.Notional / td.OriginalNotional; - } - } - - if (preClosePrice > 0 && _req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - //涨跌幅超过30%以及停牌的交易 - if (closePrice / preClosePrice >= 1.3 || closePrice / preClosePrice <= 0.7 || underlyingStatus == underlying_manager.Status_Suspension) - { - baseMargin += stockEqvNotionalForMargin * detail.MarginRatio4; - } - else //涨跌停 - { - var upDownLimit = _helper.GetStockUpDownLimit(td.UnderlyingCode, preClosePrice); - - //涨跌停暂时不使用精确等于处理 - if (upDownLimit.DownLimitPrice >= closePrice || upDownLimit.UpLimitPrice <= closePrice) - { - //一字涨跌停 - if (eodPrice != null && eodPrice.HighPrice == eodPrice.LowPrice) - { - baseMargin += stockEqvNotionalForMargin * detail.MarginRatio3; - } - else - { - baseMargin += stockEqvNotionalForMargin * detail.MarginRatio2; - } - } - } - } - - var tradeSpan = _helper.CreateTradeSpan(td, udm); - tradeSpan.WorstCastClientPayable = baseMargin; - tradeSpan.PositionWin = positionWin; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - private TradeValueResult CalcTradeValueResult(trade td, underlying_manager udm, double closePrice) - { - var positionVol = VolatilityHelper.GetTradeVol(td, _req.settleDate, _req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - TradeValueResult optionValue; - switch (td.TradeType) - { - case "远期": - if (PS.Config.ErpElement.ForwardTradePriceModel == Configuration.Enums.ForwardTradePriceModel.STANDARD && !string.IsNullOrWhiteSpace(td.BasisUnderlyingCode) && _req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - var Basisudm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.BasisUnderlyingCode); - if (Basisudm == null) - { - Basisudm = new underlying_manager(); - } - new EodPriceProvider(_req.settleDate, false).TryGetEodPrice(td.BasisUnderlyingCode, out var BasiseodPrice); - closePrice -= BasiseodPrice?.ClosePrice ?? Basisudm.Price ?? 0; - } - optionValue = ForwardradeCalcService.CalcValue(td, closePrice); - break; - case "信用债": - case "商品期货": - case "股票": - optionValue = new TradeValueResult { Pv = closePrice * td.Notional, Delta = td.Notional, DeltaCash = closePrice * td.Notional }; - break; - case "自定义交易": - var calcMarginType = _req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? CalcScenarioEnum.InitialMargin : CalcScenarioEnum.EodMargin; - optionValue = TradeRiskCalcUtil.GetManualOptionValue(_req.settleDate, td, closePrice, positionVol, true, calcMarginType, _req.volType, _req.settlementType, positionVol, _req.CalcMarginType == CalcMarginTypeEnum.EodMargin).optionValue; - break; - case "收益互换": - optionValue = PayoffSwapCalcService.CalcValue(td, _req.settleDate, null, _req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - break; - default: - optionValue = ValueCalculator.GetOptionValueResultV2( - _req.userId.ToString(), - udm, - td, - new double[] { positionVol }, - new double[] { closePrice }, - request: QdpPricingRequest.PV_ONLY, - preciseTimeMode: td.ExerciseDate == _req.settleDate); - break; - } - - return optionValue; - } - - /// - /// 二元期权tradespan处理 - /// - /// - /// - private trade_span CalcBinary(trade td) - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - - if (td.TradeType == "二元期权" && td.BuySell == "买入") - { - var margin = td.IsUsePremiumRate == true ? Math.Abs(Math.Max((td.trade_binary_option.CashOrNothingAmountRate ?? 0), (td.trade_binary_option.CashOrNothingAmountHighRate ?? 0)) * TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor)) : Math.Abs(Math.Max((td.trade_binary_option.CashOrNothingAmount ?? 0), (td.trade_binary_option.CashOrNothingAmountHigh ?? 0)) * td.Notional); - tradeSpan.WorstCastClientPayable = margin; - - } - else - { - tradeSpan.WorstCastClientPayable = 0; - } - - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - #region 雪球凤凰期权tradespan处理 - - /// - /// 触发条件预付金规则1 - /// - /// - /// - /// - private trade_span CalcSnowBallAndAutoCall(trade td, margin_template_detail detail) - { - if (td.TradeType != "凤凰期权" && td.TradeType != "雪球期权") - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = 0.0; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - if (td.BuySell == "买入") - { - return CalcBuySnowBallAndAutoCall(td); - } - else - { - //敲入转价差期权 - var isSingleMargin = td.TradeType == "雪球期权" && (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - || td.TradeType == "凤凰期权" && (td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption); - //保底的雪球凤凰期权 - if (isSingleMargin) - { - return CalcSingleSnowBallAndAutoCall(td); - } - - return CalcSellSnowBallAndAutoCall(td, detail); - } - } - - /// - /// 触发条件预付金规则2 - /// - /// - /// - /// - private trade_span CalcSnowBallAndAutoCall2(trade td, margin_template_detail detail) - { - if (td.TradeType != "凤凰期权" && td.TradeType != "雪球期权") - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = 0.0; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - if (td.BuySell == "买入") - { - return CalcBuySnowBallAndAutoCall(td); - } - else - { - //敲入转价差期权 - var isSingleMargin = td.TradeType == "雪球期权" && (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - || td.TradeType == "凤凰期权" && (td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption); - //保底的雪球凤凰期权 - if (isSingleMargin) - { - return CalcSingleSnowBallAndAutoCall(td); - } - - return CalcSellSnowBallAndAutoCall2(td, detail); - } - } - - /// - /// 触发条件预付金规则3 - /// - /// - /// - /// - private trade_span CalcSnowBallAndAutoCall3(trade td, margin_template_detail detail) - { - if (td.TradeType != "凤凰期权" && td.TradeType != "雪球期权") - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = 0.0; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - if (td.BuySell == "买入") - { - return CalcBuySnowBallAndAutoCall(td); - } - else - { - //敲入转价差期权 - var isSingleMargin = td.TradeType == "雪球期权" && (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - || td.TradeType == "凤凰期权" && (td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption); - //保底的雪球凤凰期权 - if (isSingleMargin) - { - return CalcSingleSnowBallAndAutoCall(td); - } - - return CalcSellSnowBallAndAutoCall3(td, detail); - } - } - - /// - /// 触发条件预付金规则1 - /// - /// - /// - /// - private trade_span CalcSellSnowBallAndAutoCall(trade td, margin_template_detail detail) - { - var margin = 0.0; - - var marginRatio = detail.MarginRatio1 ?? 0; - var marginRatio1 = detail.MarginRatio2 ?? 0; - var redeemPriceLimit = detail.RedeemPriceLimit ?? 0; - - var closePrice = td.SpotPrice ?? 0; - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - if (!new EodPriceProvider(_req.settleDate, false).TryGetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice, out closePrice)) - { - closePrice = udm.Price ?? 0; - } - } - - var strike = td.ActualStrike ?? 0; - if (detail.IsUseStrike && strike > 0 && closePrice / strike <= (1 - redeemPriceLimit)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * marginRatio1; - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) / td.SpotPrice.Value * (strike - closePrice); - } - else if (!detail.IsUseStrike && td.SpotPrice > 0 && closePrice / td.SpotPrice <= (1 - redeemPriceLimit)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * marginRatio1; - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (1 - closePrice / td.SpotPrice.Value); - } - else - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * marginRatio; - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.IsSingleMargin = false; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - /// - /// 触发条件预付金规则2 - /// - /// - /// - /// - private trade_span CalcSellSnowBallAndAutoCall2(trade td, margin_template_detail detail) - { - var margin = 0.0; - - var redeemPriceLimit = detail.RedeemPriceLimit ?? 0; - - var closePrice = td.SpotPrice ?? 0; - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - if (!new EodPriceProvider(_req.settleDate, false).TryGetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice, out closePrice)) - { - closePrice = udm.Price ?? 0; - } - } - - var strike = td.ActualStrike ?? 0; - //满足触发条件,需要增加浮亏部分 - if (detail.IsUseStrike && strike > 0 && closePrice / strike <= (1 - redeemPriceLimit)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * closePrice / td.SpotPrice.Value * (detail.MarginRatio2 ?? 0); - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) / td.SpotPrice.Value * (strike - closePrice); - } - else if (!detail.IsUseStrike && td.SpotPrice > 0 && closePrice / td.SpotPrice <= (1 - redeemPriceLimit)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * closePrice / td.SpotPrice.Value * (detail.MarginRatio2 ?? 0); - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (1 - closePrice / td.SpotPrice.Value); - } - else - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.IsSingleMargin = false; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - /// - /// 触发条件预付金规则3 - /// - /// - /// - /// - private trade_span CalcSellSnowBallAndAutoCall3(trade td, margin_template_detail detail) - { - var margin = 0.0; - - var redeemPriceLimit = detail.RedeemPriceLimit ?? 0; - - var closePrice = td.SpotPrice ?? 0; - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (_req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - if (!new EodPriceProvider(_req.settleDate, false).TryGetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice, out closePrice)) - { - closePrice = udm.Price ?? 0; - } - } - - var strike = td.ActualStrike ?? 0; - if (detail.IsUseStrike && strike > 0) - { - var rate = (double)((decimal)closePrice / (decimal)strike); - - var times = 0.0; - if (detail.MarginRatio2 > 0) - { - if (detail.PriceLimitType == 0) - { - times = Math.Floor(((1 - rate) - redeemPriceLimit) / detail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((rate - 1) - redeemPriceLimit) / detail.MarginRatio2.Value); - } - } - - if (detail.UsePositionStockEqvNotional) - { - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (detail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + detail.MarginRatio2.Value * times); - } - else - { - rateTemp = 1 + (redeemPriceLimit + detail.MarginRatio2.Value * times); - } - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * rateTemp * (detail.MarginRatio3 ?? 0); - } - else - { - //不满足追加比例时,用初始预付金 - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - } - else - { - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio3 ?? 0); - } - else - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - } - - //满足触发条件,需要增加浮亏部分 - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * strike / td.SpotPrice.Value * (redeemPriceLimit + detail.MarginRatio2.Value * times); - } - } - else if (!detail.IsUseStrike && td.SpotPrice > 0) - { - var rate = (double)((decimal)closePrice / (decimal)td.SpotPrice.Value); - - var times = 0.0; - if (detail.MarginRatio2 > 0) - { - if (detail.PriceLimitType == 0) - { - times = Math.Floor(((1 - rate) - redeemPriceLimit) / detail.MarginRatio2.Value); - } - else - { - times = Math.Floor(((rate - 1) - redeemPriceLimit) / detail.MarginRatio2.Value); - } - } - - if (detail.UsePositionStockEqvNotional) - { - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - //满足追加比例时,持仓名本分段式处理 - var rateTemp = 0.0; - if (detail.PriceLimitType == 0) - { - rateTemp = 1 - (redeemPriceLimit + detail.MarginRatio2.Value * times); - - } - else - { - rateTemp = 1 + (redeemPriceLimit + detail.MarginRatio2.Value * times); - - } - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * rateTemp * (detail.MarginRatio3 ?? 0); - } - else - { - //不满足追加比例时,用初始预付金 - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - } - else - { - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio3 ?? 0); - } - else - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - } - - //满足触发条件,需要增加浮亏部分 - if (detail.MarginRatio2 > 0 && (rate <= (1 - redeemPriceLimit) && detail.PriceLimitType == 0 || rate >= (1 + redeemPriceLimit) && detail.PriceLimitType == 1)) - { - margin += TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (redeemPriceLimit + detail.MarginRatio2.Value * times); - } - } - else - { - margin = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) * (detail.MarginRatio1 ?? 0); - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.IsSingleMargin = false; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - /// - /// 自动赎回买入预付金规则 - /// - /// - /// - private trade_span CalcBuySnowBallAndAutoCall(trade td) - { - if ((td.TradeType == "凤凰期权" || td.TradeType == "雪球期权") && td.BuySell == "买入") - { - var margin = 0.0; - - if (td.TradeType == "雪球期权") - { - var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(td, td.trade_snowball); - var snowball = (SimpleSnowball)optionTrade.Instrument; - //雪球期权算预付金,买入按照当前日期往后两个观察日算的票息作为预付金额,如果接近到期日,按到期日处理 - var valueDate = _req.settleDate; - if (snowball.CustomizedKOBarriers != null && snowball.CustomizedKOBarriers.Length > 0) - { - var kOObsDates = snowball.KOObsDates.Select(y => y.DateTime).Where(y => y > _req.settleDate).ToList(); - if (kOObsDates.Any() && kOObsDates.Count() >= 2) - { - kOObsDates = kOObsDates.OrderBy(y => y).ToList(); - valueDate = kOObsDates[1]; - } - else - { - valueDate = td.ExerciseDate.Value; - } - } - margin = snowball.CouponPayment(new Date(valueDate), td.trade_snowball.CouponIncludeStartDate == true); - } - else - { - var optionTrade = QdpTradeBuilder.GetAutocallOptionTrade(td, td.trade_autocall); - - var autocall = (AutoCall)optionTrade.Instrument; - - if (autocall.CustomizedKOBarriers != null && autocall.CustomizedKOBarriers.Length > 0) - { - var kOObsDates = autocall.KOObsDates.Select(y => y.DateTime).Where(y => y > _req.settleDate).ToList(); - var n = (td.SpotPrice > 0) ? (TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor) / td.SpotPrice.Value) : double.NaN; - if (kOObsDates.Any() && kOObsDates.Count() >= 2) - { - kOObsDates = kOObsDates.OrderBy(y => y).ToList(); - - var observation0 = autocall.GetEffectiveObservation( - kOObsDates[0], includeTradeStartDate: td.trade_autocall.CouponIncludeStartDate == true && td.trade_autocall.CouponDayCount != "Monthly", n: n); - var observation1 = autocall.GetEffectiveObservation( - kOObsDates[1], includeTradeStartDate: td.trade_autocall.CouponIncludeStartDate == true && td.trade_autocall.CouponDayCount != "Monthly", n: n); - margin = observation0.PaymentAmount + observation1.PaymentAmount; - } - else - { - var observation0 = autocall.GetEffectiveObservation( - td.ExerciseDate.Value, includeTradeStartDate: td.trade_autocall.CouponIncludeStartDate == true, n: n); - margin = observation0.PaymentAmount; - } - } - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - else - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = 0; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - } - - /// - /// 保底预付金规则 - /// - /// - /// - private trade_span CalcSingleSnowBallAndAutoCall(trade td) - { - if ((td.TradeType == "凤凰期权" || td.TradeType == "雪球期权") && td.BuySell == "卖出") - { - var margin = 0.0; - - //敲入转价差期权 - var isSingleMargin = td.TradeType == "雪球期权" && (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - || td.TradeType == "凤凰期权" && (td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption); - //保底的雪球凤凰期权预付金计算 - if (isSingleMargin) - { - if (td.TradeType == "雪球期权") - { - margin = Math.Abs(((td.trade_snowball.SpreadStrikeAtMaturity1 ?? 0) - (td.trade_snowball.SpreadStrikeAtMaturity ?? 0)) * (td.IsMoneynessOptionData ? (td.SpotPrice ?? 0) : 1) * (td.SpotPrice > 0 ? td.StockEqvNotional / td.SpotPrice.Value : td.Notional)); - } - else - { - margin = Math.Abs(((td.trade_autocall.SpreadStrike1 ?? 0) - (td.trade_autocall.SpreadStrike ?? 0)) * (td.IsMoneynessOptionData ? (td.SpotPrice ?? 0) : 1) * (td.SpotPrice > 0 ? td.StockEqvNotional / td.SpotPrice.Value : td.Notional)); - } - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.IsSingleMargin = isSingleMargin; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - else - { - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = 0.0; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - } - - #endregion - - /// - /// 买入自动赎回1 - /// - /// - /// - /// - private trade_span CalcBuyAutoRedeem(trade td, margin_template_detail detail) - { - var margin = 0.0; - var initialMargin = 0.0; - - if ((td.TradeType == "凤凰期权" || td.TradeType == "雪球期权") && td.BuySell == "买入") - { - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (udm == null) - { - udm = new underlying_manager(); - } - EodPrice eodPrice = null; - udm.QuotationDate = _req.settleDate; - double closePrice; - if (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - closePrice = td.SpotPrice ?? 0; - } - else - { - new EodPriceProvider(_req.settleDate, false).TryGetEodPrice(td.UnderlyingCode, out eodPrice); - - closePrice = eodPrice?.ClosePrice ?? udm.Price ?? 0; - } - - var optionValue = CalcTradeValueResult(td, udm, closePrice); - - double singleConple = 0.0; - double allCouples = 0.0; - if (td.TradeType == "雪球期权") - { - var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(td, td.trade_snowball); - var snowball = (SimpleSnowball)optionTrade.Instrument; - - if (snowball.KOObsDates != null && snowball.KOObsDates.Length > 0) - { - var firstKOObsDate = snowball.KOObsDates.Select(x => x.DateTime).OrderBy(x => x).FirstOrDefault(); - singleConple = snowball.CouponPayment(new Date(firstKOObsDate), td.trade_snowball.CouponIncludeStartDate == true); - allCouples = snowball.CouponPayment(new Date(td.ExerciseDate), td.trade_snowball.CouponIncludeStartDate == true); - } - } - else - { - var optionTrade = QdpTradeBuilder.GetAutocallOptionTrade(td, td.trade_autocall); - var autocall = (AutoCall)optionTrade.Instrument; - - if (autocall.KOObsDates != null && autocall.KOObsDates.Length > 0) - { - var koDates = autocall.KOObsDates.Select(x => x.DateTime).OrderBy(x => x).ToList(); - var firstKOObsDate = koDates.FirstOrDefault(); - singleConple = autocall.CouponPayment(new Date(firstKOObsDate), td.trade_autocall.CouponIncludeStartDate == true); - koDates.ForEach(x => { - if(x == firstKOObsDate) - { - allCouples += autocall.CouponPayment(new Date(x), td.trade_autocall.CouponIncludeStartDate == true); - } - else - { - allCouples += autocall.CouponPayment(new Date(x)); - } - }); - } - } - - margin = Math.Min((detail.MarginRatio1 ?? 0) * singleConple + (detail.MarginRatio2 ?? 0) * Math.Max(0, optionValue.Pv), allCouples); - - margin = CompareWithSpreadOptionMargin(td, detail, margin); - - initialMargin = td.InitialMargin * td.StockEqvNotional / td.OriginalStockEqvNotional * detail.ComparedInitialMarginRate ?? 0; - if (_helper.req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && !_helper.req.forOtherSide) - { - margin = Math.Max(margin, initialMargin); - } - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.InitialMargin = initialMargin; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = _req.PriceProvider.GetPrice(td.UnderlyingCode); - return tradeSpan; - } - - /// - /// 卖出自动赎回1 - /// - /// - /// - /// - private trade_span CalcSellAutoRedeem(trade td, margin_template_detail detail) - { - var margin = 0.0; - var initialMargin = 0.0; - - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (udm == null) - { - udm = new underlying_manager(); - } - EodPrice eodPrice = null; - udm.QuotationDate = _req.settleDate; - double closePrice; - if (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - closePrice = td.SpotPrice ?? 0; - } - else - { - new EodPriceProvider(_req.settleDate, false).TryGetEodPrice(td.UnderlyingCode, out eodPrice); - closePrice = eodPrice?.ClosePrice ?? udm.Price ?? 0; - } - - var optionValue = CalcTradeValueResult(td, udm, closePrice); - - var virtureRate = td.SpotPrice != null && td.SpotPrice != 0 ? Math.Max(0, (_req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? td.SpotPrice.Value : closePrice) - (td.ActualStrike ?? 0)) / td.SpotPrice.Value : 0; - var flag = _helper.req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? 0 : 1; - margin = td.StockEqvNotional * Math.Max(detail.MarginRatio1 ?? 0, (detail.MarginRatio2 ?? 0) - 0.5 * virtureRate) + flag * Math.Max(0, optionValue.Pv); - - margin = CompareWithSpreadOptionMargin(td, detail, margin); - initialMargin = td.InitialMargin * td.StockEqvNotional / td.OriginalStockEqvNotional * detail.ComparedInitialMarginRate ?? 0; - if (_helper.req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && !_helper.req.forOtherSide) - { - margin = Math.Max(margin, initialMargin); - } - - var tradeSpan = _helper.CreateTradeSpan(td, null); - tradeSpan.WorstCastClientPayable = margin; - tradeSpan.InitialMargin = initialMargin; - tradeSpan.IsSingleMargin = true; - tradeSpan.UnderlyingPrice = closePrice; - return tradeSpan; - } - - /// - /// 保底部分逻辑处理 - /// - /// - /// - /// - private double CompareWithSpreadOptionMargin(trade td, margin_template_detail detail, double margin) - { - if (detail.IsNeedCompare) - { - //敲入转价差期权 - var isSpreadOption = td.TradeType == "雪球期权" && (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - || td.TradeType == "凤凰期权" && (td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption || td.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption); - //保底的雪球凤凰期权预付金计算 - if (isSpreadOption) - { - var spreadOptionMargin = 0.0; - if (td.TradeType == "雪球期权") - { - spreadOptionMargin = Math.Abs(((td.trade_snowball.SpreadStrikeAtMaturity1 ?? 0) - (td.trade_snowball.SpreadStrikeAtMaturity ?? 0)) * (td.IsMoneynessOptionData ? (td.SpotPrice ?? 0) : 1) * td.Notional); - } - else - { - spreadOptionMargin = Math.Abs(((td.trade_autocall.SpreadStrike1 ?? 0) - (td.trade_autocall.SpreadStrike ?? 0)) * (td.IsMoneynessOptionData ? (td.SpotPrice ?? 0) : 1) * td.Notional); - } - - margin = Math.Min(margin, spreadOptionMargin); - } - } - - return margin; - } - } - } - - public class TradeTypeAndBuySell - { - public string TradeType { get; set; } - - public BuySellEnum BuySellType { get; set; } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GuoHaiMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GuoHaiMarginCalculation.cs deleted file mode 100644 index 6206beef..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GuoHaiMarginCalculation.cs +++ /dev/null @@ -1,82 +0,0 @@ -using YLErp.Enums; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.TradeModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 国海预付金算法 - /// - public class GuoHaiMarginCalculation : MarginCalculationBase - { - public static readonly GuoHaiMarginCalculation Instance; - - static GuoHaiMarginCalculation() - { - Instance = new GuoHaiMarginCalculation(); - } - - protected GuoHaiMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - List spanList = new List(); - var config = valuedateBLL.SystemDate; - - var clientId = req.tradeList.Select(O => O.ClientId).ToHashSet(); - var tradeId = req.tradeList.Select(O => O.id).ToHashSet(); - var tradeList = new List(req.tradeList); - using (var db = new YLContext()) - { - tradeList.AddRange( - db.trade.Where(O => - clientId.Contains(O.ClientId) && - O.TradeType != "现金流交易" && - O.TradeType != "远期" && - O.ExerciseDate >= req.settleDate && - O.TradeDate <= req.settleDate && - ConsTrade.PositionTradeStatusList.Contains(O.TradeStatus) && - O.ValidState != "InValid" && - !tradeId.Contains(O.id) && - O.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT)); - new TradeExtendService(req.UserInfo).SetTradeExtend(tradeList, true); - } - var ccrService = new CCRService(req.UserInfo); - ccrService.IsRealtime = req.CalcMarginType != CalcMarginTypeEnum.EodMargin; - ccrService.SettlementDate = req.settleDate; - var ccrDict = ccrService.CalculationCCR(tradeList, config.MarginJ, config.MarginN); - foreach (var item in req.tradeList) - { - if (!ccrDict.ContainsKey(item.id)) - { - //throw new Exception($"{item.id}预付金计算失败"); - //结构化交易和自定义交易不计算 - continue; - } - var ccr = ccrDict[item.id]; - spanList.Add(new trade_span() - { - TradeId = item.id, - ClientId = item.ClientId, - ValueDate = req.settleDate, - Spv = ccr, - Spv1 = ccr, - Spv2 = ccr, - Spv3 = ccr, - Spv4 = ccr, - WorstCastClientPayable = ccr - }); - } - return spanList; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var margin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - return margin.Where(O => O.TradeId == req.trade.id).FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GuoTouMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GuoTouMarginCalculation.cs deleted file mode 100644 index 191ee3a2..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GuoTouMarginCalculation.cs +++ /dev/null @@ -1,501 +0,0 @@ -using System.Collections; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Modules.DataProviderModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 国投 - /// - public class GuoTouMarginCalculation : MarginCalculationBase - { - public static readonly GuoTouMarginCalculation Instance; - - static GuoTouMarginCalculation() - { - Instance = new GuoTouMarginCalculation(); - } - - private GuoTouMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var calcTradeList = req.tradeList.ToList(); - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - var mpProvider = helper.GetMarginParamProvider(); - - var upLimitPrices = new ManualPriceProvider(); - var upLimitPricesTwoThirds = new ManualPriceProvider(); - var upLimitPricesOneThird = new ManualPriceProvider(); - var downLimitPrices = new ManualPriceProvider(); - var downLimitPricesTwoThirds = new ManualPriceProvider(); - var downLimitPricesOneThird = new ManualPriceProvider(); - var normalLimitPrices = new ManualPriceProvider(); - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - foreach (var t in req.tradeList) - { - if (upLimitPrices.Contains(t.UnderlyingCode)) - { - continue; - } - if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed)) - { - updownLimit = 0.05; - } - var price = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - price = t.SpotPrice ?? 0;//期初价 - break; - case CalcMarginTypeEnum.None: - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价 - break; - case CalcMarginTypeEnum.EodMargin: - price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价 - break; - } - - //var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider(req.settleDate); - //var spotPrice = eodpriceProvider.GetPrice(t.UnderlyingCode, SettlementTypeEnum.ClosePrice);//收盘价 - if (isFixed) - { - upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + updownLimit * 2.0 / 3.0); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + updownLimit / 3.0); - - downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - updownLimit * 2.0 / 3.0); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - updownLimit / 3.0); - } - else - { - upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit))); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit * 2.0 / 3.0) : (1 - updownLimit * 2.0 / 3.0))); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit / 3.0) : (1 - updownLimit / 3.0))); - - downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit))); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit * 2.0 / 3.0) : (1 + updownLimit * 2.0 / 3.0))); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit / 3.0) : (1 + updownLimit / 3.0))); - } - //Normal - normalLimitPrices.SetPrice(t.UnderlyingCode, price); - } - var prices = new[] { - ("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird), - ("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird), - ("normal", normalLimitPrices) - }; - - foreach (var price in prices) - { - - var key = $"{price.Item1}_0"; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: calcTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - volType: "开仓", - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any()) - { - continue; - } - - foreach (var item in tradeRiskResult.Results) - { - - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - var client = helper.GetClient(item.Trade); - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - value = pv * ratio; - } - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "upTwoThirds_0": - tempTradeSpan.Spv2 = value; break; - case "upOneThird_0": - tempTradeSpan.Spv3 = value; break; - case "normal_0": - tempTradeSpan.Spv4 = value; break; - case "down_0": - tempTradeSpan.Spv5 = value; break; - case "downTwoThirds_0": - tempTradeSpan.Spv6 = value; break; - case "downOneThird_0": - tempTradeSpan.Spv7 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - - resultMap[item.Trade.id].UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList(); - - var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join um in underlyingList on trade.UnderlyingId equals um.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, um.UnderlyingTypeId, UnderlyingId = um.id }).ToList(); - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var varietyGroups = clientGroup.Where(x => x.tradeSpan.IsSingleMargin != true).GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), - Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in varietyGroups) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - var tradeIdList = clientGroup.Where(x => x.UnderlyingTypeId == item.VarietyId && x.tradeSpan.IsSingleMargin != true).Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - - //单向追保,客户收取预付金为0 - if (!HasTwoSideMargin(item.ClientId) && item.WorstCastClientPayable > 0) - { - item.WorstCastClientPayable = 0; - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - else - { - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - } - - #endregion - } - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = varietyGroups.Sum(g => g.Spv1), - Spv2 = varietyGroups.Sum(g => g.Spv2), - Spv3 = varietyGroups.Sum(g => g.Spv3), - Spv4 = varietyGroups.Sum(g => g.Spv4), - Spv5 = varietyGroups.Sum(g => g.Spv5), - Spv6 = varietyGroups.Sum(g => g.Spv6), - Spv7 = varietyGroups.Sum(g => g.Spv7), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - #region 雪球期权 互换交易单独处理 - - var tradeSpanSnowballSingle = clientGroup.Where(x => x.tradeSpan.IsSingleMargin == true); - clientSpan.WorstCastClientPayable += tradeSpanSnowballSingle.Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - - #endregion - clientSpanNews.Add(clientSpan); - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate, ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate }); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - - - - public static double TradeMargin(RunMarginCalculationReq req, trade t) - { - UnderlyingDataProvider _underlyingDataProvider = new UnderlyingDataProvider(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - var mpProvider = helper.GetMarginParamProvider(); - - var upLimitPrices = new ManualPriceProvider(); - var upLimitPricesTwoThirds = new ManualPriceProvider(); - var upLimitPricesOneThird = new ManualPriceProvider(); - var downLimitPrices = new ManualPriceProvider(); - var downLimitPricesTwoThirds = new ManualPriceProvider(); - var downLimitPricesOneThird = new ManualPriceProvider(); - var normalLimitPrices = new ManualPriceProvider(); - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - //if (upLimitPrices.Contains(t.UnderlyingCode)) - //{ - // continue; - //} - if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed)) - { - updownLimit = 0.05; - } - var price = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - price = t.SpotPrice ?? 0;//期初价 - break; - case CalcMarginTypeEnum.None: - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价 - break; - case CalcMarginTypeEnum.EodMargin: - price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价 - break; - } - if (isFixed) - { - upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + updownLimit * 2.0 / 3.0); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + updownLimit / 3.0); - - downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - updownLimit * 2.0 / 3.0); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - updownLimit / 3.0); - } - else - { - upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit))); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit * 2.0 / 3.0) : (1 - updownLimit * 2.0 / 3.0))); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit / 3.0) : (1 - updownLimit / 3.0))); - - downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit))); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit * 2.0 / 3.0) : (1 + updownLimit * 2.0 / 3.0))); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit / 3.0) : (1 + updownLimit / 3.0))); - } - //Normal - normalLimitPrices.SetPrice(t.UnderlyingCode, price); - var prices = new[] { - ("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird), - ("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird), - ("normal", normalLimitPrices) - }; - ArrayList values=new ArrayList(); - foreach (var p in prices) - { - var key = $"{p.Item1}_0"; - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: new[] { t }, - calcScenario: req.GetCalcScenario(), - priceProvider: p.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - volType: "开仓", - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any()) - { - continue; - } - foreach (var item in tradeRiskResult.Results) - { - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv; - double value = 0; - if (item.Trade.TradeType == "收益互换") { - var client = helper.GetClient(item.Trade); - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - value = pv * ratio; - } - else - { - if (!helper.GetSpecialMargin(item.Trade, pv, out value)) - { - var client = helper.GetClient(item.Trade); - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - value = pv * ratio; - } - } - - values.Add(value); - } - } - return (double)values.ToArray().Max(); - } - - private List RunTradeSpanMarginCalculation(RunMarginCalculationReq req) - { - //结果集 - var resultMap = new List(); - - var subTradeList = req.tradeList.Where(x => x.ParentTradeId != 0 && x.IsGroup == 0).GroupBy(x => x.ParentTradeId); - if (subTradeList.Count() > 0) - { - foreach (var item in subTradeList) - { - var spans = RunMarginCalculation(req.Clone(item.ToList())); - var spv1 = spans.Sum(O => O.Spv1 ?? 0); - var spv2 = spans.Sum(O => O.Spv2 ?? 0); - var spv3 = spans.Sum(O => O.Spv3 ?? 0); - var spv4 = spans.Sum(O => O.Spv4 ?? 0); - var spv5 = spans.Sum(O => O.Spv5 ?? 0); - var spv6 = spans.Sum(O => O.Spv6 ?? 0); - var spv7 = spans.Sum(O => O.Spv7 ?? 0); - - var spvArr = new[] { spv1, spv2, spv3, spv4, spv5, spv6, spv7 }; - var maxSpv = spvArr.Max(); - var index = Array.IndexOf(spvArr, maxSpv); - spans.ForEach(x => x.WorstCastClientPayable = new[] { x.Spv1, x.Spv2, x.Spv3, x.Spv4, x.Spv5, x.Spv6, x.Spv7 }[index]); - resultMap.AddRange(spans); - } - } - var singleTradeList = req.tradeList.Where(O => O.ParentTradeId == 0).ToList(); - if (singleTradeList.Count > 0) - { - resultMap.AddRange(RunMarginCalculation(req.Clone(singleTradeList))); - } - return resultMap; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/GuoXinJinYangMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/GuoXinJinYangMarginCalculation.cs deleted file mode 100644 index 7bd8ee34..00000000 --- a/YLErpDAL/BLL/MarginCalculation/GuoXinJinYangMarginCalculation.cs +++ /dev/null @@ -1,800 +0,0 @@ -using Qdp.Foundation.Implementations; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Model.Enum; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class GuoXinJinYangMarginCalculation : MarginCalculationBase - { - public static readonly GuoXinJinYangMarginCalculation Instance; - static GuoXinJinYangMarginCalculation() - { - Instance = new GuoXinJinYangMarginCalculation(); - - } - public GuoXinJinYangMarginCalculation() - { - } - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var calcTradeList = req.tradeList.ToList(); - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - helper.GetTradVolRateDic(out var tradeVolRateDic); - - //获取执行价格,敲出 ,敲入价格 - //获取有敲出敲入 点位交易 , - IPriceProvider knockInPricesDic = new Modules.DataProviderModule.ManualPriceProvider(); - IPriceProvider knockOutPricesDic = new Modules.DataProviderModule.ManualPriceProvider(); - var prices = new Dictionary(); - prices.Add("up", upLimitPrices); - prices.Add("down", downLimitPrices); - prices.Add("normal", req.PriceProvider); - var TradeStockEqvNotional = req.tradeList.GroupBy(l => l.ClientId).Select(l => new { clientId = l.Key, maxStockEqvNotional = l.Max(g => g.StockEqvNotional) }); - var clientList = new List(); - //获取 超过阈值客户 - using (var db = new YLContext()) - { - foreach (var s in TradeStockEqvNotional) - { - var clients = db.MarginCalculationThreshold.Where(l => l.ClientId == s.clientId && l.MarginCalcuThreshold < s.maxStockEqvNotional && l.TakeEffectDate <= req.settleDate).OrderByDescending(l => l.TakeEffectDate).Select(l => l.ClientId).FirstOrDefault(); - if (clients != null) clientList.Add(clients); - } - } - //获取每笔 交易 的 敲出 敲出点位 - var barPriceDic = KnockInandKnockOutPriceByTradeList(req.tradeList, req.settleDate, clientList); - if (barPriceDic.Count > 0) - { - var listPrice = barPriceDic.Select(l => new { key = l.Key, value = double.TryParse(l.Value?.ToString(), out var a) ? a : 0 }).Where(l => l.value < upLimitPrices.GetPrice(l.key.Split(',')[1]) && l.value > downLimitPrices.GetPrice(l.key.Split(',')[1])).ToList(); - if (listPrice.Count > 0) - { - var listDicprice = listPrice.GroupBy(l => new { ucode = (l.key.Split(',')[1]), price = l.value }).Select(l => l.Key).ToList(); - for (var i = 0; i < listDicprice.Count; i++) - { - var barPrices = new ManualPriceProvider(); - barPrices.SetPrice(listDicprice[i].ucode, listDicprice[i].price); - prices.Add("barPrice," + listDicprice[i].ucode + "," + i, barPrices); - } - } - - } - var volRates = new[] { null, tradeVolRateDic }; - var loops = prices.ToList().SelectMany(n => volRates.Select(m => new - { - pricekey = n.Key, - priceProvider = n.Value, - addVolRateDic = m - })).ToArray(); - - var pVJsons = new List(); - foreach (var loop in loops) - { - - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null, pricekey: loop.pricekey); - - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - - var client = helper.GetClient(item.Trade.ClientId); - var clientRatio = client?.Ratio ?? 1.0; - var clientRatio1 = client?.Ratio1 ?? 1.0; - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio1; - } - else - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - } - var pVJson = new PVJson(); - int VarietyId = 0; - using (var db = new YLContext()) - { - var Variety = db.underlying_manager.AsNoTracking().Where(t => t.id == item.Trade.UnderlyingId).FirstOrDefault(); - if (Variety != null) { VarietyId= Variety.UnderlyingTypeId; } - } - //var v item.Trade.UnderlyingId; - switch (key) - { - case "up_1": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.Name = "up_1"; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Value = value; - pVJsons.Add(pVJson); - break; - case "up_0": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = "up_0"; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - case "normal_0": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = "normal_0"; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - case "normal_1": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = "normal_1"; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - case "down_1": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = "down_1"; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - case "down_0": - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = "down_0"; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - default: - pVJson.TradeId = item.Trade.id; - pVJson.VarietyId = VarietyId; - pVJson.ClientId = item.Trade.ClientId; - pVJson.Name = key; - pVJson.Value = value; - pVJsons.Add(pVJson); break; - } - if (contains) - { - //tempTradeSpan.SetWorstCastClientPayable(); - tempTradeSpan.WorstCastClientPayable = pVJsons.Max(l => l.Value); - if (client != null) - { - var value2 = (double)tempTradeSpan.WorstCastClientPayable; - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - value2 = item.Trade.BuySell == "卖出" ? 0 : Math.Max(value2, 0); - } - tempTradeSpan.WorstCastClientPayable = value2; - } - } - } - } - - pVJsons.GroupBy(l => l.TradeId).ToList().ForEach(tId => - { - resultMap[tId.Key].PVJsonList = pVJsons.Where(l => l.TradeId == tId.Key).ToList(); - //resultMap[tId.Key].WorstCastClientPayable = pVJsons.Max(l => l.Value); - resultMap[tId.Key].PVJsons = JsonHelper.ToJson(resultMap[tId.Key].PVJsonList); - }); - return resultMap.Values.ToList(); - } - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - var runMargin = new RunMarginCalculationReq(req.UserInfo); - runMargin.settleDate = req.settleDate; - var helper = new RunMarginCalculationHelper(runMargin, _underlyingDataProvider); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList(); - - var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join um in underlyingList on trade.UnderlyingId equals um.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, um.UnderlyingTypeId}).ToList(); - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var varietyGroups = clientGroup.GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - PVJsonList = t.SelectMany(l => l.tradeSpan.PVJsonList.Select(x => new ClientPVJson { Name = x.Name, Value = x.Value, VarietyId = x.VarietyId })).ToList() - }).ToList(); - foreach (var item in varietyGroups) - { - if (item.PVJsonList != null && item.PVJsonList.Any()) - { - var sumPVModel = item.PVJsonList.GroupBy(l => new { l.Name, l.VarietyId }).Select(x => new { PvName = x.Key.Name, sumPv = -x.Sum(l => l.Value) }); - var minModel = sumPVModel.OrderBy(l => l.sumPv).FirstOrDefault(); - item.WorstCastClientPayable = minModel.sumPv; - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - var tradeIdList = clientGroup.Where(x => x.UnderlyingTypeId == item.VarietyId).Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - - if (item.PVJsonList.Any(l => l.Name == minModel.PvName)) - { - tradeSpansUpdate.ForEach(x => - { - if (x.PVJsons != null) - { - x.PVJsonList = JsonHelper.Deserialize>(x.PVJsons); - if (x.PVJsonList != null && x.PVJsonList.Any(l => l.Name == minModel.PvName)) - { - x.WorstCastClientPayable = x.PVJsonList.FirstOrDefault(l => l.Name == minModel.PvName).Value; - } - } - }); - tradeSpansReq.ForEach(x => - { - if (x.PVJsons != null) - { - x.PVJsonList = JsonHelper.Deserialize>(x.PVJsons); - if (x.PVJsonList != null && x.PVJsonList.Any(l => l.Name == minModel.PvName)) - { - x.WorstCastClientPayable = x.PVJsonList.FirstOrDefault(l => l.Name == minModel.PvName).Value; - } - } - }); - } - #endregion - } - } - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - DeltaMargin = tradeSpanInfo.Where(g => g.trade.ClientId == clientGroup.Key).Sum(g => g.tradeSpan.DeltaMargin * -1), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - if (!HasTwoSideMargin(clientGroup.Key)) - { - double? worstCastClientPayable = 0; - foreach (var vg in varietyGroups) - { - if (vg.WorstCastClientPayable < 0) - { - worstCastClientPayable += vg.WorstCastClientPayable; - } - else - { - var tradeIdList = clientGroup.Where(l=>l.UnderlyingTypeId == vg.VarietyId).Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == vg.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == vg.ClientId && x.ValueDate == req.settleDate).ToList(); - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - } - clientSpan.WorstCastClientPayable = worstCastClientPayable; - //foreach (var item in varietyGroups) - //{ - // var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - // var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - // var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - // tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - // tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - //} - } - clientSpan.PVJsonList = varietyGroups.SelectMany(l => l.PVJsonList.GroupBy(x => new { x.Name, x.VarietyId }).Select(x => new ClientPVJson { Name = x.Key.Name, Value = -x.Sum(a => a.Value), VarietyId = x.Key.VarietyId })); - clientSpan.PVJsons = JsonHelper.ToJson(clientSpan.PVJsonList); - clientSpanNews.Add(clientSpan); - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate, ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}=@settleDate and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { req.settleDate }); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin && tradeMargin.FirstOrDefault() != null) - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - - return margin; - } - return 0.0; - } - public Dictionary KnockInandKnockOutPriceByTradeList(List listTrade, DateTime settleDate, List clientList) - { - var observationStatus = new List() { "已敲入", "已敲出", "观察中" }; - var dicPrice = new Dictionary(); - foreach (var t in listTrade) - { - //过滤没超过阈值客户 - if (!clientList.Contains(t.ClientId)) - { - continue; - } - switch (t.TradeType) - { - case "障碍期权": - { - var barrier = t.trade_barrier_option?.Clone() ?? new trade_barrier_option(); - if (string.IsNullOrEmpty(barrier.ObservationDates)) - { - barrier.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(barrier.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - barrier.LatestObservationDate = latestObservationDate.DateTime; - } - else - { - barrier.LatestObservationDate = null; - } - } - if (observationStatus.Contains(barrier.KnockInOutStatusCn)) - { - if (barrier.LatestObservationDate == settleDate) - { - var ObservationStatus = barrier.KnockInOutStatusCn; - var konckInOutDate = barrier.KnockInOutDate; - if (barrier.BarrierPrice != null) - { - var BarrierLow = t.IsMoneynessOption == "是" ? barrier.BarrierPrice * t.SpotPrice : barrier.BarrierPrice; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (barrier.UpperBarrierPrice != null) - { - var BarrierHigh = t.IsMoneynessOption == "是" ? barrier.UpperBarrierPrice * t.SpotPrice : barrier.UpperBarrierPrice; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - } - } - break; - case "双鲨期权": - { - var doubleSharkFin = t.trade_double_sharkfin_option?.Clone() ?? new trade_double_sharkfin_option(); - if (string.IsNullOrEmpty(doubleSharkFin.ObservationDates)) - { - doubleSharkFin.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(doubleSharkFin.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - doubleSharkFin.LatestObservationDate = latestObservationDate.DateTime; - } - else - { - doubleSharkFin.LatestObservationDate = null; - } - } - if (observationStatus.Contains(doubleSharkFin.KnockInOutStatusCn)) - { - if (doubleSharkFin.LatestObservationDate == settleDate) - { - var ObservationStatus = doubleSharkFin.KnockInOutStatusCn; - var konckInOutDate = doubleSharkFin.KnockInOutDate; - var BarrierLow = t.IsMoneynessOption == "是" ? doubleSharkFin.BarrierLow * t.SpotPrice : doubleSharkFin.BarrierLow; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - - var BarrierHigh = t.IsMoneynessOption == "是" ? doubleSharkFin.BarrierHigh * t.SpotPrice : doubleSharkFin.BarrierHigh; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - } - break; - case "凤凰期权": - { - var tradeautocall = t.trade_autocall?.Clone() ?? new trade_autocall(); - using (var db = new YLContext()) - { - tradeautocall.HappenedObservations = db.autocall_observation.AsNoTracking().Where(o => o.TradeId == t.id && o.EndDate <= DateTime.MaxValue).ToList(); - } - if (string.IsNullOrEmpty(tradeautocall.ObservationDates)) - { - tradeautocall.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(tradeautocall.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - tradeautocall.LatestObservationDate = latestObservationDate.DateTime; - } - } - - if (string.IsNullOrEmpty(tradeautocall.KOObservationDates)) - { - tradeautocall.LatestKOObservationDate = settleDate; - tradeautocall.LatestKOBarrier = tradeautocall.KOBarrier; - if (tradeautocall.LatestKOBarrier != null) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "LatestKOBarrier", tradeautocall.LatestKOBarrier); - } - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(tradeautocall.KOObservationDates); - var koObservationDates = customizedResults.Item1; - var customizedKOBarriers = customizedResults.Item2; - var latestKOObservationDate = koObservationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestKOObservationDate != null) - { - tradeautocall.LatestKOObservationDate = latestKOObservationDate.DateTime; - - if (customizedKOBarriers == null || !customizedKOBarriers.Any()) - { - tradeautocall.LatestKOBarrier = tradeautocall.KOBarrier; - } - else - { - tradeautocall.LatestKOBarrier = customizedKOBarriers[GetDateIndex(koObservationDates, latestKOObservationDate)]; - } - if (tradeautocall.LatestKOBarrier != null) - { dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "LatestKOBarrier", tradeautocall.LatestKOBarrier); } - - } - } - - if (observationStatus.Contains(tradeautocall.KnockInOutStatusCn)) - { - if (tradeautocall.LatestObservationDate == settleDate || tradeautocall.LatestKOObservationDate == settleDate) - { - var ObservationStatus = tradeautocall.KnockInOutStatusCn; - var konckInOutDate = tradeautocall.KnockInOutDate; - var BarrierLow = t.IsMoneynessOption == "是" ? tradeautocall.KIBarrier * t.SpotPrice : tradeautocall.KIBarrier; - var BarrierHigh = t.IsMoneynessOption == "是" ? tradeautocall.KOBarrier * t.SpotPrice : tradeautocall.KOBarrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - } - break; - case "雪球期权": - { - var snowball = t.trade_snowball?.Clone() ?? new trade_snowball(); - if (string.IsNullOrEmpty(snowball.ObservationDates)) - { - snowball.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(snowball.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - snowball.LatestObservationDate = latestObservationDate.DateTime; - - } - } - if (string.IsNullOrEmpty(snowball.KOObservationDates)) - { - snowball.LatestKOObservationDate = settleDate; - if (snowball.LatestKOBarrier != null) - { - snowball.LatestKOBarrier = snowball.KOBarrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "LatestKOBarrier", snowball.LatestKOBarrier); - } - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(snowball.KOObservationDates); - var koObservationDates = customizedResults.Item1; - var customizedKOBarriers = customizedResults.Item2; - var latestKOObservationDate = koObservationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestKOObservationDate != null) - { - snowball.LatestKOObservationDate = latestKOObservationDate.DateTime; - - if (customizedKOBarriers == null || !customizedKOBarriers.Any()) - { - snowball.LatestKOBarrier = snowball.KOBarrier; - } - else - { - snowball.LatestKOBarrier = customizedKOBarriers[GetDateIndex(koObservationDates, latestKOObservationDate)]; - } - if (snowball.LatestKOBarrier != null) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "LatestKOBarrier", snowball.LatestKOBarrier); - } - } - } - if (observationStatus.Contains(snowball.KnockInOutStatusCn)) - { - if (snowball.LatestObservationDate == settleDate) - { - var ObservationStatus = snowball.KnockInOutStatusCn; - var konckInOutDate = snowball.KnockInOutDate; - var BarrierLow = t.IsMoneynessOption == "是" ? snowball.KIBarrier * t.SpotPrice : snowball.KIBarrier; - var BarrierHigh = t.IsMoneynessOption == "是" ? snowball.KOBarrier * t.SpotPrice : snowball.KOBarrier; - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", out var a)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", out var b)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - - } - if (snowball.LatestKOObservationDate == settleDate) - { - var ObservationStatus = snowball.KnockInOutStatusCn; - var konckInOutDate = snowball.KnockInOutDate; - if (ConsGlobal.CallPut.IsCall(t.OptionType)) //向下敲入向上敲出 - { - var BarrierHigh = t.IsMoneynessOption == "是" ? snowball.KOBarrier * t.SpotPrice : snowball.KOBarrier; - var BarrierLow = t.IsMoneynessOption == "是" ? snowball.KIBarrier * t.SpotPrice : snowball.KIBarrier; - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", out var a)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", out var b)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - else //向上敲入向下敲出 - { - var BarrierLow = t.IsMoneynessOption == "是" ? snowball.KOBarrier * t.SpotPrice : snowball.KOBarrier; - var BarrierHigh = t.IsMoneynessOption == "是" ? snowball.KIBarrier * t.SpotPrice : snowball.KIBarrier; - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", out var a)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (!dicPrice.TryGetValue(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", out var b)) - { - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - } - } - } - break; - case "二元期权": - { - var binary = t.trade_binary_option?.Clone() ?? new trade_binary_option(); - if (t.ExerciseModeCn == "欧式") - { - break; - } - if (string.IsNullOrEmpty(binary.ObservationDates)) - { - binary.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(binary.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - binary.LatestObservationDate = latestObservationDate.DateTime; - } - else - { - binary.LatestObservationDate = null; - } - } - if (binary.LatestObservationDate == settleDate) - { - - if (t.Strike != null) - { - var BarrierLow = t.IsMoneynessOption == "是" ? t.Strike * t.SpotPrice : t.Strike; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (binary.UpperBarrier != null) - { - var BarrierHigh = t.IsMoneynessOption == "是" ? binary.UpperBarrier * t.SpotPrice : binary.UpperBarrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - - } - } - break; - case "气囊结构": - { - var airbag = t.trade_airbag ?? new trade_airbag(); - var BarrierLow = t.IsMoneynessOption == "是" ? t.trade_airbag.Barrier * t.SpotPrice : t.trade_airbag.Barrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - //没有观察日,只计算敲入敲出 - } - break; - case "区间累积期权": - { - var rangeaccrual = t.trade_rangeaccrual?.Clone() ?? new trade_rangeaccrual(); - if (string.IsNullOrEmpty(rangeaccrual.ObservationDates)) - { - rangeaccrual.LatestObservationDate = settleDate; - } - else - { - var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(rangeaccrual.ObservationDates); - var observationDates = customizedResults.Item1; - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - rangeaccrual.LatestObservationDate = latestObservationDate.DateTime; - } - else - { - rangeaccrual.LatestObservationDate = null; - } - } - if (rangeaccrual.LatestObservationDate == settleDate) - { - if (t.Strike != null) - { - var BarrierLow = t.IsMoneynessOption == "是" ? t.Strike * t.SpotPrice : t.Strike; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - - } - } - break; - case "累计期权": - { - var accumulator = t.trade_accumulator_option?.Clone() ?? new trade_accumulator_option(); - DateTime? LatestObservationDate = settleDate; - if (!string.IsNullOrEmpty(accumulator.KOObservationDates)) - { - var observationDates = QdpHelper.ParseObservationDate(accumulator.KOObservationDates); - var latestObservationDate = observationDates.Where(x => x.DateTime >= settleDate).OrderBy(x => x.DateTime).FirstOrDefault(); - if (latestObservationDate != null) - { - LatestObservationDate = latestObservationDate.DateTime; - } - else - { - LatestObservationDate = null; - } - } - if (accumulator.KnockOutDate.HasValue) - { - var konckInOutDate = accumulator.KnockOutDate; - if (ConsGlobal.CallPut.IsCall(t.OptionType)) - { - if (t.Strike != null) - { - var BarrierLow = t.IsMoneynessOption == "是" ? t.Strike * t.SpotPrice : t.Strike; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (accumulator.KOBarrier != null) - { - var BarrierHigh = t.IsMoneynessOption == "是" ? accumulator.KOBarrier * t.SpotPrice : accumulator.KOBarrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - else - { - if (t.Strike != null) - { - var BarrierLow = t.IsMoneynessOption == "是" ? t.Strike * t.SpotPrice : t.Strike; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierLow", BarrierLow); - } - if (accumulator.KOBarrier != null) - { - var BarrierHigh = t.IsMoneynessOption == "是" ? accumulator.KOBarrier * t.SpotPrice : accumulator.KOBarrier; - dicPrice.Add(t.id + "," + t.UnderlyingCode + "," + "BarrierHigh", BarrierHigh); - } - } - } - } - break; - } - } - return dicPrice; - } - private int GetDateIndex(Date[] source, Date value) - { - var index = 0; - foreach (var item in source) - { - if (item.DateTime == value.DateTime) - { - return index; - } - - index++; - } - return -1; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/HaiTongMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/HaiTongMarginCalculation.cs deleted file mode 100644 index d2495a95..00000000 --- a/YLErpDAL/BLL/MarginCalculation/HaiTongMarginCalculation.cs +++ /dev/null @@ -1,479 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 海通预付金计算 - /// - public class HaiTongMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly HaiTongMarginCalculation Instance; - - static HaiTongMarginCalculation() - { - Instance = new HaiTongMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected HaiTongMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var resultMap = new List(); - - var list2 = new List(req.tradeList.Count); - - using (var db = new YLContext()) - { - var tradeIds = req.tradeList.Select(x => x.id); - var tradeMarginTemplates = db.trade_margin_template.Where(x => tradeIds.Contains(x.TradeId)).ToList(); - foreach (var td in req.tradeList) - { - //交易员买客户卖的雪球,就用span算法;交易员卖客户买,就用文档里的公式 - if (td.TradeType == "雪球期权" && td.BuySell == "卖出") - { - double value = 0; - var actualStrike = td.IsMoneynessOptionData ? td.Strike : td.Strike / td.SpotPrice; - var SpreadStrike = td.IsMoneynessOptionData ? td.trade_snowball.SpreadStrikeAtMaturity : td.trade_snowball.SpreadStrikeAtMaturity / td.SpotPrice; - //雪球期权 - 保底雪球(仅收初始预付金,后续不追保):逐笔交易持仓预付金=簿记预付金模板选为“雪球保底固定比例”; - //雪球期权 - 非保底雪球(不收初始预付金,后续线性追保,跌多少追多少):逐笔交易持仓预付金 = max(1 - 标的每日收盘价 / 期初价格,0)*名义本金; - //雪球期权 - 其他(系统定价类型):逐笔交易持仓预付金 = Span涨跌停行情下的雪球持仓市值 * 1.1。 - if (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption) - { - value = ((td.StockEqvNotional) * (SpreadStrike - actualStrike)) ?? 0; - } - else if (td.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption) - { - value = ((td.StockEqvNotional) * (actualStrike - SpreadStrike)) ?? 0; - } - else - { - if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin) - { - var closePrice = req.PriceProvider.GetPrice(td.UnderlyingCode); - value = Math.Max(1 - closePrice / (double)td.SpotPrice, 0) * td.StockEqvNotional + td.InitialMargin ?? 0; - } - } - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var client = helper.GetClient(td.ClientId); - var ts = new trade_span() - { - TradeId = td.id, - ClientId = td.ClientId, - ValueDate = req.settleDate, - UnderlyingId = td.UnderlyingId, - UnderlyingCode = td.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - IsSingleMargin = true, - Comment = "雪球特殊算法", - }; - if (client != null) - { - if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保 || client.MarginOptionType == (int)MarginOptionEnum.其他) - { - value = 0; - } - else - { - value = Math.Max((double)value, 0); - } - } - ts.SetAllSpvAndWorst((double)value); - resultMap.Add(ts); - } - else - { - list2.Add(td); - } - } - resultMap.AddRange(marginCalculation(req.Clone(list2))); - return resultMap; - } - } - private List marginCalculation(RunMarginCalculationReq req) - { - //结果集 - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - helper.GetUpDownVolRateDic(out var tradeVolRateDicUp, out var tradeVolRateDicDown); - - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - - var volRates = new (int, Dictionary)[] { - (0, null), - (1, tradeVolRateDicUp), - (2, tradeVolRateDicDown) - }; - - foreach (var price in prices) - { - foreach (var itemDic in volRates) - { - var key = $"{price.Item1}_{itemDic.Item1}"; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: req.tradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: itemDic.Item2, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - foreach (var item in tradeRiskResult.Results) - { - var client = helper.GetClient(item.Trade.ClientId); - var clientRatio = client?.Ratio ?? 1.0; - var clientRatio1 = client?.Ratio1 ?? 1.0; - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio1; - } - else - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - } - - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - if (item.Trade.TradeType == "雪球期权" && item.Trade.BuySell == "买入") - { - resultMap[item.Trade.id].IsSingleMargin = true; - resultMap[item.Trade.id].Comment = "雪球买入"; - } - } - - switch (key) - { - case "up_1": - tempTradeSpan.Spv1 = value; break; - case "up_0": - tempTradeSpan.Spv2 = value; break; - case "up_2": - tempTradeSpan.Spv3 = value; break; - case "normal_0": - tempTradeSpan.Delta = item.ValueResult.Delta; - tempTradeSpan.UnderlyingPrice = req.PriceProvider.GetPrice(item.ValueResult.UnderlyingCode); - mpProvider.TryGetMarginRate(item.ValueResult.UnderlyingCode, out var marginRate); - tempTradeSpan.DeltaMargin = (tempTradeSpan.Delta * tempTradeSpan.UnderlyingPrice * marginRate) ?? 0; - break; - case "normal_1": - tempTradeSpan.Spv4 = value; break; - case "normal_2": - tempTradeSpan.Spv5 = value; break; - case "down_1": - tempTradeSpan.Spv6 = value; break; - case "down_0": - tempTradeSpan.Spv7 = value; break; - case "down_2": - tempTradeSpan.Spv8 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - if (client != null) - { - var value2 = (double)tempTradeSpan.WorstCastClientPayable; - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - value2 = item.Trade.BuySell == "卖出" ? 0 : Math.Max(value2, 0); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保 || client.MarginOptionType == (int)MarginOptionEnum.其他) - { - value2 = 0; - } - else if (client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - value2 = Math.Max(value2, 0); - } - tempTradeSpan.WorstCastClientPayable = value2; - } - } - } - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - //海通预付金保底收益率-用来计算名义本金 - double GuaranteedIncome = (db.valuedate.FirstOrDefault().GuaranteedIncome ?? 100) / 100; - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var client = DataCacheProvider.GetClientDataSource().GetData(clientGroup.Key); - var clientLevel = DataCacheProvider.GetClientLevelDataSource().GetData(client.LevelId ?? 0); - var clientRatio = clientLevel?.Ratio ?? 1.0; - - var underlyingGroup = clientGroup.Where(x => x.tradeSpan.IsSingleMargin != true).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - //负数代表客户应缴预付金,正数代表客户应收预付金 - Spv1 = -t.Sum(g => g.tradeSpan.Spv1), - Spv2 = -t.Sum(g => g.tradeSpan.Spv2), - Spv3 = -t.Sum(g => g.tradeSpan.Spv3), - Spv4 = -t.Sum(g => g.tradeSpan.Spv4), - Spv5 = -t.Sum(g => g.tradeSpan.Spv5), - Spv6 = -t.Sum(g => g.tradeSpan.Spv6), - Spv7 = -t.Sum(g => g.tradeSpan.Spv7), - Spv8 = -t.Sum(g => g.tradeSpan.Spv8), - WorstCastClientPayable = -t.Sum(g => g.tradeSpan.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - foreach (var item in underlyingGroup) - { - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保 || client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - if (clientGroup.Where(m => m.trade.UnderlyingId == item.UnderlyingId && m.trade.ClientId == item.ClientId).Count() > 1) - { - item.SetWorstCastClientPayableMin(); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else if (item.WorstCastClientPayable == item.Spv7) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - else if (item.WorstCastClientPayable == item.Spv8) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8); - } - - #endregion - } - else - { - var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - tradeSpansUpdate.ForEach(x => x.Comment = "单笔计算"); - } - - //客户信息中追保方向为“单向追保”或“双向追保”的客户: call 看涨 - //(1)Call净名义本金 = 客户Call卖方持仓名义本金 - 客户Call买方持仓名义本金; - //(2)Put净名义本金 = 客户Put卖方持仓名义本金 - 客户Put买方持仓名义本金; - //(3)单品种预付金占用 = max(0, max(∑逐笔交易持仓预付金,(Call净名义本金 + Put净名义本金)*1 % *1.1)); - //(4)预付金占用 =∑单品种预付金占用。 - //客户信息追保方向“对手方单向追保”或“其他”的客户:预付金占用 = 0。 - - var callsale = clientGroup.Where(m => m.trade.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "买入" && m.trade.OptionType == "看涨").Select(m => m.trade.StockEqvNotional).Sum(); - var callbuy = clientGroup.Where(m => m.trade.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "卖出" && m.trade.OptionType == "看涨").Select(m => m.trade.StockEqvNotional).Sum(); - var putsale = clientGroup.Where(m => m.trade.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "买入" && m.trade.OptionType == "看跌").Select(m => m.trade.StockEqvNotional).Sum(); - var putbuy = clientGroup.Where(m => m.trade.UnderlyingId == item.UnderlyingId && m.trade.BuySell == "卖出" && m.trade.OptionType == "看跌").Select(m => m.trade.StockEqvNotional).Sum(); - - var StockEqvNotional = (double)((callsale - callbuy + putsale - putbuy) * GuaranteedIncome * clientRatio); - - if (client.MarginOptionType != (int)MarginOptionEnum.双向追保) - { - item.WorstCastClientPayable = -Math.Max(0, Math.Max(-(double)item.WorstCastClientPayable, StockEqvNotional)); - } - } - else - { - item.WorstCastClientPayable = 0; - } - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - Spv5 = underlyingGroup.Sum(g => g.Spv5), - Spv6 = underlyingGroup.Sum(g => g.Spv6), - Spv7 = underlyingGroup.Sum(g => g.Spv7), - Spv8 = underlyingGroup.Sum(g => g.Spv8), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - DeltaMargin = tradeSpanInfo.Where(g => g.trade.ClientId == clientGroup.Key).Sum(g => g.tradeSpan.DeltaMargin * -1), - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - - #region 雪球期权单独处理 - - var tradeSpanSingle = clientGroup.Where(x => x.tradeSpan.IsSingleMargin == true); - clientSpan.WorstCastClientPayable += tradeSpanSingle.Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - - #endregion - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - //var clientIds = clientSpanNews.Select(t => t.ClientId).Distinct().ToList(); - //var clientSpanOlds = db.client_span.Where(t => t.SpanType == SpanType); - if (req.RefreshClientIds != null) - { - //clientSpanOlds = db.client_span.Where(t => RefreshClientIds.Contains(t.ClientId ?? 0)); - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - //MySqlBulkExtensions.BulkDelete(db, clientSpanOlds); - } - else - { - if(req.ClientIds !=null) - { - - } - //var clientSpanOldsWithOutFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && !t.ModifiedFlag).ToList(); - //MySqlBulkExtensions.BulkDelete(db, clientSpanOldsWithOutFlag); - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin && tradeMargin.FirstOrDefault() != null) - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - - return margin; - } - return 0.0; - } - - - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/HongYeMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/HongYeMarginCalculation.cs deleted file mode 100644 index e6621dd8..00000000 --- a/YLErpDAL/BLL/MarginCalculation/HongYeMarginCalculation.cs +++ /dev/null @@ -1,327 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Model.Enum; -using YLErp.Modules.CalculationModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class HongYeMarginCalculation : MarginCalculationBase - { - //定义一个静态变量来保存类的实例(单例模式) - public static readonly HongYeMarginCalculation Instance; - - static HongYeMarginCalculation() - { - Instance = new HongYeMarginCalculation(); - } - - //定义私有构造函数,使外界不能创建该类实例 - private HongYeMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - return CalcMargin(req).ToList(); - } - - - private IEnumerable CalcMargin(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - var calcReq = helper.GetCalculateRisksForTradesReq(req.PriceProvider, null, null, QdpPricingRequest.BASIC_PRICING); - - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - calcReq.volType = "开仓"; - calcReq.isUseTradeVol = false; - break; - case CalcMarginTypeEnum.None: - case CalcMarginTypeEnum.EodMargin: - default: - calcReq.volType = "交易"; - calcReq.isUseTradeVol = true; - break; - } - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - foreach (var item in tradeRiskResult.Results) - { - resultMap[item.Trade.id] = generateTradeSpan( - (resultMap.ContainsKey(item.Trade.id) ? resultMap[item.Trade.id] : null), - item, - helper, - req); - } - - var structureIds = new List(); - var tDict = - (from r in tradeRiskResult.Results - join ts in resultMap - on r.Trade.id equals ts.Key - where r.Trade.TradeType == "结构化交易" || - r.Trade.ParentTradeId != 0 - group new { r, ts } by r.Trade.ParentTradeId into rGroup - select rGroup).ToDictionary(K => K.First().r.Trade, V => V.ToList()); - - if (tDict.Count > 0) - { - foreach (var structureItem in tDict) - { - var client = GetClientInfo(structureItem.Key.ClientId); - var direction = structureItem.Value.Select(O => O.r.Trade.BuySell).ToHashSet(); - double value = 0; - var index = 0; - if ((structureItem.Key.StructureType == "牛市价差" || structureItem.Key.StructureType == "熊市价差") && structureItem.Value.Count >= 2) - { - if (client != null && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.单向追保) - { - var buyLeg = structureItem.Value.Where(O => O.r.Trade.BuySell == "买入").FirstOrDefault(); - var buyMargin = (buyLeg?.ts.Value.WorstCastClientPayable) ?? 0; - foreach (var item in structureItem.Value) - { - setTradeSpanValue(item.ts.Value, 0); - } - if (structureItem.Value.Sum(O => O.r.ValueResult.Pv) > 0) - { - var strikes = structureItem.Value.Select(O => ((O.r.Trade.IsMoneynessOption == "是" ? (O.r.Trade.SpotPrice * O.r.Trade.Strike) : O.r.Trade.Strike) ?? 0)).ToArray(); - value = Math.Abs((strikes[0] - strikes[1]) * structureItem.Key.Notional); - setTradeSpanValue(buyLeg.ts.Value, Math.Min(value, buyMargin)); - } - } - else if (client != null && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.对手方单向追保) - { - var sellLeg = structureItem.Value.Where(O => O.r.Trade.BuySell == "卖出").FirstOrDefault(); - var sellMargin = (sellLeg?.ts.Value.WorstCastClientPayable) ?? 0; - foreach (var item in structureItem.Value) - { - setTradeSpanValue(item.ts.Value, 0); - } - if (structureItem.Value.Sum(O => O.r.ValueResult.Pv) < 0) - { - var strikes = structureItem.Value.Select(O => ((O.r.Trade.IsMoneynessOption == "是" ? (O.r.Trade.SpotPrice * O.r.Trade.Strike) : O.r.Trade.Strike) ?? 0)).ToArray(); - value = Math.Abs((strikes[0] - strikes[1]) * structureItem.Key.Notional); - setTradeSpanValue(sellLeg.ts.Value, Math.Min(value, sellMargin)); - } - } - } - else if (structureItem.Key.StructureType.Contains("跨式") && structureItem.Value.Count == 2) - { - var minLeg = structureItem.Value[1]; - if (Math.Abs(structureItem.Value[0].r.ValueResult.Delta) < Math.Abs(structureItem.Value[1].r.ValueResult.Delta)) - { - minLeg = structureItem.Value[0]; - } - setTradeSpanValue(minLeg.ts.Value, minLeg.r.ValueResult.Pv); - } - else - { - if (client != null) - { - switch ((MarginOptionEnum)client.MarginOptionType) - { - case MarginOptionEnum.对手方单向追保: - if (direction.Count == 1) - { - value = double.MaxValue; - //最小值 - for (var i = 0; i < structureItem.Value.Count; i++) - { - if (value > structureItem.Value[i].ts.Value.WorstCastClientPayable) - { - index = i; - value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0; - } - setTradeSpanValue(structureItem.Value[i].ts.Value, 0); - structureIds.Add(structureItem.Value[i].ts.Key); - } - setTradeSpanValue(structureItem.Value[index].ts.Value, value); - } - break; - case MarginOptionEnum.单向追保: - case MarginOptionEnum.双向追保: - default: - if (direction.Count == 1) - { - value = double.MinValue; - //最大值 - for (var i = 0; i < structureItem.Value.Count; i++) - { - if (value < structureItem.Value[i].ts.Value.WorstCastClientPayable) - { - index = i; - value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0; - } - setTradeSpanValue(structureItem.Value[i].ts.Value, 0); - structureIds.Add(structureItem.Value[i].ts.Key); - } - setTradeSpanValue(structureItem.Value[index].ts.Value, value); - } - break; - } - } - else - { - if (direction.Count == 1) - { - value = double.MinValue; - //最大值 - for (var i = 0; i < structureItem.Value.Count; i++) - { - if (value < structureItem.Value[i].ts.Value.WorstCastClientPayable) - { - index = i; - value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0; - } - setTradeSpanValue(structureItem.Value[i].ts.Value, 0); - structureIds.Add(structureItem.Value[i].ts.Key); - } - setTradeSpanValue(structureItem.Value[index].ts.Value, value); - } - } - } - } - } - - var tList = (from r in tradeRiskResult.Results - join ts in resultMap - on r.Trade.id equals ts.Key - where !structureIds.Contains(r.Trade.id) - select new { r, ts }).ToList(); - - if (tList.Count > 0) - { - foreach (var item in tList) - { - double value = 0; - var client = GetClientInfo(item.r.Trade.ClientId); - if (client != null) - { - switch ((MarginOptionEnum)client.MarginOptionType) - { - case MarginOptionEnum.单向追保: - value = item.ts.Value.WorstCastClientPayable ?? 0; - value = Math.Max(value, 0); - break; - case MarginOptionEnum.对手方单向追保: - value = item.ts.Value.WorstCastClientPayable ?? 0; - value = Math.Max(value, 0); - break; - case MarginOptionEnum.双向追保: - default: - value = item.ts.Value.WorstCastClientPayable ?? 0; - break; - } - } - else - { - value = item.ts.Value.WorstCastClientPayable ?? 0; - } - item.ts.Value.Spv1 = value; - item.ts.Value.Spv2 = value; - item.ts.Value.Spv3 = value; - item.ts.Value.Spv4 = value; - item.ts.Value.SetWorstCastClientPayable(); - } - } - return resultMap.Values.ToList(); - } - - private trade_span generateTradeSpan(trade_span trade_Span, TradeRiskResultRecord record, RunMarginCalculationHelper helper, RunMarginCalculationReq req) - { - if (trade_Span == null) - { - trade_Span = helper.CreateTradeSpan(record.Trade); - } - - var client = GetClientInfo(record.Trade.ClientId); - double value; - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && record.Trade.TradeType == "收益互换") - { - var pnl = record.Trade.trade_swap.GetTradePrice.GetValueOrDefault() - record.Trade.trade_swap.PayTradePrice.GetValueOrDefault() - record.ValueResult.Pv; - helper.GetSpecialMargin(record.Trade, pnl, out value); - } - else if (record.Trade.TradeType == "远期" || record.Trade.TradeType == "收益互换") - { - var marginRate = helper.GetMarginParamProvider().GetMarginRate(record.Trade.UnderlyingCode) ?? 0; - var price = req.PriceProvider.GetPrice(record.Trade.UnderlyingCode); - value = price * marginRate * record.Trade.Notional + Math.Max((record.ValueResult.Pv - record.Trade.TradePrice ?? 0), 0); - } - else - { - var marginRate = helper.GetMarginParamProvider().GetMarginRate(record.Trade.UnderlyingCode) ?? 0; - var price = req.PriceProvider.GetPrice(record.Trade.UnderlyingCode); - var delta = Math.Abs(record.ValueResult.Delta); - if (record.ValueResult.Pv < 0) - { - delta = -delta; - } - if (HasTwoSideMargin(record.Trade.ClientId)) - { - value = record.ValueResult.Pv + delta * marginRate * price; - } - else if (!helper.GetSpecialMargin(record.Trade, 0, out value)) - { - double ratio; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - ratio = client?.Ratio1 ?? 1; - break; - case CalcMarginTypeEnum.None: - case CalcMarginTypeEnum.EodMargin: - default: - ratio = client?.Ratio ?? 1; - break; - } - value = record.ValueResult.Pv + ratio * delta * marginRate * price; - } - } - trade_Span.Spv1 = value; - trade_Span.Spv2 = value; - trade_Span.Spv3 = value; - trade_Span.Spv4 = value; - trade_Span.SetWorstCastClientPayable(); - return trade_Span; - } - - private void setTradeSpanValue(trade_span obj, double value) - { - obj.Spv1 = value; - obj.Spv2 = value; - obj.Spv3 = value; - obj.Spv4 = value; - obj.SetWorstCastClientPayable(); - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) - { - using (var db = new YLContext()) - { trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/HongYuanMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/HongYuanMarginCalculation.cs deleted file mode 100644 index 79349017..00000000 --- a/YLErpDAL/BLL/MarginCalculation/HongYuanMarginCalculation.cs +++ /dev/null @@ -1,500 +0,0 @@ -using Org.BouncyCastle.Ocsp; -using System.Collections.Generic; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.DBModels; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model; -using YLErp.Model.Enum; -using YLErp.Modules; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; -using static iTextSharp.text.pdf.AcroFields; - -namespace YLErp.BLL.MarginCalculation -{ - public class HongYuanMarginCalculation : MarginCalculationBase - { - //定义一个静态变量来保存类的实例(单例模式) - public static readonly HongYuanMarginCalculation Instance; - static HongYuanMarginCalculation() - { - Instance = new HongYuanMarginCalculation(); - } - - //定义私有构造函数,使外界不能创建该类实例 - private HongYuanMarginCalculation() - { - - } - - /// - /// 宏源定制算法 -- 远期和敲入的气囊 - /// - /// - /// - /// - private List CalculationSingleTrade(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(0); - } - - var resultMap = new Dictionary(); - var vols = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - - var normalProvider = new (string key, IPriceProvider priceProvider)[] { ("normal", helper.req.PriceProvider) }; - - foreach (var t in req.tradeList) - { - var clone = t.Clone(); - var vol = clone.TradeOpenVolatility ?? 0; - var client = helper.GetClient(clone); - var ProperClientClass = client?.ProperClientClass; - if (string.IsNullOrWhiteSpace(ProperClientClass)) - { - throw new Exception($"交易编号为{clone.TradeNumber}的客户适当性类型不存在,无法计算预付金!"); - } - if (ProperClientClass.Contains("普通投资者")) - { - vol *= 1.2; - } - vols[clone.id] = vol; - } - - var calcReq = helper.GetCalculateRisksForTradesReq(helper.req.PriceProvider, null, vols, QdpPricingRequest.PV_ONLY); - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate).Initialize(tradeRiskResult.Results.GroupBy(l => l.Trade.UnderlyingCode).Select(l => l.Key).ToHashSet(), MarginParamTypeEnum.MarginRate); - - foreach (var r in tradeRiskResult.Results) - { - if (!req.PriceProvider.TryGetPrice(r.Trade.UnderlyingCode, out var settlementPrice)) - { - settlementPrice = r.Trade.SpotPrice ?? 0; - } - mpProvider.TryGetMarginRate(r.Trade.UnderlyingCode, out var marginRate); - var positionNumber = r.Trade.Notional * marginRate; - var positionWinLoss = (double.IsNaN(r.ValueResult.Pv) ? 0.0 : r.ValueResult.Pv) + (r.Trade.TradePrice ?? 0.0 * r.Trade.Notional / r.Trade.OriginalNotional ?? 0) * (r.Trade.BuySell == "买入" ? -1 : 1); - var yqvalue = Math.Abs(settlementPrice * positionNumber + (double)positionWinLoss); - var yqtempTradeSpan = new trade_span - { - TradeId = r.Trade.id, - ClientId = r.Trade.ClientId, - ValueDate = req.settleDate, - UnderlyingId = r.Trade.UnderlyingId, - UnderlyingCode = r.Trade.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - Spv1 = yqvalue, - Spv2 = yqvalue, - Spv3 = yqvalue, - Spv4 = yqvalue, - IsSingleMargin = true, - WorstCastClientPayable = yqvalue - }; - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - var client = helper.GetClient(r.Trade); - if (client != null && client.Ratio1 != null) - { - yqtempTradeSpan.WorstCastClientPayable = yqtempTradeSpan.WorstCastClientPayable * client.Ratio1; - } - } - resultMap[r.Trade.id] = yqtempTradeSpan; - } - return resultMap.Values.ToList(); - } - - /// - /// span算法 - /// - /// - /// - private List SpanRunMarginCalculation(RunMarginCalculationReq req) - { - using (var db = new YLContext()) - { - var tradeIds = req.tradeList.Select(x => x.id); - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - tradeIds = new List { req.realTradeId }; - } - var tradeMarginTemplates = db.trade_margin_template.Where(x => tradeIds.Contains(x.TradeId)).ToList(); - var tradeMarginTemplateIds = tradeMarginTemplates.Select(x => x.MarginTemplateId).ToArray(); - var marginTemplates = db.margin_template_v2.Where(x => tradeMarginTemplateIds.Contains(x.id)).ToList(); - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - helper.GetTradVolRateDic(out var tradeVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.Item1, - priceProvider = n.Item2, - addVolRateDic = m - })).ToArray(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - var pv = item.ValueResult.Pv; - var isSpecial = true; - var client = helper.GetClient(item.Trade); - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - isSpecial = false; - value = double.IsNaN(pv) ? 0 : pv; - } - - if (!isSpecial) - { - if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin || ("雪球期权".Equals(item.Trade.TradeType) && "买入".Equals(item.Trade.BuySell))) - { - if (!("雪球期权".Equals(item.Trade.TradeType) && "卖出".Equals(item.Trade.BuySell))) - { - var clientRatio = client?.Ratio ?? 1.0; - value = value * clientRatio; - } - } - } - - if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && "雪球期权".Equals(item.Trade.TradeType) && "卖出".Equals(item.Trade.BuySell)) - { - if (item.Trade.InitialMargin != null && value < item.Trade.InitialMargin) - { - value = item.Trade.InitialMargin.Value; - } - } - - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && !"雪球期权".Equals(item.Trade.TradeType) && !"收益互换".Equals(item.Trade.TradeType)) - { - value = value * (client?.Ratio1 ?? 1.0); - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - - //设置了特殊的规则 - var tradeMarginTemplate = tradeMarginTemplates.Where(x => x.TradeId == item.Trade.id && x.ValueDate <= req.settleDate).OrderByDescending(x => x.ValueDate).FirstOrDefault(); - if (tradeMarginTemplate != null) - { - var marginTemplate = marginTemplates.FirstOrDefault(x => x.id == tradeMarginTemplate.MarginTemplateId); - if (marginTemplate == null) - { - throw new Exception(string.Format("{0}未找到配置的预付金模板", item.Trade.TradeNumber)); - } - if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.单独计算规则) - { - tempTradeSpan.IsSingleMargin = true; - } - - } - } - } - } - return resultMap.Values.ToList(); - } - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(0); - } - //结果集 - var resultMap = new List(); - - if ((req.CalcMarginType != CalcMarginTypeEnum.EodMargin && req.CalcMarginType != CalcMarginTypeEnum.InitialMargin)) - { - //价格列表不是空的说明是计算实时预付金或期初预付金 - //宏源在计算实时预付金的时候使用前一天的结算价这个逻辑是一开始确认的,后续对数据的时候要再次确认 --时嬴政 - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - req.PriceProvider = new EodPriceProvider(lastDate).GetPriceProvider(SettlementTypeEnum.SettlePrice); - req.CalcMarginType = CalcMarginTypeEnum.EodMargin; - } - - var list1 = req.tradeList.Where(x => x.TradeType == "远期" || (x.TradeType == "气囊结构" && x.trade_airbag.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)).ToList(); - resultMap.AddRange(CalculationSingleTrade(req.Clone(list1))); - - var list2 = req.tradeList.Where(x => x.TradeType != "远期" && !(x.TradeType == "气囊结构" && x.trade_airbag.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)).ToList(); - resultMap.AddRange(SpanRunMarginCalculation(req.Clone(list2))); - - return resultMap; - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - using (var db = new YLContext()) - { - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var teamA = db.assetunit.Where(x => x.UserGroup == "A").Select(x => x.id).ToArray(); - - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var clientids = tradeList.Select(x => x.ClientId).Distinct().ToArray(); - - foreach (var clientid in clientids) - { - var client = DataCacheProvider.GetClientDataSource().GetData(clientid); - - if (client == null) - { - throw new Exception(string.Format("该交易{0},客户不存在", tradeList.Where(x => x.ClientId == clientid).FirstOrDefault().TradeNumber)); - } - - //A团队 - var tradeListA = tradeList.Where(x => teamA.Contains(x.AssetId) && x.ClientId == clientid).ToList(); - var clientSpanA = GetUnderlyingGroup(client, req, tradeListA); - - //B团队 - var tradeListB = tradeList.Where(x => !teamA.Contains(x.AssetId) && x.ClientId == clientid).ToList(); - var clientSpanB = GetUnderlyingGroup(client, req, tradeListB); - - UserGroupPVJson userGroupPVJson = new UserGroupPVJson(); - userGroupPVJson.ValueA = clientSpanA.WorstCastClientPayable ?? 0; - userGroupPVJson.ValueB = clientSpanB.WorstCastClientPayable ?? 0; - - var clientSpan = new ClientSpan - { - ClientId = clientid, - ValueDate = req.settleDate, - Spv1 = clientSpanA.Spv1 + clientSpanB.Spv1, - Spv2 = clientSpanA.Spv2 + clientSpanB.Spv2, - Spv3 = clientSpanA.Spv3 + clientSpanB.Spv3, - Spv4 = clientSpanA.Spv4 + clientSpanB.Spv4, - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = clientSpanA.WorstCastClientPayable + clientSpanB.WorstCastClientPayable, - SwapWorstCastClientPayable = clientSpanA.SwapWorstCastClientPayable + clientSpanB.SwapWorstCastClientPayable, - MySideMargin = clientSpanA.MySideMargin + clientSpanB.MySideMargin, - TwoSideMargin = clientSpanA.TwoSideMargin + clientSpanB.TwoSideMargin, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - PVJsons = JsonHelper.ToJson(userGroupPVJson), - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(clientid, out var dd) ? dd : 0 - }; - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}={req.SpanType}"); - } - - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - //MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - db.client_span.AddRange(clientSpanNews); - } - - db.SaveChanges(); - - return req.tradeSpans; - } - } - - public ClientSpan GetUnderlyingGroup(Client client, CalcClientMarginReq req, List tradeList) - { - using (var db = new YLContext()) - { - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - var tradeIdList = tradeSpanInfo.Where(x => x.tradeSpan.IsSingleMargin != true).Select(x => x.tradeSpan.TradeId); - - var underlyingGroup = tradeSpanInfo.Where(x => x.tradeSpan.IsSingleMargin != true).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = client.id, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - SwapWorstCastClientPayable = t.Where(g => g.trade.TradeType == "收益互换").Sum(g => g.tradeSpan.WorstCastClientPayable) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - - }).ToList(); - - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == client.id && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == client.id && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - - #endregion - } - - var clientSpan = new ClientSpan - { - ClientId = client.id, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - SwapWorstCastClientPayable = underlyingGroup.Sum(g => g.SwapWorstCastClientPayable), - MySideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null - && req.clientAdditionalMarginDic.TryGetValue(client.id, out var dd) ? dd : 0 - }; - - var tradeSpanSingle = tradeSpanInfo.Where(x => x.tradeSpan.IsSingleMargin == true); - clientSpan.Spv1 += tradeSpanSingle.Sum(x => -(x.tradeSpan.Spv1 ?? 0)); - clientSpan.Spv2 += tradeSpanSingle.Sum(x => -(x.tradeSpan.Spv2 ?? 0)); - clientSpan.Spv3 += tradeSpanSingle.Sum(x => -(x.tradeSpan.Spv3 ?? 0)); - clientSpan.Spv4 += tradeSpanSingle.Sum(x => -(x.tradeSpan.Spv4 ?? 0)); - clientSpan.WorstCastClientPayable += tradeSpanSingle.Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - clientSpan.SwapWorstCastClientPayable += tradeSpanSingle.Where(g => g.trade.TradeType == "收益互换").Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - clientSpan.MySideMargin += tradeSpanSingle.Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - clientSpan.TwoSideMargin += tradeSpanSingle.Sum(x => -(x.tradeSpan.WorstCastClientPayable ?? 0)); - - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable.Value, 0); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保) - { - clientSpan.WorstCastClientPayable = Math.Max(clientSpan.WorstCastClientPayable.Value, 0); - } - - db.SaveChanges(); - - return clientSpan; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) - { - using (var db = new YLContext()) - { trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/HuaAnMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/HuaAnMarginCalculation.cs deleted file mode 100644 index e962620e..00000000 --- a/YLErpDAL/BLL/MarginCalculation/HuaAnMarginCalculation.cs +++ /dev/null @@ -1,749 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.BLL.Eod; -using YLErp.Helpers; -using YLErp.Modules; -using YLErp.Modules.DataProviderModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class HuaAnMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly HuaAnMarginCalculation Instance; - - static HuaAnMarginCalculation() - { - Instance = new HuaAnMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private HuaAnMarginCalculation() - { - - } - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var resultList = new List(); - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin) - { - resultList = calcInitialMargin(req); - } - else - { - resultList = calcPositionMargin(req); - } - - return resultList; - } - - private List calcPositionMargin(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - req.PriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.SettlePrice); - var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - _helper.GetUpDownLimitPrices(out var upPrices, out var downPrices); - _helper.GetUpDownVolRateDic(out var upVolRateDic, out _); - - var ForwordOrSwapList = req.tradeList.Where(O => !resultMap.Keys.Contains(O.id) && O.TradeType != "收益互换" && O.TradeType != "远期"); - var ForwordOrSwapcalcReq = - _helper.GetCalculateRisksForTradesReq( - req.PriceProvider, - null, - null, - Qdp.Pricing.Base.Implementations.PricingRequest.Pv); - ForwordOrSwapcalcReq.tradeList = req.tradeList.Where(O => O.TradeType == "远期" || O.TradeType == "收益互换"); - var ForwordOrSwapRusult = CalculatorHelper.CalculateRisksForTrades(ForwordOrSwapcalcReq); - foreach (var f in ForwordOrSwapRusult.Results.Where(l => l.Trade.TradeType == "远期" || l.Trade.TradeType == "收益互换")) - { - double? marginRate2 = 0; - if (!string.IsNullOrEmpty(f.Trade.BasisUnderlyingCode) && f.Trade.TradeType == "远期") - { - marginRate2 = GetUnderlyingCodeMarginRate(f.Trade.BasisUnderlyingCode); - } - double? marginRate1 = GetUnderlyingCodeMarginRate(f.Trade.UnderlyingCode); - var positionPnl = EodOperationBase.GetPositionPnl(f.ValueResult.Pv, f.Trade.TradePrice ?? 0.0, f.Trade.Notional, f.Trade.OriginalNotional ?? 0, f.Trade.BuySell); - var marginRate = ((marginRate1 > marginRate2 ? marginRate1 : marginRate2) ?? 0); - var margin = (f.Trade.TradeType == "远期" ? f.Trade.SpotPrice : req.PriceProvider.GetPrice(f.Trade.UnderlyingCode)) * f.Trade.Notional * marginRate + positionPnl; - var sp = _helper.CreateTradeSpan(f.Trade).SetAllSpvAndWorst(Math.Max((margin ?? 0), 0)); - sp.SetWorstCastClientPayable(); - resultMap[sp.TradeId] = sp; - } - var allList = req.tradeList.Where(O => !resultMap.Keys.Contains(O.id) && O.TradeType != "收益互换" && O.TradeType != "远期"); - var calcReq = - _helper.GetCalculateRisksForTradesReq( - req.PriceProvider, - null, - null, - Qdp.Pricing.Base.Implementations.PricingRequest.Delta); - calcReq.tradeList = allList; - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - var sellList = tradeRiskResult.Results.Where(O => O.Trade.ParentTradeId == 0 && O.Trade.IsGroup == 0 && (O.Trade.TradeType.Contains("香草") || O.Trade.TradeType.Contains("亚式")) && O.Trade.BuySell == "卖出"); - foreach (var item in sellList) - { - var sp = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(0); - sp.SetWorstCastClientPayable(); - resultMap[sp.TradeId] = sp; - } - //1、交易员角度买入香草和亚式期权 - //先按标的分类,在标的i下 - //Span算法:先算出品种i下每笔交易的span算法预付金,然后合计 - //Delta算法:先算出每一笔交易的delta算法预付金 = max(期权的总的delta* 收盘价*交易所预付金比例,0),然后合计算出该品种的delta算法预付金 - //品种i的预付金 = max(span算法预付金,Delta算法预付金) - //香草和亚式的总的预付金 - var VanillaOrAsianList = tradeRiskResult.Results.Where(O => !resultMap.Keys.Contains(O.Trade.id) && (O.Trade.ParentTradeId == 0 || O.Trade.IsGroup == 2) && (O.Trade.TradeType.Contains("香草") || O.Trade.TradeType.Contains("亚式")) && O.Trade.BuySell == "买入"); - - foreach (var i in VanillaOrAsianList) - { - var deltaMargin = i.ValueResult.Delta * i.Trade.SpotPrice * GetUnderlyingCodeMarginRate(i.Trade.UnderlyingCode); - var sp = marginCalculation(req, new List { i.Trade }).First(); - var spanMargin = sp.WorstCastClientPayable; - deltaMargin = deltaMargin > 0 ? deltaMargin : 0; - var margin = Math.Max((deltaMargin ?? 0), (spanMargin ?? 0)); - sp.DeltaMargin = deltaMargin; - sp.WorstCastClientPayable = margin; - resultMap[sp.TradeId] = sp; - } - - - //买入宽跨式(跨式)期权组合 - var StraddleTradeIds = req.tradeList.Where(O => (O.StructureType ?? O.TradeType).Contains("跨式")).Select(O => O.id); - var StraddleResultDict = tradeRiskResult.Results.Where(O => StraddleTradeIds.Contains(O.Trade.id)).GroupBy(O => O.Trade.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList()); - foreach (var straddle in StraddleResultDict) - { - //获取多个腿的 deltaInitialMargin - var deltaInitialMargin = straddle.Value.Where(l => l.Trade.BuySell == "买入").ToDictionary(k => k.Trade.id, O => O.ValueResult.Delta * req.PriceProvider.GetPrice(O.Trade.UnderlyingCode) * GetUnderlyingCodeMarginRate(O.ValueResult.UnderlyingCode)); - //获取多个腿的 spanInitialMargin - var spanInitialMargin = marginCalculation(req, straddle.Value.Where(l => l.Trade.BuySell == "买入").Select(l => l.Trade).ToList()).ToDictionary(k => k.TradeId, v => v.WorstCastClientPayable); - double margin = 0; - int selfLegTradeId = 0; - deltaInitialMargin.ToList().Union(spanInitialMargin.ToList()).ToList().ForEach(x => - { - if (margin < x.Value) - { - margin = x.Value ?? 0; - selfLegTradeId = x.Key; - } - }); - //另外一条腿的权利金总额 - var straddleCalcReq = _helper.GetCalculateRisksForTradesReq( - req.PriceProvider, - null, - null, - Qdp.Pricing.Base.Implementations.PricingRequest.Pv); - straddleCalcReq.tradeList = new List { straddle.Value.Where(l => l.Trade.id != selfLegTradeId).Select(l => l.Trade).FirstOrDefault() }; - var straddleRusult = CalculatorHelper.CalculateRisksForTrades(straddleCalcReq); - var t = straddleRusult.Results.FirstOrDefault().Trade; - double? otherLegAmount = t.BuySell == "买入" ? Math.Abs(t.TradePrice ?? 0) : 0; - var partialNotionalRate = t.Notional / t.OriginalNotional; - for (int i = 0; i < straddle.Value.Count; i++) - { - if (straddle.Value[i].Trade.id == selfLegTradeId) - { - var sp = _helper.CreateTradeSpan(straddle.Value[i].Trade).SetAllSpvAndWorst(margin); - sp.SetWorstCastClientPayable(); - resultMap[straddle.Value[i].Trade.id] = sp; - } - else - { - var sp = _helper.CreateTradeSpan(straddle.Value[i].Trade).SetAllSpvAndWorst((otherLegAmount ?? 0) * (partialNotionalRate ?? 0)); - sp.SetWorstCastClientPayable(); - resultMap[straddle.Value[i].Trade.id] = sp; - } - } - } - //其它奇异期权 持仓预付金:用span算 - var ExoticOptionsList = req.tradeList.Where(O => !resultMap.Keys.Contains(O.id) && O.TradeType != "收益互换" && (O.ParentTradeId == 0 || O.IsGroup == 2) && !O.TradeType.Contains("香草") && !O.TradeType.Contains("亚式")); - - //牛市价差、熊市价差期权 - var NiuxiongTradeIds = req.tradeList.Where(O => ((O.StructureType ?? O.TradeType).Contains("牛市") || (O.StructureType ?? O.TradeType).Contains("熊市"))).Select(O => O.id); - var NiuxiongResultDict = tradeRiskResult.Results.Where(O => NiuxiongTradeIds.Contains(O.Trade.id)).GroupBy(O => O.Trade.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList()); - foreach (var buyNiuxiong in NiuxiongResultDict) - { - var margin = buyNiuxiong.Value.Max(O => Math.Max(Math.Abs(O.ValueResult.Delta) / O.Trade.Notional, 0.5) * req.PriceProvider.GetPrice(O.Trade.UnderlyingCode) * O.Trade.Notional * GetUnderlyingCodeMarginRate(O.Underlyings.Select(l => l.UnderlyingCode).FirstOrDefault())) * 0.5; - for (int i = 0; i < buyNiuxiong.Value.Count; i++) - { - if (buyNiuxiong.Value[i].Trade.BuySell == "买入") - { - var sp = _helper.CreateTradeSpan(buyNiuxiong.Value[i].Trade).SetAllSpvAndWorst(margin ?? 0); - sp.SetWorstCastClientPayable(); - resultMap[buyNiuxiong.Value[i].Trade.id] = sp; - } - else - { - var sp = _helper.CreateTradeSpan(buyNiuxiong.Value[i].Trade).SetAllSpvAndWorst(0); - sp.SetWorstCastClientPayable(); - resultMap[buyNiuxiong.Value[i].Trade.id] = sp; - } - } - } - //除了宽跨式(跨式)期权、牛熊市价差期权以外的其他组合期权 - var OtherTradeList = req.tradeList.Where(O => (O.ParentTradeId > 0 && O.IsGroup == 0) && !(O.StructureType ?? O.TradeType).Contains("牛市") && !(O.StructureType ?? O.TradeType).Contains("熊市") && !(O.StructureType ?? O.TradeType).Contains("跨式")).ToList(); - - var tradeList = ExoticOptionsList.Union(OtherTradeList).ToList(); - if (tradeList.Count > 0) - { - var resultspan = marginCalculation(req, tradeList); - foreach (var i in resultspan) - { - if (resultMap.ContainsKey(i.TradeId)) - { - resultMap[i.TradeId] = i; - } - else - { - resultMap.Add(i.TradeId, i); - } - } - } - return resultMap.Values.ToList(); - } - - /// - /// 获取标的现价 - /// - /// - /// - /// - /// - public static double GetUnderlyingPrice(RunMarginCalculationReq req, string underlyingCode, DateTime tradeDate, SettlementTypeEnum typeEnum = SettlementTypeEnum.SettlePrice) - { - double price = 0; - - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); - if (udm != null) - { - var priceProvider = new EodPriceProvider(tradeDate).GetPriceProvider(typeEnum); - price = priceProvider.GetPrice(underlyingCode); - } - - return price; - } - public List calcInitialMargin(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var tradeSpanList = new List(); - var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - _helper.GetUpDownLimitPrices(out var upPrices, out var downPrices); - _helper.GetUpDownVolRateDic(out var upVolRateDic, out _); - - //收益互换交易单独计算trade_span - var swap = req.tradeList.Where(O => O.TradeType == "收益互换"); - tradeBLL.SetFieldsByTradeType(swap); - foreach (var item in swap) - { - var margin = 0d; - var un = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode); - if (un != null) - { - margin = (double)(item.StockEqvNotional * (item.trade_swap?.GetMarginRate ?? 0)); - } - var sp = _helper.CreateTradeSpan(item).SetAllSpvAndWorst(margin); - sp.SetWorstCastClientPayable(); - resultMap[sp.TradeId] = sp; - } - //远期计算span - if (req.tradeList.Any(t => t.TradeType == "远期")) - { - var forwardTradeList = req.tradeList.Where(t => t.TradeType == "远期").ToList(); - foreach (var t in forwardTradeList) - { - double? marginRate2 = 0; - if (!string.IsNullOrEmpty(t.BasisUnderlyingCode)) - { - marginRate2 = GetUnderlyingCodeMarginRate(t.BasisUnderlyingCode); - } - double? marginRate1 = GetUnderlyingCodeMarginRate(t.UnderlyingCode); - var margin = t.OriginalNotional * (t.SpotPrice ?? 0) * (marginRate1 > marginRate2 ? marginRate1 : marginRate2); - var sp = _helper.CreateTradeSpan(t).SetAllSpvAndWorst(margin ?? 0); - sp.SetWorstCastClientPayable(); - resultMap[sp.TradeId] = sp; - } - } - - - var allList = req.tradeList.Where(O => !resultMap.Keys.Contains(O.id) && O.TradeType != "收益互换" && O.TradeType != "远期"); - var calcReq = - _helper.GetCalculateRisksForTradesReq( - req.PriceProvider, - null, - null, - Qdp.Pricing.Base.Implementations.PricingRequest.Delta); - calcReq.tradeList = allList; - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - var sellList = tradeRiskResult.Results.Where(O => (O.Trade.CalcId == null || (O.Trade.CalcId != null && !O.Trade.CalcId.Contains("-"))) && O.Trade.IsGroup == 0 && (O.Trade.TradeType.Contains("香草") || O.Trade.TradeType.Contains("亚式")) && O.Trade.BuySell == "卖出"); - foreach (var item in sellList) - { - var sp = _helper.CreateTradeSpan(item.Trade).SetAllSpvAndWorst(0); - sp.SetWorstCastClientPayable(); - resultMap[sp.TradeId] = sp; - } - - //1、买入香草和亚式期权 初始预付金:基于delta算法,max(期权的总Delta *期初价格*交易所预付金比例,0) - var VanillaOrAsianList = tradeRiskResult.Results.Where(O => (O.Trade.CalcId == null || (O.Trade.CalcId != null && !O.Trade.CalcId.Contains("-"))) && !resultMap.Keys.Contains(O.Trade.id) && (O.Trade.TradeType.Contains("香草") || O.Trade.TradeType.Contains("亚式")) && O.Trade.BuySell == "买入"); - foreach (var item in VanillaOrAsianList) - { - var deltaMargin = item.ValueResult.Delta * item.Trade.SpotPrice * GetUnderlyingCodeMarginRate(item.Trade.UnderlyingCode); - var sp = marginCalculation(req, new List { item.Trade }).First(); - var spanMargin = sp.WorstCastClientPayable; - deltaMargin = deltaMargin > 0 ? deltaMargin : 0; - var margin = Math.Max((deltaMargin ?? 0), (spanMargin ?? 0)); - sp.DeltaMargin = deltaMargin; - sp.WorstCastClientPayable = margin; - resultMap[sp.TradeId] = sp; - } - - - //买入宽跨式(跨式)期权组合 - var StraddleTradeIds = req.tradeList.Where(O => (O.StructureType ?? O.TradeType).Contains("跨式")).Select(O => O.id); - var StraddleResultDict = tradeRiskResult.Results.Where(O => StraddleTradeIds.Contains(O.Trade.id)).GroupBy(O => O.Trade.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList()); - foreach (var item in StraddleResultDict) - { - //获取多个腿的 deltaInitialMargin - var deltaInitialMargin = item.Value.Where(l => l.Trade.BuySell == "买入").ToDictionary(k => k.Trade.id, O => O.ValueResult.Delta * O.ValueResult.SpotPrice * GetUnderlyingCodeMarginRate(O.ValueResult.UnderlyingCode)); - //获取多个腿的 spanInitialMargin - var spanInitialMargin = marginCalculation(req, item.Value.Where(l => l.Trade.BuySell == "买入").Select(l => l.Trade).ToList()).ToDictionary(k => k.TradeId, v => v.WorstCastClientPayable); - double margin = 0; - int selfLegTradeId = 0; - deltaInitialMargin.ToList().Union(spanInitialMargin.ToList()).ToList().ForEach(x => - { - if (margin < x.Value) - { - margin = x.Value ?? 0; - selfLegTradeId = x.Key; - - } - }); - if (item.Value.Where(l => l.Trade.id != selfLegTradeId).Select(l => l.Trade).FirstOrDefault() != null) - { - var straddleCalcReq = _helper.GetCalculateRisksForTradesReq( - req.PriceProvider, - null, - null, - Qdp.Pricing.Base.Implementations.PricingRequest.Pv); - straddleCalcReq.tradeList = new List { item.Value.Where(l => l.Trade.id != selfLegTradeId).Select(l => l.Trade).FirstOrDefault() }; - var straddleRusult = CalculatorHelper.CalculateRisksForTrades(straddleCalcReq); - var t = straddleRusult.Results.FirstOrDefault().Trade; - double? otherLegAmount = t.BuySell == "买入" ? Math.Abs(t.TradePrice ?? 0) : 0; - for (int i = 0; i < item.Value.Count; i++) - { - if (item.Value[i].Trade.id == selfLegTradeId) - { - var sp = _helper.CreateTradeSpan(item.Value[i].Trade).SetAllSpvAndWorst(margin); - sp.SetWorstCastClientPayable(); - resultMap[item.Value[i].Trade.id] = sp; - } - else - { - var sp = _helper.CreateTradeSpan(item.Value[i].Trade).SetAllSpvAndWorst((otherLegAmount ?? 0)); - sp.SetWorstCastClientPayable(); - resultMap[item.Value[i].Trade.id] = sp; - } - } - } - else - { - for (int i = 0; i < item.Value.Count; i++) - { - if (item.Value[i].Trade.id == selfLegTradeId) - { - var sp = _helper.CreateTradeSpan(item.Value[i].Trade).SetAllSpvAndWorst(margin); - sp.SetWorstCastClientPayable(); - resultMap[item.Value[i].Trade.id] = sp; - } - } - } - } - //其它奇异期权 初始预付金:用span算 - var ExoticOptionsList = req.tradeList.Where(O => !(O.CalcId ?? "").Contains("-") && !resultMap.Keys.Contains(O.id) && O.TradeType != "收益互换" && O.TradeType != "远期" && !O.TradeType.Contains("香草") && !O.TradeType.Contains("亚式") && O.BuySell == "买入"); - - //牛市价差、熊市价差期权 - var NiuxiongTradeIds = req.tradeList.Where(O => ((O.StructureType ?? O.TradeType).Contains("牛市") || (O.StructureType ?? O.TradeType).Contains("熊市"))).Select(l => l.id); - var NiuxiongResultDict = tradeRiskResult.Results.Where(O => NiuxiongTradeIds.Contains(O.Trade.id)).GroupBy(O => O.Trade.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList()); - foreach (var buyNiuxiong in NiuxiongResultDict) - { - var margin = buyNiuxiong.Value.Max(O => Math.Max((Math.Abs(O.ValueResult.Delta) / O.Trade.OriginalNotional ?? 0), 0.5) * O.Trade.SpotPrice * O.Trade.OriginalNotional * GetUnderlyingCodeMarginRate(O.Trade.UnderlyingCode)) * 0.5; - for (int i = 0; i < buyNiuxiong.Value.Count; i++) - { - if (buyNiuxiong.Value[i].Trade.BuySell == "买入") - { - var sp = _helper.CreateTradeSpan(buyNiuxiong.Value[i].Trade).SetAllSpvAndWorst(margin ?? 0); - sp.SetWorstCastClientPayable(); - resultMap[buyNiuxiong.Value[i].Trade.id] = sp; - } - else - { - var sp = _helper.CreateTradeSpan(buyNiuxiong.Value[i].Trade).SetAllSpvAndWorst(0); - sp.SetWorstCastClientPayable(); - resultMap[buyNiuxiong.Value[i].Trade.id] = sp; - } - } - } - //除了宽跨式(跨式)期权、牛熊市价差期权以外的其他组合期权 - var OtherTradeList = req.tradeList.Where(O => (O.CalcId ?? "").Contains("-") && !(O.StructureType ?? O.TradeType).Contains("牛市") && !(O.StructureType ?? O.TradeType).Contains("熊市") && !(O.StructureType ?? O.TradeType).Contains("跨式")); - - var tradeList = ExoticOptionsList.Union(OtherTradeList).ToList(); - if (tradeList.Count > 0) - { - var resultspan = marginCalculation(req, tradeList); - foreach (var i in resultspan) - { - if (resultMap.ContainsKey(i.TradeId)) - { - resultMap[i.TradeId] = i; - } - else - { - resultMap.Add(i.TradeId, i); - } - } - } - - return resultMap.Values.ToList(); - } - - /// - /// 获取预付金比率 - /// - /// - /// - public double? GetUnderlyingCodeMarginRate(string UnderlyingCode) - { - double? MarginRate = 0; - var un = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCode); - if (un != null) - { - MarginRate = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCode).MarginRate ?? DataCacheProvider.GetVarietyDataSource().GetData(UnderlyingCode).Margin; - } - - return MarginRate; - } - public List marginCalculation(RunMarginCalculationReq req, List trades) - { - var thisReq = req.Clone(); - var helper = new RunMarginCalculationHelper(thisReq, _underlyingDataProvider); - var resultMap = new Dictionary(); - if (trades != null && trades.Any()) - { - //处理香草,亚式,跨式 - thisReq.tradeList = trades; - } - helper.SetFieldsByTradeType(); - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - helper.GetTradVolRateDic(out var tradeVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string key, IPriceProvider priceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", thisReq.PriceProvider) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.key, - priceProvider = n.priceProvider, - addVolRateDic = m - })).ToArray(); - var uProvider = new UnderlyingDataProvider(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null, pricingRequest: QdpPricingRequest.BASIC_PRICING); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - if (key == "normal_1") continue; - - foreach (var item in tradeRiskResult.Results) - { - if ((item.Trade.TradeType == "远期" || item.Trade.TradeType == "收益互换")) - { - continue; - } - var pv = item.ValueResult.Pv; - if (!helper.GetSpecialMargin(item.Trade, pv, out var value, helper.req.forOtherSide)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "normal_0": - if (!(item.Trade.StructureType ?? item.Trade.TradeType).Contains("跨式")) - { - - var um = uProvider.GetUnderlying(item.Trade.UnderlyingCode); - var variety = uProvider.GetVariety(item.Trade.UnderlyingCode); - var marginRate = ((um?.MarginRate ?? 0) > 0 ? um.MarginRate : variety?.Margin) ?? 0; - double deltaCash = 0; - if ((item.Trade.BuySell == "买入" && item.Trade.OptionType == "看涨") || (item.Trade.BuySell == "卖出" && item.Trade.OptionType == "看跌")) - { - deltaCash = Math.Abs(item.ValueResult.DeltaCash); - } - else - { - deltaCash = -Math.Abs(item.ValueResult.DeltaCash); - } - value = deltaCash * marginRate; - tempTradeSpan.DeltaMargin = value; - tempTradeSpan.PositionWinLoss = EodOperationBase.GetPositionPnl(item.ValueResult.Pv, item.Trade.TradePrice ?? 0.0, item.Trade.Notional, item.Trade.OriginalNotional ?? 0, item.Trade.BuySell); - } - break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - - if (tempTradeSpan.WorstCastClientPayable > 0) - { - tempTradeSpan.WorstCastClientPayable = Math.Max(tempTradeSpan.WorstCastClientPayable.Value, Math.Abs(tempTradeSpan.DeltaMargin ?? 0) + (tempTradeSpan.PositionWinLoss ?? 0)); - } - else - { - tempTradeSpan.WorstCastClientPayable = 0; - } - } - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - //获取收盘日那天对应的预付金模板 - var tradeTemplates = db.trade_margin_template.AsNoTracking().Where(t => tradeIds.Contains(t.TradeId) && t.ValueDate <= req.settleDate); - var groupQuery = from tt in tradeTemplates - group tt by tt.TradeId into tts - select new - { - TradeId = tts.Key, - ValueDate = tts.Max(n => n.ValueDate) - }; - var groupTemplates = from gq in groupQuery - join tt in tradeTemplates - on new { gq.TradeId, gq.ValueDate } equals new { tt.TradeId, tt.ValueDate } - select tt; - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, tradetemplate }).ToList(); - - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var spans = req.tradeSpansOtherSide != null - ? req.tradeSpansOtherSide.Where(n => n != null).ToArray() : Enumerable.Empty(); - var tradeSpanInfoOtherSide = (from tradeSpan in spans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var underlyingGroup = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1), - PositionWinLoss = t.Sum(g => g.tradeSpan.PositionWinLoss) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - foreach (var item in underlyingGroup) - { - var tradeSpanIds = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).Select(x => x.tradeSpan.id); - var tradeSpansUpdate = db.trade_span.Where(x => tradeSpanIds.Contains(x.id) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeSpanIds.Contains(x.id) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - var minSpv = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - if (minSpv < 0) - { - item.WorstCastClientPayable = Math.Max(Math.Abs(minSpv), Math.Abs(item.DeltaMargin ?? 0) - (item.PositionWinLoss ?? 0)) * (-1); - item.TwoSideMargin = item.WorstCastClientPayable; - - if (Math.Abs(minSpv) > Math.Abs(item.DeltaMargin ?? 0) - (item.PositionWinLoss ?? 0)) - { - //更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - } - } - else - { - item.WorstCastClientPayable = 0; - item.TwoSideMargin = 0; - - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - DeltaMargin = underlyingGroup.Sum(g => g.DeltaMargin), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - MySideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.DeltaMargin += singleMarginTrade.Sum(O => O.DeltaMargin * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - - //交易员不支付预付金 - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/MaoChuanMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/MaoChuanMarginCalculation.cs deleted file mode 100644 index db41b674..00000000 --- a/YLErpDAL/BLL/MarginCalculation/MaoChuanMarginCalculation.cs +++ /dev/null @@ -1,318 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Modules.MarginModule; -using YLErp.Modules.VolatilityModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class MaoChuanMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例(单例模式) - public static readonly MaoChuanMarginCalculation Instance; - - static MaoChuanMarginCalculation() - { - Instance = new MaoChuanMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private MaoChuanMarginCalculation() - { - - } - - /// - /// 计算香草期权和亚式期权预付金 - /// - private List CalculationNormalOptionMargin(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - - var codes = req.tradeList.Select(O => O.UnderlyingCode).ToHashSet(); - var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate) - .Initialize(codes, MarginParamTypeEnum.MarginRate); - //客户要求用AskVol计算预付金,所以先把所有交易方向改为卖出并把VolType赋值为 BidAskVol; - //Dictionary buySellDict = tradeList.ToDictionary(K => K.id, V => V.BuySell); - //tradeList.ForEach(t => t.BuySell = "卖出"); - var vols = new Dictionary(); - foreach (var t in req.tradeList) - { - var vType = t.VolType; - t.VolType = "报价Ask"; - var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); - if (um == null) - { - throw new MarginCalcException($"[预付金计算]找不到标的数据(交易编号:{t.TradeNumber},标的代码:{t.UnderlyingCode})"); - } - var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, isEodCalc: req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - vols[t.id] = vol; - t.VolType = vType; - } - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: req.tradeList, - calcScenario: CalcScenarioEnum.EodSettlement, - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: null, - overrideVolsForTrade: vols, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - //tradeList.ForEach(t => t.BuySell = buySellDict[t.id]); - - foreach (var r in tradeRiskResult.Results) - { - if (!mpProvider.TryGetMarginRate(r.Trade.UnderlyingCode, out var marginRate)) - { - throw new MarginCalcException($"{r.Trade.UnderlyingCode} 预付金比率不存在"); - } - - var trade = req.tradeList.FirstOrDefault(t => t.id == r.Trade.id); - - if (!req.PriceProvider.TryGetPrice(r.Trade.UnderlyingCode, out var price)) - { - price = r.Trade.SpotPrice ?? 0; - } - - logger.Info($"茂川标准预付金计算:[{r.Trade.TradeType}_{r.Trade.BuySell}_{r.Trade.OptionType}_{r.Trade.Strike}] => Vol:{r.ValueResult.Vol};Delta:{r.ValueResult.Delta}"); - //预付金= Delta*标的期货预付金比率*标的期货价格*持仓规模 (qdp计算出的Delta已经乘过数量了,所以这里不用再乘了); - var value = Math.Abs(r.ValueResult.Delta) * marginRate * price;// * r.Trade.Notional; - if (r.Trade.BuySell == "买入") { value = Math.Abs(value); } else { value = 0 - Math.Abs(value); } - var tempTradeSpan = new trade_span - { - TradeId = r.Trade.id, - ClientId = trade.ClientId, - ValueDate = req.settleDate, - UnderlyingId = trade.UnderlyingId, - UnderlyingCode = trade.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value - }; - resultMap[r.Trade.id] = tempTradeSpan; - } - - return resultMap.Values.ToList(); - } - - /// - /// 计算其他期权预付金 - /// - private List CalculationOtherOptionMargin(RunMarginCalculationReq req) - { - var resultMap = new Dictionary(); - var tempTradeList = new List(); - var vols = new Dictionary(); - foreach (var t in req.tradeList) - { - var vType = t.VolType; - t.VolType = "报价Ask"; - var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); - var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, req.CalcMarginType == CalcMarginTypeEnum.EodMargin); - vols[t.id] = vol; - t.VolType = vType; - tempTradeList.Add(t.Clone()); - } - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: tempTradeList, - calcScenario: CalcScenarioEnum.EodSettlement, - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: null, - overrideVolsForTrade: vols, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - //if (priceDict == null) - //{ - // priceDict = new Dictionary(); - // Dictionary rateDict = base.GetUpDownLimitRate(req.tradeList.Select(O => O.UnderlyingId).ToArray()); - // tempTradeList.ForEach(t => - // { - // double[] arr = base.GetUpDownLimitPrice(rateDict[t.id], (t.SpotPrice ?? 0), double.Parse(rateDict[t.id][2])); - // priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? arr[1] : arr[0]; - // }); - //} - //else - //{ - // Dictionary dict = base.GetUpDownLimitPrice(priceDict); - // tempTradeList.ForEach(t => - // priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? dict[t.id][1] : dict[t.id][0]); - //} - - var newTradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: tempTradeList, - calcScenario: CalcScenarioEnum.EodSettlement, - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: null, - overrideVolsForTrade: vols, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - foreach (var t in tempTradeList) - { - var cPv = tradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; - var nPv = newTradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; - //预付金= 次日最大亏损; - var value = t.OptionType == "看涨" ? cPv - nPv : cPv + nPv; - logger.Info($"茂川奇异预付金计算:[{t.TradeType}_{t.BuySell}_{t.OptionType}_{t.Strike}] => 当日Pv:{cPv};次日Pv:{nPv}"); - var tempTradeSpan = new trade_span - { - TradeId = t.id, - ClientId = t.ClientId, - ValueDate = req.settleDate, - UnderlyingId = t.UnderlyingId, - UnderlyingCode = t.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value - }; - resultMap[t.id] = tempTradeSpan; - } - - return resultMap.Values.ToList(); - } - - private List CalculationStructureOptionMargin(RunMarginCalculationReq req) - { - var resultMap = new List(); - foreach (var td in req.tradeList) - { - var tempId = int.MaxValue; - td.SubTrades.ToList().ForEach(t => t.id = tempId--); - var childrenSpans = RunMarginCalculation(req.Clone(td.SubTrades.ToList())); - - double margin = 0; - switch (td.StructureType) - { - case "牛市价差": - case "熊市价差": - case "亚式熊市价差": - case "三领口组合": - for (var j = 0; j < childrenSpans.Count; j++) - { - margin += childrenSpans[j].WorstCastClientPayable ?? 0; - } - break; - case "跨式组合": - case "宽跨式组合": - for (var j = 0; j < childrenSpans.Count; j++) - { - var absMargin = Math.Abs(childrenSpans[j].WorstCastClientPayable ?? 0); - if (margin < absMargin) - { - margin = absMargin; - } - } - break; - case "复制标的资产": - case "蝶式组合": - case "飞鹰式组合": - case "比例价差": - case "日历价差": - case "箱式价差": - case "风险逆转": - default: - break; - } - var tempTradeSpan = new trade_span - { - TradeId = td.id, - ClientId = td.ClientId, - ValueDate = req.settleDate, - UnderlyingId = td.UnderlyingId, - UnderlyingCode = td.UnderlyingCode, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - Spv1 = margin, - Spv2 = margin, - Spv3 = margin, - Spv4 = margin, - WorstCastClientPayable = margin - }; - resultMap.Add(tempTradeSpan); - } - return resultMap; - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var resultMap = new List(); - - if (req.tradeList == null || !req.tradeList.Any()) - { - return resultMap; - } - - if (req.forOtherSide) - { - return RunMarginCalculationOtherSide(req); - } - - var tList = req.tradeList.Where(O => O.TradeType == "结构化交易").ToList(); - - if (tList.Count > 0) - { - resultMap.AddRange(CalculationStructureOptionMargin(req.Clone(tList))); - } - - tList = req.tradeList.Where(O => O.TradeType == "香草期权" || O.TradeType == "亚式期权").ToList(); - - if (tList.Count > 0) - { - resultMap.AddRange(CalculationNormalOptionMargin(req.Clone(tList))); - } - - tList = req.tradeList.Where(O => O.TradeType != "结构化交易" && O.TradeType != "香草期权" && O.TradeType != "亚式期权").ToList(); - - if (tList.Count > 0) - { - resultMap.AddRange(CalculationOtherOptionMargin(req.Clone(tList))); - } - - return resultMap; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - - if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) - { - using (var db = new YLContext()) - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/MarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/MarginCalculation.cs index 0ec23c19..f2756f59 100644 --- a/YLErpDAL/BLL/MarginCalculation/MarginCalculation.cs +++ b/YLErpDAL/BLL/MarginCalculation/MarginCalculation.cs @@ -24,7 +24,7 @@ namespace YLErp.BLL.MarginCalculation var result = new List(); var eodTradeids = new YLContext().eod_trade_risk_manual.Where(x => x.ValueDate == req.settleDate && x.Margin != null && string.IsNullOrEmpty(x.VolType)).Select(x => x.TradeId); var tempTradeList = req.tradeList.Where(O => eodTradeids.Contains(O.id)).ToList(); - if (tempTradeList.Any() && PS.Config.Company != CompanyEnum.广期资本) + if (tempTradeList.Any()) { result = EodtraderiskmanualCalculation(req.Clone(tempTradeList)); } @@ -38,114 +38,10 @@ namespace YLErp.BLL.MarginCalculation { result.AddRange(SingleMarginCalculation(req.Clone(tempTradeList))); } - //if(PS.Config.ErpElement.SecuritiesEnvironment ){ - // tempTradeList = req.tradeList.Where(O => O.TradeType == "收益互换" && !eodTradeids.Contains(O.id)).ToList(); - // if (tempTradeList.Any()) - // { - // result.AddRange(SwapTradeMarginCalculation(req.Clone(tempTradeList))); - // } - //} tempTradeList = req.tradeList.Where(O => O.TradeType != "现金流交易" && O.MarginType == MarginTypeEnum.DEFAULT && !eodTradeids.Contains(O.id)).ToList(); - if (PS.Config.Company == CompanyEnum.广期资本) - { - tempTradeList = req.tradeList.Where(O => O.TradeType != "现金流交易" && O.MarginType == MarginTypeEnum.DEFAULT).ToList(); - } if (tempTradeList.Any()) { - switch (PS.Config.Company) - { - case CompanyEnum.渤海: - case CompanyEnum.安粮: - result.AddRange(BHRSMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.申万: - result.AddRange(SYWGMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.方顿: - result.AddRange(FDMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.茂川资本: - result.AddRange(MaoChuanMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.宏源: - result.AddRange(HongYuanMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.中财资本: - result.AddRange(ZhongCaiMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.上期资本: - result.AddRange(SQMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.伴兴: - result.AddRange(BXMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.海通: - result.AddRange(HaiTongMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.瑞达: - result.AddRange(RDMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.兴证: - result.AddRange(XingZhengMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.弘业: - result.AddRange(HongYeMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.广期资本: - result.AddRange(GQMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.中金: - result.AddRange(ZhongJinMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.厦门象屿: - result.AddRange(XMXYMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.国海: - result.AddRange(GuoHaiMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.润和: - case CompanyEnum.中基石化: - result.AddRange(DongZhengRunHeMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.华安: - result.AddRange(HuaAnMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.浙期: - result.AddRange(ZheQiMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.国投: - result.AddRange(GuoTouMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.湘财: - result.AddRange(XiangCaiMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.中粮: - result.AddRange(ZhongLiangMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.长江: - result.AddRange(ChangJiangMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.国信金阳: - result.AddRange(GuoXinJinYangMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.东吴: - result.AddRange(DongWuMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.国泰君安: - case CompanyEnum.光大光子: - case CompanyEnum.兴业商贸: - result.AddRange(GTJAMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.广发商贸: - result.AddRange(GFSMMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - case CompanyEnum.招证: - result.AddRange(ZhaoZhengMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - default: - result.AddRange(DefaultMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); - break; - } + result.AddRange(DefaultMarginCalculation.Instance.RunMarginCalculation(req.Clone(tempTradeList))); } foreach (var ret in result) { @@ -189,128 +85,6 @@ namespace YLErp.BLL.MarginCalculation return result; } - /// - /// 收益互换预付金计算 - /// - /// - /// - private static List SwapTradeMarginCalculation(RunMarginCalculationReq req) - { - var result = new List(); - var clientIds = req.tradeList.Where(t => t.ParentTradeId == 0).Select(t => t.ClientId).Distinct().ToList(); - //增加clientId=0,默认为全部 - clientIds.Add(0); - //获取客户互换预付金预警设置 - var marginRateList = new YLContext().client_marginrate.Where(t => clientIds.Contains(t.ClientId) && t.ValueDate <= req.settleDate).ToList(); - - //期权详情 - tradeBLL.SetFieldsByTradeType(req.tradeList); - - foreach (var trade in req.tradeList) - { - //剔除多空组合子交易 - if (trade.ParentTradeId > 0) continue; - client_marginrate clientMarginRateSet = null; - var extendService = new TradeExtendService(req.UserInfo); - extendService.SetTradeExtend(new[] { trade }); - //盈亏 - var profitAndLoss = 0.0; - //计息开始日 - var swapStartDate = (trade.StartDate ?? trade.TradeDate).Value.AddDays(trade.trade_swap.IncludeFirstDay ? 1 : 0); - //初始预付金比例 - var initMarginRate = (trade.trade_swap.GetMarginRate ?? 0) - (trade.trade_swap.PayMarginRate ?? 0); - var initMargin = Math.Max(initMarginRate, 0) * trade.StockEqvNotional; - //利息收入 收取 - 支付 - var interestIncome = PayoffSwapCalcService.GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, trade.trade_swap.GetSwapTimeAndRate, swapStartDate, req.settleDate, trade.trade_swap.AnnualDays ?? 0, trade.StockEqvNotional) - - PayoffSwapCalcService.GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, trade.trade_swap.PaySwapTimeAndRate, swapStartDate, req.settleDate, trade.trade_swap.AnnualDays ?? 0, trade.StockEqvNotional); - profitAndLoss += interestIncome; - - - var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); - var costTradePrice = 0.0; - //是否开仓是收取手续费 - if (!trade.trade_swap.IsTradePriceWhenOpen) - { - costTradePrice += (trade.trade_swap.GetSingleFee ?? 0) * (trade.trade_swap.GetNotional ?? 0) / underlying.ContractSize; - costTradePrice += (trade.trade_swap.GetUnAnnualRate ?? 0) * trade.StockEqvNotional; - - costTradePrice -= (trade.trade_swap.PaySingleFee ?? 0) * (trade.trade_swap.PayNotional ?? 0) / underlying.ContractSize; - costTradePrice -= (trade.trade_swap.PayUnAnnualRate ?? 0) * trade.StockEqvNotional; - } - profitAndLoss += costTradePrice; - - //多空组合 - if (SwapTypeEnum.多空组合.ToString().Equals(trade.trade_swap.SwapType)) - { - //标的盈亏 - if (trade.get_trade_swap_details != null && trade.get_trade_swap_details.Count > 0) - { - trade.get_trade_swap_details.ForEach(a => - { - profitAndLoss += (req.PriceProvider.GetPrice(a.UnderlyingCode) - (a.SpotPrice ?? 0.0)) * (a.Notional ?? 0.0) * ("空头".Equals(a.LongShort) ? -1.0 : 1.0) * (a.IsForGet ? 1 : -1); - }); - } - //预警线 - if (marginRateList.Any(a => a.Type.Equals("多空组合") && (a.ClientId == trade.ClientId || a.ClientId == 0))) - { - clientMarginRateSet = marginRateList.Where(a => a.Type.Equals("多空组合") && (a.ClientId == trade.ClientId || a.ClientId == 0)).OrderByDescending(a => a.ClientId).ThenByDescending(a => a.ValueDate).FirstOrDefault(); - } - } - else - {//普通 +收取盈亏 -支付盈亏 - profitAndLoss += - PayoffSwapCalcService.GetInitialAmountSwapGet(trade, trade.trade_swap, trade.trade_swap.GetSpotPrice ?? 0, req.PriceProvider.GetPrice(trade.trade_swap.GetUnderlyingCode), trade.StockEqvNotional, req.settleDate, null) - - PayoffSwapCalcService.GetInitialAmountSwapPay(trade, trade.trade_swap, trade.trade_swap.PaySpotPrice ?? 0, req.PriceProvider.GetPrice(trade.trade_swap.PayUnderlyingCode), trade.StockEqvNotional, req.settleDate, null); - - if (underlying != null && underlying.Variety != null) - { - if (marginRateList.Any(a => a.Type.Equals("品种") && (a.ClientId == trade.ClientId || a.ClientId == 0) && a.VarietyId == underlying.Variety.id)) - { - clientMarginRateSet = marginRateList.Where(a => a.Type.Equals("品种") && (a.ClientId == trade.ClientId || a.ClientId == 0) && a.VarietyId == underlying.Variety.id).OrderByDescending(a => a.ClientId).ThenByDescending(a => a.ValueDate).FirstOrDefault(); - } - } - } - - //维持预付金 - var WorstCastClientPayable = initMargin - profitAndLoss; - //持仓预付金 - var positionMargin = initMargin; - - var margin = 0.0; - //追保计算 未设置预警线 则取初始预付金比例 - if (WorstCastClientPayable <= (clientMarginRateSet == null ? initMarginRate : clientMarginRateSet.WarningLine) * trade.StockEqvNotional) - { - margin = initMargin - WorstCastClientPayable; - //追保暂时只算单方向 - positionMargin = initMargin + Math.Max(margin, 0); - } - - result.Add(new trade_span() - { - TradeId = trade.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = trade.ClientId, - UnderlyingId = trade.UnderlyingId, - UnderlyingCode = trade.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = positionMargin, - Spv2 = positionMargin, - Spv3 = positionMargin, - Spv4 = positionMargin, - Spv5 = positionMargin, - Spv6 = positionMargin, - Spv7 = positionMargin, - Spv8 = positionMargin, - Spv = positionMargin, - WorstCastClientPayable = positionMargin, - Margin = margin - }); - } - return result; - } - private static List SingleMarginCalculation(RunMarginCalculationReq req) { var result = new List(); @@ -422,41 +196,6 @@ namespace YLErp.BLL.MarginCalculation { value = 0; } } break; - case MarginTypeEnum.XingYe: - value = XingYeMarginCalculation.TradeMargin(req, trade); - break; - case MarginTypeEnum.GuoTouLock: - if (trade.TradeType == "雪球期权" || trade.TradeType == "收益互换") - { - var initialMargin = (trade.InitialMargin ?? 0) * trade.StockEqvNotional / trade.OriginalStockEqvNotional.Value; - double[] lockvals = { initialMargin, - PS.Config.Company == CompanyEnum.湘财 - ? XiangCaiMarginCalculation.TradeMargin(req, trade) - : GuoTouMarginCalculation.TradeMargin(req, trade) - }; - if (PS.Config.Company == CompanyEnum.湘财 && initialMargin < 0) - {// #OTC-5636 见备注 - value = lockvals.Min(); - } - else - { - value = lockvals.Max(); - } - isSingleMargin = true; - } - break; - case MarginTypeEnum.GuoTouNoLock: - if (trade.TradeType == "雪球期权" || trade.TradeType == "收益互换") - { - double[] noLockvals = { 0, - PS.Config.Company == CompanyEnum.湘财 - ? XiangCaiMarginCalculation.TradeMargin(req, trade) - : GuoTouMarginCalculation.TradeMargin(req, trade) - }; - value = noLockvals.Max(); - isSingleMargin = true; - } - break; default: case MarginTypeEnum.NONE: value = 0; @@ -533,73 +272,7 @@ namespace YLErp.BLL.MarginCalculation public static List CalcClientMargin(CalcClientMarginReq req) { - switch (PS.Config.Company) - { - case CompanyEnum.渤海: - return BHRSMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.安粮: - return BHRSMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.申万: - return SYWGMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.伴兴: - return BXMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.海通: - return HaiTongMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.瑞达: - return RDMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.兴证: - return XingZhengMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.宏源: - return HongYuanMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.中财资本: - return ZhongCaiMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.上期资本: - return SQMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.弘业: - return HongYeMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.广期资本: - return GQMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.方顿: - return FDMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.中金: - return ZhongJinMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.国海: - return GuoHaiMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.厦门象屿: - return XMXYMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.华安: - return HuaAnMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.浙期: - return ZheQiMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.润和: - case CompanyEnum.中基石化: - return DongZhengRunHeMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.国投: - return GuoTouMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.湘财: - return XiangCaiMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.中粮: - return ZhongLiangMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.长江: - return ChangJiangMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.国信金阳: - return GuoXinJinYangMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.东吴: - return DongWuMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.格林大华: -#if DEBUG - return GLDHMarginCalculation.Instance.CalcClientMargin(req); -#endif - case CompanyEnum.国泰君安: - case CompanyEnum.光大光子: - return GTJAMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.广发商贸: - return GFSMMarginCalculation.Instance.CalcClientMargin(req); - case CompanyEnum.招证: - return ZhaoZhengMarginCalculation.Instance.CalcClientMargin(req); - default: - return DefaultMarginCalculation.Instance.CalcClientMargin(req); - } + return DefaultMarginCalculation.Instance.CalcClientMargin(req); } /// @@ -614,37 +287,17 @@ namespace YLErp.BLL.MarginCalculation return true; } - switch (PS.Config.Company) - { - case CompanyEnum.渤海: - case CompanyEnum.安粮: - case CompanyEnum.润和: - case CompanyEnum.中基石化: - return true; - default: return false; - } + return false; } public static double? GetInitialMarginRatio(trade trade) { - switch (PS.Config.Company) - { - case CompanyEnum.方顿: - return FDMarginCalculation.Instance.GetInitialMarginRatio(trade); - default: - return 0; - } + return 0; } public static double? GetPositionMarginRatio(trade trade) { - switch (PS.Config.Company) - { - case CompanyEnum.方顿: - return FDMarginCalculation.Instance.GetPositionMarginRatio(trade); - default: - return 0; - } + return 0; } public static double GetInitialMarginWithPreHandle(trade trade) @@ -723,67 +376,7 @@ namespace YLErp.BLL.MarginCalculation } else { - switch (PS.Config.Company) - { - case CompanyEnum.渤海: - return BHRSMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.安粮: - return BHRSMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.申万: - return SYWGMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.茂川资本: - return MaoChuanMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.宏源: - return HongYuanMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.伴兴: - return BXMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.海通: - return HaiTongMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.瑞达: - return RDMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.兴证: - return XingZhengMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.弘业: - return HongYeMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.广期资本: - return GQMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.方顿: - return FDMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.国海: - return GuoHaiMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.华安: - return HuaAnMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.浙期: - return ZheQiMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.润和: - return DongZhengRunHeMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.国投: - return GuoTouMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.湘财: - return XiangCaiMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.中粮: - return ZhongLiangMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.长江: - return ChangJiangMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.国信金阳: - return GuoXinJinYangMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.东吴: - return DongWuMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.格林大华: -#if DEBUG - return GLDHMarginCalculation.Instance.GetTradeMargin(req); -#endif - case CompanyEnum.广发商贸: - return GFSMMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.国泰君安: - case CompanyEnum.上期资本: - case CompanyEnum.光大光子: - return GTJAMarginCalculation.Instance.GetTradeMargin(req); - case CompanyEnum.招证: - return ZhaoZhengMarginCalculation.Instance.GetTradeMargin(req); - default: - return DefaultMarginCalculation.Instance.GetTradeMargin(req); - } + return DefaultMarginCalculation.Instance.GetTradeMargin(req); } } finally diff --git a/YLErpDAL/BLL/MarginCalculation/RDMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/RDMarginCalculation.cs deleted file mode 100644 index 1af22525..00000000 --- a/YLErpDAL/BLL/MarginCalculation/RDMarginCalculation.cs +++ /dev/null @@ -1,541 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 瑞达预付金计算 - /// - public class RDMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly RDMarginCalculation Instance; - - static RDMarginCalculation() - { - Instance = new RDMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected RDMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - helper.SetFieldsByTradeType(); - - var mpProvider = helper.GetMarginParamProvider(); - var tradeVolatilityRateDic = new Dictionary(); - var calcTradeList = req.tradeList.ToList(); - var twoMarginClietIds = new HashSet(); - - foreach (var t in req.tradeList) - { - var volRate = 0d; - var price = req.PriceProvider.GetPrice(t.UnderlyingCode); - if (t.OptionType == "看涨" && price / t.ActualStrike < 0.9 || t.OptionType == "看跌" && price / t.ActualStrike > 1.1) - { - volRate = 0.2; - } - else - { - volRate = mpProvider.GetVolatilityRate(t.UnderlyingCode) ?? 0; - } - if (volRate > 0) - { - tradeVolatilityRateDic[t.id] = volRate; - } - - //if (t.id > 0 && t.TradeType != "掉期" - // && !twoMarginClietIds.Contains(t.ClientId) - // && !twoMarginClietIds.Contains(~t.ClientId)) - //{ - // var client = helper.GetClient(t.ClientId); - // if (client != null && client.MarginOptionType == (int)MarginOptionEnum.双向追保) - // { - // twoMarginClietIds.Add(t.ClientId); - // } - // else - // { - // twoMarginClietIds.Add(~t.ClientId); - // } - //} - } - - var upLimitPrices = new ManualPriceProvider(); - var upLimitPricesTwoThirds = new ManualPriceProvider(); - var upLimitPricesOneThird = new ManualPriceProvider(); - var downLimitPrices = new ManualPriceProvider(); - var downLimitPricesTwoThirds = new ManualPriceProvider(); - var downLimitPricesOneThird = new ManualPriceProvider(); - var normalLimitPrices = new ManualPriceProvider(); - - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - foreach (var t in req.tradeList) - { - if (upLimitPrices.Contains(t.UnderlyingCode)) - { - continue; - } - - if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed)) - { - updownLimit = 0.05; - } - - var price = req.PriceProvider.GetPrice(t.UnderlyingCode); - - if (isFixed) - { - upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + updownLimit * 2.0 / 3.0); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + updownLimit / 3.0); - - downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - updownLimit * 2.0 / 3.0); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - updownLimit / 3.0); - } - else - { - upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit))); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit * 2.0 / 3.0) : (1 - updownLimit * 2.0 / 3.0))); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit / 3.0) : (1 - updownLimit / 3.0))); - - downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit))); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit * 2.0 / 3.0) : (1 + updownLimit * 2.0 / 3.0))); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit / 3.0) : (1 + updownLimit / 3.0))); - } - - //Normal - normalLimitPrices.SetPrice(t.UnderlyingCode, price); - } - - var prices = new[] { - ("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird), - ("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird), - ("normal", normalLimitPrices) - }; - foreach (var price in prices) - { - foreach (var addVolRateDic in new[] { null, tradeVolatilityRateDic }) - { - var key = $"{price.Item1}_{(addVolRateDic == null ? 0 : 1)}"; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: calcTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: addVolRateDic, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any()) - { - continue; - } - foreach (var item in tradeRiskResult.Results) - { - if (item.Trade.StructureType == "掉期") - { - continue; - } - - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - value = pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_1": - tempTradeSpan.Spv1 = value; break; - case "upTwoThirds_1": - tempTradeSpan.Spv2 = value; break; - case "upOneThird_1": - tempTradeSpan.Spv3 = value; break; - case "normal_1": - tempTradeSpan.Spv4 = value; break; - case "down_1": - tempTradeSpan.Spv5 = value; break; - case "downTwoThirds_1": - tempTradeSpan.Spv6 = value; break; - case "downOneThird_1": - tempTradeSpan.Spv7 = value; break; - case "normal_0": - tempTradeSpan.Delta = item.ValueResult.Delta; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - - resultMap[item.Trade.id].UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - } - } - - if (price.Item1 == "normal") - { - var lastSettleDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - - var tradeRiskResultNormal = CalculatorHelper.CalculateRisksForTrades( - valueDate: lastSettleDate, - tradeList: calcTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.BASIC_PRICING, - addVolRateDic: null, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - if (tradeRiskResultNormal.Results != null && tradeRiskResultNormal.Results.Count > 0) - { - foreach (var item in tradeRiskResultNormal.Results) - { - if (item.Trade.StructureType != "掉期") - { - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - value = pv * clientRatio; - } - - resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - tempTradeSpan.Spv = value; - } - } - } - } - } - - //foreach (var item in resultMap.Values) - //{ - // if (item.ClientId > 0 && twoMarginClietIds.Contains(item.ClientId.Value)) - // { - // var clone = item.Clone(); - // clone.ReverseSpv().SetWorstCastClientPayable(); - // item.WorstCastClientPayable += clone.WorstCastClientPayable ?? 0; - // item.SetAllSpv(item.WorstCastClientPayable ?? 0); - // } - //} - - var tradeListDQ = req.tradeList.Where(x => x.StructureType == "掉期").ToList(); - - tradeListDQ.ForEach(x => - { - var contains = resultMap.TryGetValue(x.id, out var tempTradeSpan); - if (!contains) - { - resultMap[x.id] = tempTradeSpan = helper.CreateTradeSpan(x); - } - - var eodPrice = req.PriceProvider.GetPrice(x.UnderlyingCode); - if (x.SpotPrice != null && x.SpotPrice != 0 && (Math.Abs(eodPrice / x.SpotPrice.Value) > 1.05 && x.BuySell == "买入" || Math.Abs(eodPrice / x.SpotPrice.Value) < 0.95 && x.BuySell == "卖出")) - { - tempTradeSpan.WorstCastClientPayable = tempTradeSpan.DeltaMargin = (0.15 + Math.Abs((eodPrice / x.SpotPrice.Value) - 1)) * eodPrice * x.TradeAmount; - } - else - { - tempTradeSpan.WorstCastClientPayable = tempTradeSpan.DeltaMargin = 0.15 * eodPrice * x.TradeAmount; - } - }); - - return resultMap.Values.Where(n => n.TradeId >= 0).ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var underlyingCodes = req.tradeSpans.Select(t => t.UnderlyingCode).ToHashSet(); - var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate).Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - - //删除 - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - //var clientIds = req.tradeSpans.Select(t => t.ClientId).Distinct().ToList(); - //var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); - var tradeSpanInfos = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - var tradeSpanInfosWithoutDQ = tradeSpanInfos.Where(x => x.trade.StructureType != "掉期"); - var tradeSpanInfosDQ = tradeSpanInfos.Where(x => x.trade.StructureType == "掉期"); - - var clientGroups = tradeSpanInfosWithoutDQ.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - #region Span Margin Method - - var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), - Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - - #endregion - } - - #endregion - - #region Delta Margin Method - - var varietyGroup = clientGroup.GroupBy(t => t.tradeSpan.VarietyId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - MaxMarginRate = t.Max(g => mpProvider.TryGetMarginRate(g.tradeSpan.UnderlyingCode, out var marginRate) ? marginRate : 0), - MaxSpotPrice = t.Max(g => g.tradeSpan.UnderlyingPrice), - PvForDelta = t.Sum(g => g.tradeSpan.Spv) * (-1), - DeltaSell = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "买入" || g.trade.TradeType == "远期" ? 1 : 0)), - DeltaBuy = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta < 0 && g.trade.TradeType != "远期" ? 1 : 0)), - DeltaBuyMinus = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta > 0 && g.trade.TradeType != "远期" ? 1 : 0)), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - foreach (var item in varietyGroup) - { - #region 更新tradeSpan,通过Delta品种级别求和算法,给tradeSpan的deltaMargin赋值 - - var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.VarietyId == item.VarietyId && x.ValueDate == req.settleDate).ToList(); - //DeltaSell为客户角度卖出,且为客户角度看Delta - if (item.DeltaSell > 0) - { - tradeSpansUpdate.ForEach(x => - { - var tradeSpanInfo = tradeSpanInfosWithoutDQ.FirstOrDefault(y => y.trade.id == x.TradeId); - var trade = tradeSpanInfo != null ? tradeSpanInfo.trade : null; - //客户角度卖出的交易 - //客户角度买入的交易,客户角度Delta<0,即交易员角度Delta>0 - if (trade != null && (trade.BuySell == "买入" || trade.TradeType == "远期" || x.Delta > 0)) - { - x.DeltaMargin = -x.Delta * item.MaxSpotPrice * item.MaxMarginRate + x.Spv; - } - }); - item.DeltaMargin = -Math.Max((item.DeltaSell ?? 0) + (item.DeltaBuyMinus ?? 0), 0) * item.MaxSpotPrice * item.MaxMarginRate + item.PvForDelta; - } - else - { - tradeSpansUpdate.ForEach(x => - { - var tradeSpanInfo = tradeSpanInfosWithoutDQ.FirstOrDefault(y => y.trade.id == x.TradeId); - var trade = tradeSpanInfo?.trade; - //客户角度卖出的交易 - //客户角度买入的交易,客户角度Delta>0,即交易员角度Delta<0 - if (trade != null && (trade.BuySell == "买入" || trade.TradeType == "远期" || x.Delta < 0)) - { - x.DeltaMargin = x.Delta * item.MaxSpotPrice * item.MaxMarginRate + x.Spv; - } - }); - item.DeltaMargin = Math.Min((item.DeltaSell ?? 0) + (item.DeltaBuy ?? 0), 0) * item.MaxSpotPrice * item.MaxMarginRate + item.PvForDelta; - } - - #endregion - } - - #endregion - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - Spv5 = underlyingGroup.Sum(g => g.Spv5), - Spv6 = underlyingGroup.Sum(g => g.Spv6), - Spv7 = underlyingGroup.Sum(g => g.Spv7), - DeltaMargin = varietyGroup.Sum(g => g.DeltaMargin), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - if (clientSpan.WorstCastClientPayable > clientSpan.DeltaMargin) - { - clientSpan.WorstCastClientPayable = clientSpan.DeltaMargin; - - //取delta预付金作为最终预付金 - var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - } - var worstCastClientPayableDQ = tradeSpanInfosDQ.Where(x => x.tradeSpan.ClientId == clientSpan.ClientId).Sum(x => x.tradeSpan.WorstCastClientPayable * -1); - clientSpan.WorstCastClientPayable += worstCastClientPayableDQ; - clientSpanNews.Add(clientSpan); - } - - var clientIdsDQ = tradeSpanInfosDQ.Select(x => x.trade.ClientId).ToHashSet(); - foreach (var clientId in clientIdsDQ) - { - if (!clientSpanNews.Select(x => x.ClientId).Contains(clientId)) - { - var clientSpan = new ClientSpan - { - ClientId = clientId, - ValueDate = req.settleDate, - WorstCastClientPayable = 0, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }; - - var worstCastClientPayableDQ = tradeSpanInfosDQ.Where(x => x.tradeSpan.ClientId == clientId).Sum(x => x.tradeSpan.WorstCastClientPayable * -1); - clientSpan.WorstCastClientPayable += worstCastClientPayableDQ; - clientSpanNews.Add(clientSpan); - } - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (tradeMargin != null && tradeMargin.FirstOrDefault() != null && trade.BuySell == "买入") - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - var mpProvider = new MarginParamProvider(OptUserInfo.SystemUser, valuedateBLL.ValueDate.Date).Initialize(new List { trade.UnderlyingCode }.ToHashSet(), MarginParamTypeEnum.MarginRate); - mpProvider.TryGetMarginRate(trade.UnderlyingCode, out var marginRate); - var deltaMargin = Math.Abs(tradeMargin.FirstOrDefault().Delta ?? 0) * (trade.SpotPrice ?? 0) * marginRate; - return margin > deltaMargin ? margin : deltaMargin; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/SQMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/SQMarginCalculation.cs deleted file mode 100644 index daf93fba..00000000 --- a/YLErpDAL/BLL/MarginCalculation/SQMarginCalculation.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 上期预付金计算 - /// - public class SQMarginCalculation : MarginCalculationBase - { - public static readonly SQMarginCalculation Instance; - - static SQMarginCalculation() - { - Instance = new SQMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected SQMarginCalculation() - { - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/SYWGMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/SYWGMarginCalculation.cs deleted file mode 100644 index db31bc20..00000000 --- a/YLErpDAL/BLL/MarginCalculation/SYWGMarginCalculation.cs +++ /dev/null @@ -1,254 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.DBModels.Helpers; -using YLErp.Enums; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 申银万国 - /// - public class SYWGMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly SYWGMarginCalculation Instance; - - static SYWGMarginCalculation() - { - Instance = new SYWGMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private SYWGMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - - if (req.tradeList == null || req.tradeList.Count < 1) - { - return tradeSpans; - } - - var tempStockTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); - if (tempStockTradeList.Any()) - { - var stockTradeSpanlist = StockMarginCalculation(req.Clone(tempStockTradeList)); - if (stockTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(stockTradeSpanlist); - } - } - - var tempFutureTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); - if (tempFutureTradeList.Any()) - { - var futureTradeSpanlist = FutureMarginCalculation(req.Clone(tempFutureTradeList)); - if (futureTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(futureTradeSpanlist); - } - } - - return tradeSpans; - } - - /// - /// 股票类期权计算预付金 - /// - public List StockMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - - if (req.tradeList == null || req.tradeList.Count < 1) - { - return tradeSpans; - } - - var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - foreach (var t in req.tradeList) - { - if (!helper.GetSpecialMargin(t, 0, out var value)) - { - var client = helper.GetClient(t); - if (client == null) - { - continue; - } - var clientRatio = client?.Ratio ?? 1.0; - //如果是股票去名义本金,如果是期货取:份额 * 即期价格 - value = (t.StockEqvNotional == 0 ? TradeHelper.GetStockEqvNotional(t.Notional * t.SpotPrice, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotional) * marginRation * (t.BuySell == "买入" ? 1 : 0) * clientRatio; - } - - tradeSpans.Add(new trade_span - { - TradeId = t.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = t.ClientId, - UnderlyingId = t.UnderlyingId, - UnderlyingCode = t.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value - }); - } - return tradeSpans; - } - - /// - /// 商品期权计算预付金 - /// - public List FutureMarginCalculation(RunMarginCalculationReq req) - { - var futureTradeList = req.tradeList; - - if (futureTradeList == null || !futureTradeList.Any()) - { - return new List(0); - } - - var tradeSpans = new List(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - helper.SetFieldsByTradeType(); - - using (var db = new YLContext()) - { - var underlyingCodes = futureTradeList.Select(t => t.UnderlyingCode).ToHashSet(); - var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate).Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - - var overrideVolsForTrades = VolCaculator.Instance.GetVol(futureTradeList, req.settleDate); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: futureTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: req.PriceProvider, - pricingRequest: QdpPricingRequest.BASIC_GREEKS, addVolRateDic: null, - volType: req.volType, overrideVolsForTrade: overrideVolsForTrades, isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - logger.Info($"商品期货预付金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); - var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; - var FutureMarginAddRatio = valuedateBLL.SystemDate.FutureMarginAddRatio ?? 0; - - if (tradeRiskResult.Results.Count <= 0) - { - return tradeSpans; - } - - foreach (var trade in futureTradeList) - { - var closePrice = req.PriceProvider.GetPrice(trade.UnderlyingCode); - var optionValueList = tradeRiskResult.Results.Where(t => t.Trade.id == trade.id && t.ValueResult != null && t.Trade != null && !double.IsNaN(t.ValueResult.Delta) && !double.IsNaN(t.ValueResult.Vega) && !double.IsNaN(t.ValueResult.Gamma)).ToList(); - - //未设置相关预付金系数默认为1.0 - double clientRatio = 1, clientAddRatio = 0; - var client = helper.GetClient(trade); - if (client != null) - { - clientRatio = client.Ratio ?? 1; - clientAddRatio = client.AddRatio ?? 0; - } - - if (optionValueList.Any()) - { - var deltaMerge = 0.0; - var deltaShort = optionValueList.Sum(t => t.ValueResult.Delta * (t.Trade.BuySell == "买入" ? 1 : 0)); - var deltaMax = optionValueList.Sum(t => t.ValueResult.DeltaMax * (t.Trade.BuySell == "买入" ? 1 : 0)); - //跨式组合和宽跨式组合用到的是组合交易里面的Max Delta作为deltaMerge参与预付金的计算 - deltaMerge = trade.TradeType == "结构化交易" && (trade.StructureType == "跨式组合" || trade.StructureType == "宽跨式组合") ? Math.Abs(deltaMax) : Math.Abs(deltaShort); - logger.Info("交易id为" + trade.id + "的delta:" + deltaMerge); - //if (deltaLong * deltaShort == 0) - //{ - // deltaMerge = Math.Abs(deltaShort); - //} - //else if (deltaLong * deltaShort < 0) - //{ - // if (Math.Abs(deltaLong) >= Math.Abs(deltaShort)) - // { - // deltaMerge = 0; - // } - // else - // { - // deltaMerge = Math.Abs(deltaShort) - Math.Abs(deltaLong); - // } - //} - //else - //{ - // deltaMerge = Math.Abs(deltaShort); - //} - mpProvider.TryGetMarginRate(trade.UnderlyingCode, out var marginRate); - //预付金 = (交易预付金率+公司预付金率加点)*合约名义金额(期货价格*数量)*delta - var margin = deltaMerge * closePrice * (marginRate + FutureMarginAddRatio + clientAddRatio) * alphaRate * clientRatio; - - if (trade.TradeType == "自定义交易") - { - if (helper.GetSpecialMargin(trade, 0, out var value)) - { - margin = value; - } - } - - tradeSpans.Add(new trade_span - { - TradeId = trade.id,//默认记录为第一条交易记录中 - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = trade.ClientId, - ValueDate = req.settleDate, - UnderlyingId = trade.UnderlyingId, - UnderlyingCode = trade.UnderlyingCode, - Spv1 = margin, - Spv2 = margin, - Spv3 = margin, - Spv4 = margin, - WorstCastClientPayable = margin, - Comment = $"标的{trade.UnderlyingCode},deltaMerge:{deltaMerge},closePrice:{closePrice},Margin:{marginRate},FutureMarginAddRatio:{FutureMarginAddRatio},clientAddRatio:{clientAddRatio},alphaRate:{alphaRate},clientRatio:{clientRatio}" - }); - } - else - { - var nanTradeValue = tradeRiskResult.Results.Where(t => t.Trade.id == trade.id && (double.IsNaN(t.ValueResult.Delta) || !double.IsNaN(t.ValueResult.Vega) || !double.IsNaN(t.ValueResult.Gamma))).Select(t => t.ValueResult).ToList(); - nanTradeValue.ForEach(optionValue => - { - logger.Error($"交易ID:{trade.UnderlyingId},Delta:{optionValue.Delta},DeltaCash{optionValue.DeltaCash},Vega{optionValue.Vega},Gamma:{optionValue.Gamma},vol:{optionValue.Vol}"); - }); - - } - } - } - - return tradeSpans; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/UniversalMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/UniversalMarginCalculation.cs deleted file mode 100644 index 1dca3b2b..00000000 --- a/YLErpDAL/BLL/MarginCalculation/UniversalMarginCalculation.cs +++ /dev/null @@ -1,139 +0,0 @@ -using YLErp.Modules.MarginModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class UniversalMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly UniversalMarginCalculation Instance; - - static UniversalMarginCalculation() - { - Instance = new UniversalMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - private UniversalMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var tradeSpans = new List(); - if (req.tradeList != null && req.tradeList.Count > 0) - { - var tempStockTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); - if (tempStockTradeList.Any()) - { - var stockTradeSpanlist = StockMarginCalculation(req.Clone(tempStockTradeList)); - if (stockTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(stockTradeSpanlist); - } - } - var tempFutureTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); - if (tempFutureTradeList.Any()) - { - var futureTradeSpanlist = FutureMarginCalculation(req.Clone(tempFutureTradeList)); - if (futureTradeSpanlist.Count > 0) - { - tradeSpans.AddRange(futureTradeSpanlist); - } - } - } - return tradeSpans; - } - - /// - /// 股票类期权计算预付金 - /// - public List StockMarginCalculation(RunMarginCalculationReq req) - { - //20210415:为了格林大华收盘通过 - //throw new Exception("未实现"); - return new List(); - } - - /// - /// 商品期权计算预付金 - /// - public List FutureMarginCalculation(RunMarginCalculationReq req) - { - var futureTradeList = req.tradeList; - var tradeSpans = new List(); - if (futureTradeList == null || futureTradeList.Count < 1) - { - return tradeSpans; - } - - var underlyingCodes = futureTradeList.Select(O => O.UnderlyingCode).ToHashSet(); - var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate) - .Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - - foreach (var t in futureTradeList) - { - if (!helper.GetSpecialMargin(t, 0, out var value)) - { - req.PriceProvider.TryGetPrice(t.UnderlyingCode, out var price); - mpProvider.TryGetMarginRate(t.UnderlyingCode, out var marginRate); - var contractSize = (_underlyingDataProvider.GetUnderlying(t.UnderlyingCode)?.ContractSize) ?? 0; - double diffPrice = 0; - switch (t.OptionType) - { - case "看涨": - diffPrice = (t.Strike ?? 0) - price; - break; - case "看跌": - diffPrice = price - (t.Strike ?? 0); - break; - } - var visualValue = Math.Max(diffPrice, 0) * contractSize; - var futureMargin = price * marginRate * contractSize; - var optionMargin1 = t.StockEqvNotional + futureMargin - 0.5 * visualValue; - var optionMargin2 = t.StockEqvNotional + futureMargin * 0.5; - - value = Math.Max(optionMargin1, optionMargin2); - } - - tradeSpans.Add(new trade_span - { - TradeId = t.id, - OptDate = DateTime.Now, - OptId = req.userId, - OptName = req.userName, - ClientId = t.ClientId, - UnderlyingId = t.UnderlyingId, - UnderlyingCode = t.UnderlyingCode, - ValueDate = req.settleDate, - Spv1 = value, - Spv2 = value, - Spv3 = value, - Spv4 = value, - WorstCastClientPayable = value - }); - } - - return tradeSpans; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin) - { - return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/XMXYMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/XMXYMarginCalculation.cs deleted file mode 100644 index fe1e154d..00000000 --- a/YLErpDAL/BLL/MarginCalculation/XMXYMarginCalculation.cs +++ /dev/null @@ -1,422 +0,0 @@ -using Qdp.Pricing.Base.Implementations; -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 国泰君安预付金计算 - /// - public class XMXYMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly XMXYMarginCalculation Instance; - - static XMXYMarginCalculation() - { - Instance = new XMXYMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected XMXYMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var tradeSpans = RunMarginCalculationForCommodity(helper); - - using (var db = new YLContext()) - { - var tradeIds = req.tradeList.Select(x => x.id); - var tradeMarginTemplates = db.trade_margin_template.Where(x => tradeIds.Contains(x.TradeId)).ToList(); - tradeSpans.ForEach(x => - { - var trade = req.tradeList.FirstOrDefault(y => y.id == x.TradeId); - var tradeMarginTemplate = tradeMarginTemplates.Where(y => y.TradeId == x.TradeId && x.ValueDate <= req.settleDate).OrderByDescending(y => y.ValueDate).FirstOrDefault(); - if (tradeMarginTemplate != null) - { - var marginTemplate = db.margin_template_v2.Find(tradeMarginTemplate.MarginTemplateId); - if (marginTemplate != null) - { - switch (marginTemplate.RuleType) - { - case (int)MarginRuleTypeEnum.无预付金: - CalcAsNo(x); - break; - case (int)MarginRuleTypeEnum.交易所基本规则: - var PriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.ClosePrice); - CalcAsExchangeBasicRule(x, trade, req, PriceProvider); - break; - } - } - } - }); - } - - return tradeSpans; - } - - private void CalcAsNo(trade_span span) - { - span.Spv1 = 0; - span.Spv2 = 0; - span.Spv3 = 0; - span.Spv4 = 0; - span.WorstCastClientPayable = 0; - span.MaxlossMargin = 0; - span.IsSingleMargin = true; - } - - private void CalcAsExchangeBasicRule(trade_span span, trade trade, RunMarginCalculationReq req, IEodPriceProviderWrap priceProvider) - { - if (trade.BuySell == "买入") - { - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - mpProvider.TryGetMarginRate(trade.UnderlyingCode, out var marginRate); - - var price = req.PriceProvider.GetPrice(trade.UnderlyingCode); - if (req.CalcMarginType == CalcMarginTypeEnum.EodMargin) - { - price = new EodPriceProvider(req.settleDate).GetPrice(trade.UnderlyingCode, SettlementTypeEnum.ClosePrice); - } - - double RoundedPv = 0; - - var reqConv = new CalculateRisksForTradesReq - { - valueDate = req.settleDate, - tradeList = new List { trade }, - priceProvider = priceProvider,//req.PriceProvider, - pricingRequest = PricingRequest.Pv | PricingRequest.Delta | PricingRequest.Gamma, - addVolRateDic = null, - volType = req.volType, - isUseTradeVol = PS.Config.IsTradeVol, - PreciseTimeMode = req.CalcMarginType != Enums.CalcMarginTypeEnum.EodMargin, - isAddVolPercent = true, - overrideVolsForTrade = null, - isMarginCalc = true - }; - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.EodMargin) - { - reqConv.calcScenario = Enums.CalcScenarioEnum.EodSettlement; - } - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(reqConv); - - RoundedPv = tradeRiskResult.Results.Where(x => x.Trade.id == trade.id).FirstOrDefault().ValueResult.Pv; - - var margin1 = RoundedPv + 0.5 * price * trade.TradeAmount * marginRate; - var margin2 = RoundedPv + price * trade.TradeAmount * marginRate - (trade.OptionType == "看涨" ? Math.Max((trade.ActualStrike ?? 0) - price, 0) : Math.Max(price - (trade.ActualStrike ?? 0), 0)) * trade.Notional / 2; - - //var margin1 = price * trade.Notional + 0.5 * trade.StockEqvNotional * marginRate; - //var margin2 = price * trade.Notional + trade.StockEqvNotional * marginRate - (trade.OptionType == "看涨" ? Math.Max((trade.ActualStrike ?? 0) - price, 0) : Math.Max(price - (trade.ActualStrike ?? 0), 0)) * trade.Notional / 2; - var value = Math.Max(margin1, margin2); - span.Spv1 = value; - span.Spv2 = value; - span.Spv3 = value; - span.Spv4 = value; - span.WorstCastClientPayable = value; - span.MaxlossMargin = value; - span.IsSingleMargin = true; - } - } - - //商品类预付金计算 - private static List RunMarginCalculationForCommodity(RunMarginCalculationHelper helper) - { - var resultMap = new Dictionary(); - - //为了算客户角度的一个预付金数值 - helper.ReverseTradeSide(); - - helper.SetFieldsByTradeType(); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - helper.GetTradVolRateDic(out var tradeVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.Item1, - priceProvider = n.Item2, - addVolRateDic = m - })).ToArray(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - - foreach (var item in tradeRiskResult.Results) - { - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value, helper.req.forOtherSide)) - { - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - tempTradeSpan.MaxlossMargin = tempTradeSpan.WorstCastClientPayable; - } - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeSpanInfoOtherSide = (from tradeSpan in req.tradeSpansOtherSide - join - trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var underlyingGroup = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT && O.tradeSpan.IsSingleMargin != true).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - - #endregion - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - MySideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT || O.tradeSpan.IsSingleMargin == true).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - clientSpanNews.Add(clientSpan); - } - - //处理从客户角度的预付金计算(将交易买卖方向反向处理) - var clientGroupsOtherSide = tradeSpanInfoOtherSide.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroupsOtherSide) - { - var underlyingGroup = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = new[] { item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0 }.Min(); - } - var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate); - clientSpan.OtherSideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable); - - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.OtherSideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.OtherSideMargin = Math.Min(clientSpan.OtherSideMargin ?? 0, 0); - - if (HasTwoSideMargin(clientGroup.Key)) - { - clientSpan.WorstCastClientPayable = clientSpan.MySideMargin - clientSpan.OtherSideMargin; - } - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/XiangCaiMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/XiangCaiMarginCalculation.cs deleted file mode 100644 index b5e113a7..00000000 --- a/YLErpDAL/BLL/MarginCalculation/XiangCaiMarginCalculation.cs +++ /dev/null @@ -1,545 +0,0 @@ -using System.Collections; -using YLErp.BLL.Calculation; -using YLErp.DBModels; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules.DataProviderModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 湘财证券 - /// - public class XiangCaiMarginCalculation : MarginCalculationBase - { - public static readonly XiangCaiMarginCalculation Instance; - - static XiangCaiMarginCalculation() - { - Instance = new XiangCaiMarginCalculation(); - } - - private XiangCaiMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var calcTradeList = req.tradeList.ToList(); - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - var mpProvider = helper.GetMarginParamProvider(); - - var upLimitPrices = new ManualPriceProvider(); - var upLimitPricesTwoThirds = new ManualPriceProvider(); - var upLimitPricesOneThird = new ManualPriceProvider(); - var downLimitPrices = new ManualPriceProvider(); - var downLimitPricesTwoThirds = new ManualPriceProvider(); - var downLimitPricesOneThird = new ManualPriceProvider(); - var normalLimitPrices = new ManualPriceProvider(); - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - foreach (var t in req.tradeList) - { - if (upLimitPrices.Contains(t.UnderlyingCode)) - { - continue; - } - if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed)) - { - updownLimit = 0.05; - } - var price = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - price = t.SpotPrice ?? 0;//期初价 - break; - case CalcMarginTypeEnum.None: - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价 - break; - case CalcMarginTypeEnum.EodMargin: - price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价 - break; - } - - //var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider(req.settleDate); - //var spotPrice = eodpriceProvider.GetPrice(t.UnderlyingCode, SettlementTypeEnum.ClosePrice);//收盘价 - if (isFixed) - { - upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + (updownLimit * 2.0 / 3.0)); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + (updownLimit / 3.0)); - - downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - (updownLimit * 2.0 / 3.0)); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - (updownLimit / 3.0)); - } - else - { - upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit))); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit * 2.0 / 3.0)) : (1 - (updownLimit * 2.0 / 3.0)))); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit / 3.0)) : (1 - (updownLimit / 3.0)))); - - downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit))); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit * 2.0 / 3.0)) : (1 + (updownLimit * 2.0 / 3.0)))); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit / 3.0)) : (1 + (updownLimit / 3.0)))); - } - //Normal - normalLimitPrices.SetPrice(t.UnderlyingCode, price); - } - var prices = new[] { - ("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird), - ("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird), - ("normal", normalLimitPrices) - }; - - foreach (var price in prices) - { - - var key = $"{price.Item1}_0"; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: calcTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - volType: "开仓", - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any()) - { - continue; - } - - foreach (var item in tradeRiskResult.Results) - { - var prepayment = item.Trade.StockEqvNotional * (item.Trade.trade_snowball?.PrepaymentRatio ?? 0) * (item.Trade.BuySell == "卖出" ? -1 : 1); - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : (item.ValueResult.Pv - prepayment); - - var client = helper.GetClient(item.Trade); - - if (item.Trade.TradeType == "收益互换" && key != "normal_0" && client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - continue; - } - - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - value = pv * ratio; - } - if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && item.Trade.TradeType == "收益互换") - { - value = pv * ratio; - } - if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && (item.Trade.TradeType == "雪球期权" && item.Trade.trade_snowball.PrepaymentUsed || item.Trade.TradeType == "收益互换")) - { - var initialMargin = item.Trade.TradeType == "雪球期权" ? -prepayment : ((item.Trade.trade_swap.GetMarginRate ?? 0) - (item.Trade.trade_swap.PayMarginRate ?? 0)) * item.Trade.StockEqvNotional; - value = GetComparisonInitialMargin(value, client, item.Trade.TradeType, initialMargin); - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "upTwoThirds_0": - tempTradeSpan.Spv2 = value; break; - case "upOneThird_0": - tempTradeSpan.Spv3 = value; break; - case "normal_0": - if (item.Trade.TradeType == "收益互换" && client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - tempTradeSpan.SetAllSpvAndWorst(value); - } - tempTradeSpan.Spv4 = value; break; - case "down_0": - tempTradeSpan.Spv5 = value; break; - case "downTwoThirds_0": - tempTradeSpan.Spv6 = value; break; - case "downOneThird_0": - tempTradeSpan.Spv7 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - - resultMap[item.Trade.id].UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - using var db = new YLContext(); - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList(); - - var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join um in underlyingList on trade.UnderlyingId equals um.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, um.UnderlyingTypeId, UnderlyingId = um.id }).ToList(); - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var varietyGroups = clientGroup.GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), - Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in varietyGroups) - { - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - var tradeIdList = clientGroup.Where(x => x.UnderlyingTypeId == item.VarietyId).Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - - //单向追保,客户收取预付金为0 - if (!HasTwoSideMargin(item.ClientId) && item.WorstCastClientPayable > 0) - { - item.WorstCastClientPayable = 0; - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - else - { - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - } - - #endregion - } - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = varietyGroups.Sum(g => g.Spv1), - Spv2 = varietyGroups.Sum(g => g.Spv2), - Spv3 = varietyGroups.Sum(g => g.Spv3), - Spv4 = varietyGroups.Sum(g => g.Spv4), - Spv5 = varietyGroups.Sum(g => g.Spv5), - Spv6 = varietyGroups.Sum(g => g.Spv6), - Spv7 = varietyGroups.Sum(g => g.Spv7), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - - clientSpanNews.Add(clientSpan); - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - - /// - /// 根据追保方向判断和初始预付金比较逻辑 - /// - /// - private double GetComparisonInitialMargin(double value, InnerClient client, string tradeType, double initialMargin) - { - if (client.MarginOptionType == (int)MarginOptionEnum.双向追保 || tradeType == "雪球期权") - { - if (initialMargin >= 0) - { - value = Math.Max(initialMargin, value); - } - else - { - value = Math.Min(initialMargin, value); - } - } - else if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - if (initialMargin >= 0) - { - value = Math.Max(initialMargin, Math.Max(value, 0)); - } - else - { - value = Math.Min(initialMargin, Math.Min(value, 0)); - } - } - return value; - } - - public static double TradeMargin(RunMarginCalculationReq req, trade t) - { - var _underlyingDataProvider = new UnderlyingDataProvider(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - var mpProvider = helper.GetMarginParamProvider(); - - var upLimitPrices = new ManualPriceProvider(); - var upLimitPricesTwoThirds = new ManualPriceProvider(); - var upLimitPricesOneThird = new ManualPriceProvider(); - var downLimitPrices = new ManualPriceProvider(); - var downLimitPricesTwoThirds = new ManualPriceProvider(); - var downLimitPricesOneThird = new ManualPriceProvider(); - var normalLimitPrices = new ManualPriceProvider(); - //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 - //if (upLimitPrices.Contains(t.UnderlyingCode)) - //{ - // continue; - //} - if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed)) - { - updownLimit = 0.05; - } - var price = 0.0; - switch (req.CalcMarginType) - { - case CalcMarginTypeEnum.InitialMargin: - price = t.SpotPrice ?? 0;//期初价 - break; - case CalcMarginTypeEnum.None: - var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1)); - price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价 - break; - case CalcMarginTypeEnum.EodMargin: - price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价 - break; - } - if (isFixed) - { - upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + (updownLimit * 2.0 / 3.0)); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + (updownLimit / 3.0)); - - downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - (updownLimit * 2.0 / 3.0)); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - (updownLimit / 3.0)); - } - else - { - upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit))); - upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit * 2.0 / 3.0)) : (1 - (updownLimit * 2.0 / 3.0)))); - upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit / 3.0)) : (1 - (updownLimit / 3.0)))); - - downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit))); - downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit * 2.0 / 3.0)) : (1 + (updownLimit * 2.0 / 3.0)))); - downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit / 3.0)) : (1 + (updownLimit / 3.0)))); - } - //Normal - normalLimitPrices.SetPrice(t.UnderlyingCode, price); - var prices = new[] { - ("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird), - ("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird), - ("normal", normalLimitPrices) - }; - var values = new ArrayList(); - foreach (var p in prices) - { - var key = $"{p.Item1}_0"; - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: new[] { t }, - calcScenario: req.GetCalcScenario(), - priceProvider: p.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - volType: "开仓", - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin); - - if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any()) - { - continue; - } - foreach (var item in tradeRiskResult.Results) - { - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : (item.ValueResult.Pv - item.Trade.StockEqvNotional * (item.Trade.trade_snowball?.PrepaymentRatio ?? 0) * (item.Trade.BuySell == "卖出" ? -1 : 1)); - double value = 0; - if (item.Trade.TradeType == "收益互换") - { - var client = helper.GetClient(item.Trade); - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - value = pv * ratio; - } - else - { - if (!helper.GetSpecialMargin(item.Trade, pv, out value)) - { - var client = helper.GetClient(item.Trade); - var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1; - value = pv * ratio; - } - } - - values.Add(value); - } - } - return (double)values.ToArray().Max(); - } - - private List RunTradeSpanMarginCalculation(RunMarginCalculationReq req) - { - //结果集 - var resultMap = new List(); - - var subTradeList = req.tradeList.Where(x => x.ParentTradeId != 0 && x.IsGroup == 0).GroupBy(x => x.ParentTradeId); - if (subTradeList.Count() > 0) - { - foreach (var item in subTradeList) - { - var spans = RunMarginCalculation(req.Clone(item.ToList())); - var spv1 = spans.Sum(O => O.Spv1 ?? 0); - var spv2 = spans.Sum(O => O.Spv2 ?? 0); - var spv3 = spans.Sum(O => O.Spv3 ?? 0); - var spv4 = spans.Sum(O => O.Spv4 ?? 0); - var spv5 = spans.Sum(O => O.Spv5 ?? 0); - var spv6 = spans.Sum(O => O.Spv6 ?? 0); - var spv7 = spans.Sum(O => O.Spv7 ?? 0); - - var spvArr = new[] { spv1, spv2, spv3, spv4, spv5, spv6, spv7 }; - var maxSpv = spvArr.Max(); - var index = Array.IndexOf(spvArr, maxSpv); - spans.ForEach(x => x.WorstCastClientPayable = new[] { x.Spv1, x.Spv2, x.Spv3, x.Spv4, x.Spv5, x.Spv6, x.Spv7 }[index]); - resultMap.AddRange(spans); - } - } - var singleTradeList = req.tradeList.Where(O => O.ParentTradeId == 0).ToList(); - if (singleTradeList.Count > 0) - { - resultMap.AddRange(RunMarginCalculation(req.Clone(singleTradeList))); - } - return resultMap; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using var db = new YLContext(); - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/XingYeMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/XingYeMarginCalculation.cs deleted file mode 100644 index b4b199ce..00000000 --- a/YLErpDAL/BLL/MarginCalculation/XingYeMarginCalculation.cs +++ /dev/null @@ -1,226 +0,0 @@ -using Qdp.Pricing.Base.Implementations; -using System.Data; -using YLErp.BLL.Calculation; -using YLErp.Commons; -using YLErp.Model.Enum; -using YLErp.Models; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.DataProviderModule; -using YLErp.Modules.MarginModule; - - -namespace YLErp.BLL.MarginCalculation -{ - public class XingYeMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly XingYeMarginCalculation Instance; - - static XingYeMarginCalculation() - { - Instance = new XingYeMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected XingYeMarginCalculation() - { - - } - - /// - /// 完整预付金公式: - /// - /// - /// - /// - /// - /// - public static double TradeMargin(RunMarginCalculationReq req, trade td) - { - var sourcePath = OtcAppContext.MapPath("~/App_Docs"); - var sourceFileName = Path.Combine(sourcePath, "Delta调整系数表.xlsx"); - DataTable dt = new ExcelHelper().ExcelToDataTable(sourceFileName, "", true); - UnderlyingDataProvider _underlyingDataProvider = new UnderlyingDataProvider(); - var reqConv = new CalculateRisksForTradesReq - { - valueDate = req.settleDate, - tradeList = new List { td }, - priceProvider = req.PriceProvider, - pricingRequest = PricingRequest.Pv | PricingRequest.Delta | PricingRequest.Gamma, - addVolRateDic = null, - volType = req.volType, - isUseTradeVol = PS.Config.IsTradeVol, - PreciseTimeMode = req.CalcMarginType != Enums.CalcMarginTypeEnum.EodMargin, - isAddVolPercent = true, - overrideVolsForTrade = null, - isMarginCalc = true - }; - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.EodMargin) - { - reqConv.calcScenario = Enums.CalcScenarioEnum.EodSettlement; - } - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(reqConv); - - double ITM = 0; - double Margin_part = 0; - double Margin_part1 = 0; - double Margin_part2 = 0; - double maxMarginRate = 0; - new EodPriceProvider(req.settleDate, false).TryGetEodPrice(td.UnderlyingCode, out var eodPrice); - double Delta = -1; - double coefficient = 0; - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - var udmA = new underlying_manager(); - var udmB = new underlying_manager(); - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - mpProvider.TryGetMarginRate(td.UnderlyingCode, out var marginRate); - - if (eodPrice == null) - { - eodPrice = new EodPrice(); - eodPrice.SettlePrice = td.SpotPrice ?? 0; - } - - if (td.TradeType == "收益互换") - { - Delta = 1; - ITM = 0; - } - else - { - if (td.OptionType == "看涨") - { - ITM = (eodPrice.SettlePrice - (td.IsMoneynessOption == "是" ? (td.Strike.Value * td.SpotPrice.Value) : td.Strike.Value)); - ITM = ITM > 0 ? ITM : 0; - } - else - { - ITM = ((td.IsMoneynessOption == "是" ? (td.Strike.Value * td.SpotPrice.Value) : td.Strike.Value) - eodPrice.SettlePrice); - ITM = ITM > 0 ? ITM : 0; - } - Delta = Math.Round((tradeRiskResult.Results.Where(x => x.Trade.id == td.id).FirstOrDefault().ValueResult.Delta / td.Notional), 2); - } - - if (td.TradeType == "收益互换" || (td.ExerciseMode == "European" && string.IsNullOrEmpty(td.StructureType))) - { - //预付金_part1 = ((ABS(Delta) * VLOOKUP(ABS(ROUND(Delta,2)), Delta调整系数表, 2, FALSE) - //* 标的结算价 * ABS(标的规模) * 交易所预付金率) + 实值部分 * ABS(标的规模) ) - DataRow[] drs2 = dt.Select("Delta='" + Math.Abs(Delta) + "'", "Delta desc");//维持系数 - if (drs2.Count() > 0) - coefficient = Convert.ToDouble(drs2[0]["维持系数"]); - Margin_part1 = (Math.Abs(Delta) * coefficient - * SettlePrice(req.settleDate, td) * Math.Abs(td.TradeAmount) * marginRate); - } - else if (udm.CommodityCode == "组合标的" && td.TradeType == "收益互换") - { - //1*I2101-1*I2009 - var UnderlyingCode = td.trade_swap.GetUnderlyingCode == null ? td.trade_swap.PayUnderlyingCode : td.trade_swap.GetUnderlyingCode; - var UnderlyingCodeS = UnderlyingCode.Split(new char[] { '-', '+' }).ToList(); //多字节切割 - //new EodPriceProvider(req.settleDate, false).TryGetEodPrice(UnderlyingCodeS[0].Split('*')[1], out eodPriceA); - //new EodPriceProvider(req.settleDate, false).TryGetEodPrice(UnderlyingCodeS[1].Split('*')[1], out eodPriceB); - //udmA = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCodeS[0].Split('*')[1]); - //udmB = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCodeS[1].Split('*')[1]); - - foreach (var code in UnderlyingCodeS) - { - if (code.Contains("*")) - { - udm = DataCacheProvider.GetUnderlyingDataSource().GetData(code.Split('*')[1]); - if (udm.MarginRate != null) - { - maxMarginRate = maxMarginRate > udm.MarginRate.Value ? maxMarginRate : udm.MarginRate.Value; - } - } - } - //预付金_part1 = (标的A收盘价 - 标的B收盘价) * ABS(标的规模) * 交易所预付金率 * 0.9 - Margin_part1 = (eodPrice.ClosePrice) * Math.Abs(td.TradeAmount) * maxMarginRate * 0.9; - } - else if (udm.CommodityCode == "组合标的" && td.ExerciseMode == "European") - { - var UnderlyingCode = td.trade_swap.GetUnderlyingCode == null ? td.trade_swap.PayUnderlyingCode : td.trade_swap.GetUnderlyingCode; - var UnderlyingCodeS = UnderlyingCode.Split(new char[] { '-', '+' }).ToList(); //多字节切割 - //new EodPriceProvider(req.settleDate, false).TryGetEodPrice(UnderlyingCodeS[0].Split('*')[1], out eodPriceA); - //new EodPriceProvider(req.settleDate, false).TryGetEodPrice(UnderlyingCodeS[1].Split('*')[1], out eodPriceB); - //udmA = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCodeS[0].Split('*')[1]); - //udmB = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCodeS[1].Split('*')[1]); - - foreach (var code in UnderlyingCodeS) - { - if (code.Contains("*")) - { - udm = DataCacheProvider.GetUnderlyingDataSource().GetData(code.Split('*')[1]); - if (udm.MarginRate != null) - { - maxMarginRate = maxMarginRate > udm.MarginRate.Value ? maxMarginRate : udm.MarginRate.Value; - } - } - } - //预付金_part1 = (标的A收盘价 + 标的B收盘价)/2 * ABS(标的规模) * 交易所预付金率 - Margin_part1 = ((eodPrice.ClosePrice) / 2) * Math.Abs(td.TradeAmount) * maxMarginRate; - } - //预付金_part2 = 期权实值部门 * ABS(标的规模) - - Margin_part2 = ITM * Math.Abs(td.TradeAmount); - - Margin_part = Margin_part2 + Margin_part1; - return Margin_part; - } - - /// - /// 标的结算价的公式为: - /// If 期权类别 = “亚式”: - /// If 当前估值日期 <= 亚式采价起始日: - /// 标的结算价 = 当日收盘价 - /// Else: - /// 标的结算价 = (标的前结算价*(已采价期-1) + 当日收盘价* (剩余天数+1))/(已采价期+剩余天数) - /// Elseif 期权类别 = “价差欧式” OR 期权类别 = “价差互换” OR "欧式": - /// 标的结算价 = 当日结算价 - /// - /// - /// - /// - private static double SettlePrice(DateTime settleDate, trade td) - { - EodPrice eodPrice = null; - double settlePrice = 0; - new EodPriceProvider(settleDate, false).TryGetEodPrice(td.UnderlyingCode, out eodPrice); - if (eodPrice == null) - { - eodPrice = new EodPrice(); - eodPrice.SettlePrice = td.SpotPrice ?? 0; - } - var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); - if (td.TradeType == "亚式期权") - { - if (settleDate <= td.trade_asian_option.AveragingPeriodStartDate) - { - return eodPrice.ClosePrice; - } - else - { - TimeSpan sp = Convert.ToDateTime(settleDate).Subtract(td.trade_asian_option.AveragingPeriodStartDate.Value); - TimeSpan sp1 = Convert.ToDateTime(td.ExerciseDate.Value).Subtract(settleDate); - return (eodPrice.SettlePrice * (sp.Days - 1) + eodPrice.ClosePrice * (sp1.Days + 1)) / (sp.Days + sp1.Days); - } - } - else if (udm.CommodityCode == "组合标的" && td.ExerciseMode == "European") - { - return eodPrice.SettlePrice; - } - else if (udm.CommodityCode == "组合标的" && td.TradeType == "收益互换") - { - return eodPrice.SettlePrice; - } - else if (td.ExerciseMode == "European") - { - return eodPrice.SettlePrice; - } - else - return settlePrice; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/XingZhengMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/XingZhengMarginCalculation.cs deleted file mode 100644 index 05320e05..00000000 --- a/YLErpDAL/BLL/MarginCalculation/XingZhengMarginCalculation.cs +++ /dev/null @@ -1,494 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Commons; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.Modules; -using YLErp.Modules.MarginModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 兴证预付金计算 - /// - public class XingZhengMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly XingZhengMarginCalculation Instance; - - static XingZhengMarginCalculation() - { - Instance = new XingZhengMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected XingZhengMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var underlyingCodes = req.tradeList.Select(t => t.UnderlyingCode).ToHashSet(); - var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit); - - helper.SetFieldsByTradeType(); - - var addVolRateDic = req.tradeList.Select(t => - { - var volRate = 0d; - var client = helper.GetClient(t); - if (client?.QuestionnaireScore == null || client.QuestionnaireScore < 60) - { - volRate = 0.03; - } - return (t.id, volRate); - }).Where(d => d.volRate > 0).ToDictionary(d => d.id, d => d.volRate); - - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - - var userIdNew = UniqueTimeId.Get().ToString(); - - var calcTradeList = req.tradeList.Where(t => t.TradeType != "雪球期权").ToArray(); - var prices = new[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - - foreach (var price in prices) - { - var key = price.Item1; - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: price.Item2, addVolRateDic: addVolRateDic, overrideVols: null, pricingRequest: QdpPricingRequest.BASIC_PRICING); - calcReq.tradeList = calcTradeList; - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - foreach (var item in tradeRiskResult.Results) - { - var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv; - - var hasSpecialMargin = helper.GetSpecialMargin(item.Trade, pv, out var value); - if (!hasSpecialMargin) - { - var client = helper.GetClient(item.Trade); - value = pv * (client == null ? 1d : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 0); - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - tempTradeSpan.UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode); - } - - switch (key) - { - case "up": - tempTradeSpan.Spv1 = value; - break; - case "down": - tempTradeSpan.Spv2 = value; - break; - case "normal": - tempTradeSpan.Spv = value; - tempTradeSpan.Delta = item.ValueResult.Delta; - mpProvider.TryGetMarginRate(item.ValueResult.UnderlyingCode, out var marginRate); - tempTradeSpan.DeltaMargin = (tempTradeSpan.Delta * tempTradeSpan.UnderlyingPrice * marginRate) ?? 0; - break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - } - } - } - - var snowballMargin = new SnowballMarginService(); - - foreach (var td in req.tradeList) - { - if (td.TradeType != "雪球期权") - { - continue; - } - - var um = helper.GetUnderlying(td.UnderlyingCode); - var spotPrice = req.PriceProvider.GetPrice(td.UnderlyingCode); - - trade_span tempTradeSpan; - resultMap[td.id] = tempTradeSpan = helper.CreateTradeSpan(td, um); - tempTradeSpan.UnderlyingPrice = spotPrice; - - var margin = snowballMargin.CalcMargin(req.settleDate, td, td.trade_snowball, um, spotPrice); - - tempTradeSpan.Spv1 = tempTradeSpan.Spv2 - = tempTradeSpan.Spv3 = tempTradeSpan.Spv4 - = tempTradeSpan.WorstCastClientPayable = margin; - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - using (var db = DbContextFactory.GetYLDbContext()) - { - //删除 - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)) - .Select(n => new { n.id, n.ClientId, n.UnderlyingId }).ToList(); - - var tradeSpanInfos = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfos.GroupBy(t => t.trade.ClientId); - - var clientIds = clientGroups.Select(n => n.Key).ToArray(); - - var dbTradeSpans = db.trade_span.Where(x => x.ValueDate == req.settleDate && x.ClientId != null && clientIds.Contains(x.ClientId.Value)).ToArray(); - - foreach (var clientGroup in clientGroups) - { - #region Span Margin Method - - var client = DataCacheProvider.GetClientDataSource().GetData(clientGroup.Key); - - var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = -t.Sum(g => g.tradeSpan.Spv1), - Spv2 = -t.Sum(g => g.tradeSpan.Spv2), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - DeltaMargin = -t.Sum(g => g.tradeSpan.DeltaMargin) - }).ToList(); - - foreach (var item in underlyingGroup) - { - item.WorstCastClientPayable = Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = dbTradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - - #endregion - - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable.Value, 0); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保) - { - item.WorstCastClientPayable = Math.Max(item.WorstCastClientPayable.Value, 0); - } - } - - #endregion - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - DeltaMargin = underlyingGroup.Sum(g => g.DeltaMargin), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - - if (clientSpan.WorstCastClientPayable > clientSpan.DeltaMargin) - { - clientSpan.WorstCastClientPayable = clientSpan.DeltaMargin; - - //取delta预付金作为最终预付金 - var tradeSpansUpdate = dbTradeSpans.Where(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList(); - - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - } - - if (!HasTwoSideMargin(clientGroup.Key)) - { - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - } - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (tradeMargin != null && tradeMargin.FirstOrDefault() != null && trade.BuySell == "买入") - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - var mpProvider = new MarginParamProvider(OptUserInfo.SystemUser, valuedateBLL.ValueDate.Date).Initialize(new List { trade.UnderlyingCode }.ToHashSet(), MarginParamTypeEnum.MarginRate); - mpProvider.TryGetMarginRate(trade.UnderlyingCode, out var marginRate); - var deltaMargin = Math.Abs(tradeMargin.FirstOrDefault().Delta ?? 0) * (trade.SpotPrice ?? 0) * marginRate; - - //单笔交易的初始预付金 = 维持预付金 × 105%(初始预付金是为避免客户频繁转账,在盘中对当天收盘时的维持预付金的预估,该比例不低于105%,可根据不同客户情况进行调整) - var client = GetClientInfo(trade.ClientId); - var ratio = client == null ? 1 : (client.Ratio1 ?? 1); - return (margin > deltaMargin ? margin : deltaMargin) * ratio; - } - } - - return 0.0; - } - - /// - /// 雪球期权预付金计算 - /// - class SnowballMarginService : YLBaseService - { - const string MK_MarginSpot1 = "MarginSpot1"; - const string MK_MarginSpot2 = "MarginSpot2"; - - public SnowballMarginService() : base(OptUserInfo.SystemUser) - { - - } - - public double CalcMargin(DateTime settleDate, OtcTradeBase td, trade_snowball snowball, underlying_manager um, double spotPrice) - { - if (GetObSpots(td, out var spot1, out var spot2)) - { - var obDates = GetObDates(snowball.ObservationDates, td.TradeDate.Value, settleDate); - - if (td.id > 0 && !IsCalcEnable(obDates, um, spot1)) - { - return 0; - } - - var marginRate = 1d; - - if (spotPrice < spot2) - { - var perUnit = (td.SpotPrice ?? 0) * 0.05;//不考虑为0的情况了太累 - marginRate += Math.Floor((spot2 - spotPrice) / perUnit); - } - - return marginRate * td.StockEqvNotional * 0.05; - } - - return 0; - } - - //获取是否追保处理 - private bool IsCalcEnable(List obDates, underlying_manager um, double spot1) - { - if (ConsGlobal.InstrumentType.CalcTypeIsFutures(um.UnderlyingCode) || ConsGlobal.InstrumentType.IsCommoditySpot(um.UnderlyingCode)) - { - var query = from t in DbContext.eod_commodity_future_price - where obDates.Contains(t.ValueDate) - && t.UnderlyingCode == um.UnderlyingCode && t.SettlePrice < spot1 - select t; - return query.Any(); - } - else - { - var query = from t in DbContext.eod_stock_price - where obDates.Contains(t.ValueDate) - && t.UnderlyingCode == um.UnderlyingCode && t.ClosePrice < spot1 - select t; - return query.Any(); - } - } - - //获取追保价格 - private bool GetObSpots(OtcTradeBase td, out double spot1, out double spot2) - { - spot1 = 0; - spot2 = 0; - - TradeMetaDto[] metas; - - if (td.MetaDic.ContainsKey(MK_MarginSpot1)) - { - metas = new[] { new TradeMetaDto { MetaKey = MK_MarginSpot1, MetaValue = td.MetaDic[MK_MarginSpot1] } }; - - if (td.MetaDic.ContainsKey(MK_MarginSpot2)) - { - metas = new[] { - metas[0], - new TradeMetaDto { MetaKey = MK_MarginSpot2, MetaValue = td.MetaDic[MK_MarginSpot2] } - }; - } - } - else if (td.id > 0) - { - var metaKeys = new[] { MK_MarginSpot1, MK_MarginSpot2 }; - - metas = DbContext.TradeMeta.Where(n => n.TradeId == td.id && metaKeys.Contains(n.MetaKey)) - .Select(n => new TradeMetaDto { MetaKey = n.MetaKey, MetaValue = n.MetaValue }).ToArray(); - } - else - { - return false; - } - - if (!metas.Any()) - { - return false; - } - - foreach (var m in metas) - { - if (MK_MarginSpot1.Equals(m.MetaKey, StringComparison.OrdinalIgnoreCase)) - { - NumberHelper.TryParse(m.MetaValue, out spot1, out _); - } - else - { - NumberHelper.TryParse(m.MetaValue, out spot2, out _); - } - } - - if (td.IsMoneynessOption == "是") - { - spot1 *= td.SpotPrice ?? 0; - spot2 *= td.SpotPrice ?? 0; - } - - if (spot1 < 1e-2) - { - return false; - } - - return true; - } - - //获取敲入观察日列表 - private List GetObDates(string ObservationDates, DateTime startDate, DateTime endDate) - { - var dateList = new List(); - - if (string.IsNullOrWhiteSpace(ObservationDates)) - { - var obDate = startDate; - - for (var i = 0; i < 10000; i++) - { - obDate = QdpCalendarHelper.GetNonHoliday(obDate); - - if (obDate > endDate) - { - break; - } - else - { - dateList.Add(obDate); - } - - obDate = obDate.AddDays(1); - } - } - else - { - var obStrs = ObservationDates.Split(','); - - foreach (var str in obStrs) - { - if (DateTime.TryParse(str, out var obDate) && obDate >= startDate && obDate <= endDate) - { - obDate = QdpCalendarHelper.GetNonHoliday(obDate); - dateList.Add(obDate); - } - } - } - - return dateList; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ZhaoZhengMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ZhaoZhengMarginCalculation.cs deleted file mode 100644 index 41e03f94..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ZhaoZhengMarginCalculation.cs +++ /dev/null @@ -1,389 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Helpers; -using YLErp.Modules; -using YLErp.Modules.PricingModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 招证 - /// - public class ZhaoZhengMarginCalculation : MarginCalculationBase - { - public static readonly ZhaoZhengMarginCalculation Instance; - - static ZhaoZhengMarginCalculation() - { - Instance = new ZhaoZhengMarginCalculation(); - } - - protected ZhaoZhengMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var result = new List(); - - if (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin) - { - var swapList = req.tradeList.Where(O => O.TradeType == "收益互换"); - RunMarginCalculationHelper helper = null; - foreach (var item in swapList) - { - helper ??= new RunMarginCalculationHelper(req, _underlyingDataProvider); - var clientRatio = helper.GetClient(item)?.Ratio1 ?? 1.0; - var tradeSpan = new trade_span(); - var ratio = item.trade_swap.GetSwapRate - item.trade_swap.PaySwapRate; - logger.Info($"互换初始预付金:tradeId:{item.id} 名义本金 * (收取预付金比例 - 支付预付金比例) * 客户初始预付金系数"); - logger.Info($"互换初始预付金:tradeId:{item.id} {item.OriginalStockEqvNotional} * ({item.trade_swap.GetSwapRate} - {item.trade_swap.PaySwapRate}) * {clientRatio}"); - tradeSpan.SetAllSpvAndWorst((item.OriginalStockEqvNotional ?? 0) * ratio * clientRatio); - result.Add(tradeSpan); - } - var optionList = req.tradeList.Where(O => O.TradeType != "收益互换"); - req.tradeList = optionList.ToList(); - result.AddRange(calcPositionMargin(req)); - return result; - } - else - { - return calcPositionMargin(req); - } - } - - private List calcPositionMargin(RunMarginCalculationReq req) - { - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var resultMap = new Dictionary(); - - helper.SetFieldsByTradeType(); - var priceArr = helper.GetUpDownLimitPrices(6); - //var prices = priceArr.Select(O=> new (string key, IPriceProvider priceProvider){ ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - var index = 0; - var loops = priceArr.Select(n => - { - index++; - return new - { - pricekey = $"P{index}", - priceProvider = n, - }; - }).ToArray(); - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: null, overrideVols: null, pricingRequest: QdpPricingRequest.BASIC_PRICING); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - var key = $"{loop.pricekey}"; - - foreach (var item in tradeRiskResult.Results) - { - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "P1": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格1 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv1 = item.ValueResult.Pv; - break; - case "P2": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格2 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv2 = item.ValueResult.Pv; - break; - case "P3": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格3 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv3 = item.ValueResult.Pv; - break; - case "P4"://这里是现价计算的,所以同时保存一下Delta - tempTradeSpan.Spv4 = item.ValueResult.Pv; - var marginRatio = helper.GetMarginParamProvider().GetMarginRate(item.Trade.UnderlyingCode) ?? 1; - tempTradeSpan.DeltaMargin = item.ValueResult.DeltaCash * marginRatio; - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格4 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv} Delta = {item.ValueResult.Delta} DeltaCash = {item.ValueResult.DeltaCash} 品种最低预付金率 = Delta * Price * 品种最低预付金比例 = {marginRatio} DeltaMargin = {tempTradeSpan.DeltaMargin}"); - break; - case "P5": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格5 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv5 = item.ValueResult.Pv; - break; - case "P6": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格6 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv6 = item.ValueResult.Pv; - break; - case "P7": - logger.Info($"期权预付金:tradeId:{item.Trade.id} 价格7 = {loop.priceProvider.GetPrice(item.Trade.UnderlyingCode)} Pv = {item.ValueResult.Pv}"); - tempTradeSpan.Spv7 = item.ValueResult.Pv; - break; - } - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - - if (tempTradeSpan.WorstCastClientPayable > 0) - { - var clientInfo = helper.GetClient(item.Trade); - var clientRatio = (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin ? clientInfo?.Ratio1 : clientInfo?.Ratio) ?? 1.0; - if (key == "P7") - { - var ss = Math.Max(tempTradeSpan.WorstCastClientPayable ?? 0, tempTradeSpan.DeltaMargin ?? 0) * clientRatio; - logger.Info($"期权预付金:tradeId:{item.Trade.id} 预付金 = MaxPv > 0 Max(MaxPv, DeltaMargin) * 客户预付金率"); - logger.Info($"期权预付金:tradeId:{item.Trade.id} {ss} = {tempTradeSpan.WorstCastClientPayable} > 0 Max({tempTradeSpan.WorstCastClientPayable}, {tempTradeSpan.DeltaMargin}) * {clientRatio}"); - } - tempTradeSpan.WorstCastClientPayable = Math.Max(tempTradeSpan.WorstCastClientPayable ?? 0, tempTradeSpan.DeltaMargin ?? 0) * clientRatio; - } - else - { - if (key == "P7") - { - logger.Info($"期权预付金:tradeId:{item.Trade.id} 预付金 = MaxPv <= 0"); - } - tempTradeSpan.WorstCastClientPayable = 0; - } - } - } - } - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - // 手动维护的预付金VarietyId是null,合计的时候需要排除掉,最后再加进来 - var varietyGroup = clientGroup.Where(O => O.tradeSpan.VarietyId > 0).GroupBy(t => t.tradeSpan.VarietyId ?? 0).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), - Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), - DeltaMargin = -Math.Abs(t.Sum(g => g.tradeSpan.DeltaMargin ?? 0)), - PositionWinLoss = t.Sum(g => g.tradeSpan.PositionWinLoss) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var varietyInfo in varietyGroup) - { - var tradeSpanIds = clientGroup.Where(O => O.tradeSpan.VarietyId == varietyInfo.VarietyId).Select(x => x.tradeSpan.id); - var tradeSpansUpdate = db.trade_span.Where(x => tradeSpanIds.Contains(x.id)).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeSpanIds.Contains(x.id)).ToList(); - - varietyInfo.SetWorstCastClientPayableMin(); - - if (varietyInfo.WorstCastClientPayable >= 0 || varietyInfo.WorstCastClientPayable.Value < (varietyInfo.DeltaMargin ?? 0)) - { - if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (varietyInfo.WorstCastClientPayable == varietyInfo.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - } - else - { - varietyInfo.WorstCastClientPayable = varietyInfo.DeltaMargin ?? 0; - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin); - } - - if (varietyInfo.WorstCastClientPayable < 0) - { - var clientRatio = 1.0; - var clientLevelId = DataCacheProvider.GetClientDataSource().GetData(varietyInfo.ClientId).LevelId; - if (clientLevelId > 0) - { - clientRatio = DataCacheProvider.GetClientLevelDataSource().GetData(clientLevelId ?? 0).Ratio ?? 1.0; - } - varietyInfo.WorstCastClientPayable *= clientRatio; - } - else - { - varietyInfo.WorstCastClientPayable = varietyInfo.TwoSideMargin = 0; - } - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = varietyGroup.Sum(g => g.Spv1), - Spv2 = varietyGroup.Sum(g => g.Spv2), - Spv3 = varietyGroup.Sum(g => g.Spv3), - Spv4 = varietyGroup.Sum(g => g.Spv4), - Spv5 = varietyGroup.Sum(g => g.Spv5), - Spv6 = varietyGroup.Sum(g => g.Spv6), - Spv7 = varietyGroup.Sum(g => g.Spv7), - DeltaMargin = varietyGroup.Sum(g => g.DeltaMargin), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroup.Sum(g => g.WorstCastClientPayable), - MySideMargin = varietyGroup.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = varietyGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.trade.MarginType != DBModels.Enums.MarginTypeEnum.DEFAULT).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.Spv5 += singleMarginTrade.Sum(O => O.Spv5 * (-1)); - clientSpan.Spv6 += singleMarginTrade.Sum(O => O.Spv6 * (-1)); - clientSpan.Spv7 += singleMarginTrade.Sum(O => O.Spv7 * (-1)); - clientSpan.DeltaMargin += singleMarginTrade.Sum(O => O.DeltaMargin * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - - //交易员不支付预付金 - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - //手动维护的预付金,不参与以上算法 - var maMargin = clientGroup.Where(O => O.tradeSpan.VarietyId == null).Sum(t => t.tradeSpan.WorstCastClientPayable * (-1)); - clientSpan.WorstCastClientPayable += maMargin; - clientSpan.MySideMargin += maMargin; - - clientSpanNews.Add(clientSpan); - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - db.SaveChanges(); - } - return req.tradeSpans; - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using var db = new YLContext(); - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - if (req.trade.ParentTradeId > 0) - { - marginReq.tradeList.AddRange(db.trade.Where(x => x.ParentTradeId == req.trade.ParentTradeId && x.id != req.realTradeId).ToList()); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - - double margin; - if (req.trade.IsGroup == 1) - { - margin = (double)tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0); - } - else if (req.trade.ParentTradeId > 0) - { - PriceCalcService.GroupSpansCalc(tradeMargin); - margin = (double)(tradeMargin.FirstOrDefault(O => O.TradeId == req.trade.id)?.WorstCastClientPayable ?? 0); - } - else - { - margin = (double)(tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - } - - return margin; - } - return 0.0; - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ZheQiMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ZheQiMarginCalculation.cs deleted file mode 100644 index 53d9a791..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ZheQiMarginCalculation.cs +++ /dev/null @@ -1,409 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.BLL.Eod; -using YLErp.BLL.MarginCalculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Modules.DataProviderModule; -using YLErp.QdpModule; - -namespace YLErp.BLL -{ - /// - /// 浙期 - /// - public class ZheQiMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly ZheQiMarginCalculation Instance; - - static ZheQiMarginCalculation() - { - Instance = new ZheQiMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected ZheQiMarginCalculation() - { - - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var resultMap = new Dictionary(); - - helper.SetFieldsByTradeType(); - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - helper.GetTradVolRateDic(out var tradeVolRateDic); - - var vols = new[] { null, tradeVolRateDic }; - var prices = new (string key, IPriceProvider priceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - var loops = prices.SelectMany(n => vols.Select(m => new - { - pricekey = n.key, - priceProvider = n.priceProvider, - addVolRateDic = m - })).ToArray(); - var uProvider = new UnderlyingDataProvider(); - - foreach (var loop in loops) - { - var calcReq = helper.GetCalculateRisksForTradesReq(priceProvider: loop.priceProvider, addVolRateDic: loop.addVolRateDic, overrideVols: null, pricingRequest: QdpPricingRequest.BASIC_PRICING); - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq); - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - var key = $"{loop.pricekey}_{(loop.addVolRateDic == null ? 0 : 1)}"; - if (key == "normal_1") continue; - - foreach (var item in tradeRiskResult.Results) - { - // 远期掉期是否走现货算法 - bool isStock = false; - if (item.Trade.TradeType == "远期") - { - isStock = uProvider.GetUnderlying(item.Trade.UnderlyingCode).UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommoditySpot; - if (!isStock && !string.IsNullOrWhiteSpace(item.Trade.BasisUnderlyingCode)) - { - isStock = uProvider.GetUnderlying(item.Trade.BasisUnderlyingCode).UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommoditySpot; - } - } - if (isStock && key != "normal_0") - { - continue; - } - - var pv = item.ValueResult.Pv; - var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0; - if (!helper.GetSpecialMargin(item.Trade, pv, out var value, helper.req.forOtherSide)) - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - } - - switch (key) - { - case "up_0": - tempTradeSpan.Spv1 = value; break; - case "up_1": - tempTradeSpan.Spv2 = value; break; - case "normal_0": - if (isStock) - { - // 现货预付金: - // 普通掉期开仓固定 15%, - // 基差掉期开仓预付金固定 10% - // 持仓预付金观察: - // 1. -5%*名义本金<单笔持仓盈亏<0, - // 一般掉期持仓预付金为15% - // 基差掉期持仓预付金为10% - // 2. 单笔持仓盈亏<-5%*名义本金 - // 一般掉期持仓预付金为: -单笔持仓盈亏+15% - // 基差掉期持仓预付金为: -单笔持仓盈亏+10% - var config = valuedateBLL.SystemDate.ConfigInfoData; - if (helper.req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - double rate = string.IsNullOrWhiteSpace(item.Trade.BasisUnderlyingCode) ? config.NormalSwapInitMarginRatio : config.BasisSwapInitMarginRatio; - rate /= 100; - value = rate * item.Trade.StockEqvNotional; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = 普通掉期开仓固定 15%,基差掉期开仓预付金固定 10%"); - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = {rate} * {item.Trade.StockEqvNotional}"); - } - else - { - double rate = string.IsNullOrWhiteSpace(item.Trade.BasisUnderlyingCode) ? config.NormalSwapMarginRatio : config.BasisSwapMarginRatio; - rate /= 100; - var tradePrice = (item.Trade.TradePrice * item.Trade.Notional / item.Trade.OriginalNotional) ?? 0; - double pnl = item.ValueResult.Pv + tradePrice; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber} pnl = Pv + tradePrice"); - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber} pnl = {item.ValueResult.Pv} + {tradePrice}"); - - // 客户持仓盈亏 - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = 1. -5%*名义本金<单笔持仓盈亏<0,\r\n一般掉期持仓预付金为15%,\r\n基差掉期持仓预付金为10%\r\n2. 单笔持仓盈亏<-5%*名义本金,一般掉期持仓预付金为:\r\n-单笔持仓盈亏+15%,\r\n基差掉期持仓预付金为:\r\n-单笔持仓盈亏+10%"); - double clientpnl = -pnl; - double rateStockEqvNotional = config.StockEqvNotionalRatio / 100d * item.Trade.StockEqvNotional; - if (rateStockEqvNotional < clientpnl && clientpnl < 0) - { - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber} if({config.StockEqvNotionalRatio / 100d} * {item.Trade.StockEqvNotional} < {clientpnl} && {clientpnl} > 0)"); - value = rate * item.Trade.StockEqvNotional; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = {rate} * {item.Trade.StockEqvNotional}"); - } - else if (clientpnl < rateStockEqvNotional) - { - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber} if({clientpnl} < {rateStockEqvNotional} > 0)"); - value = -clientpnl + rate * item.Trade.StockEqvNotional; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = -{clientpnl} + {rate} * {item.Trade.StockEqvNotional}"); - } - else - { - value = rate * item.Trade.StockEqvNotional; - logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = {rate} * {item.Trade.StockEqvNotional}"); - } - } - tempTradeSpan.SetAllSpvAndWorst(value); - } - else - { - var um = uProvider.GetUnderlying(item.Trade.UnderlyingCode); - var variety = uProvider.GetVariety(item.Trade.UnderlyingCode); - var marginRate = ((um?.MarginRate ?? 0) > 0 ? um.MarginRate : variety?.Margin) ?? 0; - double deltaCash = 0; - if ((item.Trade.BuySell == "买入" && item.Trade.OptionType == "看涨") || (item.Trade.BuySell == "卖出" && item.Trade.OptionType == "看跌")) - { - deltaCash = Math.Abs(item.ValueResult.DeltaCash); - } - else - { - deltaCash = -Math.Abs(item.ValueResult.DeltaCash); - } - value = deltaCash * marginRate * clientRatio; - tempTradeSpan.DeltaMargin = value; - tempTradeSpan.PositionWinLoss = EodOperationBase.GetPositionPnl(item.ValueResult.Pv, item.Trade.TradePrice ?? 0.0, item.Trade.Notional, item.Trade.OriginalNotional ?? 0, item.Trade.BuySell); - } - break; - case "down_0": - tempTradeSpan.Spv3 = value; break; - case "down_1": - tempTradeSpan.Spv4 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - - if (tempTradeSpan.WorstCastClientPayable > 0) - { - tempTradeSpan.WorstCastClientPayable = Math.Max(tempTradeSpan.WorstCastClientPayable.Value, Math.Abs(tempTradeSpan.DeltaMargin ?? 0) + (tempTradeSpan.PositionWinLoss ?? 0)); - } - else - { - tempTradeSpan.WorstCastClientPayable = 0; - } - } - } - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - - //获取收盘日那天对应的预付金模板 - var tradeTemplates = db.trade_margin_template.AsNoTracking().Where(t => tradeIds.Contains(t.TradeId) && t.ValueDate <= req.settleDate); - var groupQuery = from tt in tradeTemplates - group tt by tt.TradeId into tts - select new - { - TradeId = tts.Key, - ValueDate = tts.Max(n => n.ValueDate) - }; - var groupTemplates = from gq in groupQuery - join tt in tradeTemplates - on new { gq.TradeId, gq.ValueDate } equals new { tt.TradeId, tt.ValueDate } - select tt; - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradetemplate in groupTemplates on tradeSpan.TradeId equals tradetemplate.TradeId into templates - from tradetemplate in templates.DefaultIfEmpty() - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan, tradetemplate }).ToList(); - - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var spans = req.tradeSpansOtherSide != null - ? req.tradeSpansOtherSide.Where(n => n != null).ToArray() : Enumerable.Empty(); - var tradeSpanInfoOtherSide = (from tradeSpan in spans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var underlyingGroup = clientGroup.Where(O => O.tradeSpan.IsSingleMargin != true).GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - DeltaMargin = t.Sum(g => g.tradeSpan.DeltaMargin) * (-1), - PositionWinLoss = t.Sum(g => g.tradeSpan.PositionWinLoss) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - foreach (var item in underlyingGroup) - { - var tradeSpanIds = clientGroup.Where(O => O.tradeSpan.IsSingleMargin != true).Select(x => x.tradeSpan.id); - var tradeSpansUpdate = db.trade_span.Where(x => tradeSpanIds.Contains(x.id) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeSpanIds.Contains(x.id) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList(); - - var minSpv = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - if (minSpv < 0) - { - item.WorstCastClientPayable = Math.Max(Math.Abs(minSpv), Math.Abs(item.DeltaMargin ?? 0) - (item.PositionWinLoss ?? 0)) * (-1); - item.TwoSideMargin = item.WorstCastClientPayable; - - if (Math.Abs(minSpv) > Math.Abs(item.DeltaMargin ?? 0) - (item.PositionWinLoss ?? 0)) - { - //更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = (item.DeltaMargin > 0 ? -(x.DeltaMargin ?? 0) : (x.DeltaMargin ?? 0)) + (x.PositionWinLoss ?? 0)); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = (item.DeltaMargin > 0 ? -(x.DeltaMargin ?? 0) : (x.DeltaMargin ?? 0)) + (x.PositionWinLoss ?? 0)); - } - } - else - { - item.WorstCastClientPayable = 0; - item.TwoSideMargin = 0; - - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - } - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = underlyingGroup.Sum(g => g.Spv1), - Spv2 = underlyingGroup.Sum(g => g.Spv2), - Spv3 = underlyingGroup.Sum(g => g.Spv3), - Spv4 = underlyingGroup.Sum(g => g.Spv4), - DeltaMargin = underlyingGroup.Sum(g => g.DeltaMargin), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable), - MySideMargin = underlyingGroup.Sum(g => g.WorstCastClientPayable), - TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - //单笔预付金算法的交易不参与品种轧差; - var singleMarginTrade = clientGroup.Where(O => O.tradeSpan.IsSingleMargin == true).Select(O => O.tradeSpan); - clientSpan.Spv1 += singleMarginTrade.Sum(O => O.Spv1 * (-1)); - clientSpan.Spv2 += singleMarginTrade.Sum(O => O.Spv2 * (-1)); - clientSpan.Spv3 += singleMarginTrade.Sum(O => O.Spv3 * (-1)); - clientSpan.Spv4 += singleMarginTrade.Sum(O => O.Spv4 * (-1)); - clientSpan.DeltaMargin += singleMarginTrade.Sum(O => O.DeltaMargin * (-1)); - clientSpan.WorstCastClientPayable += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.MySideMargin += singleMarginTrade.Sum(O => O.WorstCastClientPayable * (-1)); - clientSpan.TwoSideMargin += singleMarginTrade.Sum(O => O.TwoSideMargin); - clientSpan.MySideMargin = Math.Min(clientSpan.MySideMargin ?? 0, 0); - - //交易员不支付预付金 - clientSpan.WorstCastClientPayable = Math.Min(clientSpan.WorstCastClientPayable ?? 0, 0); - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - db.SaveChanges(); - return req.tradeSpans; - } - } - - public override double GetTradeMargin(GetTradeMarginReq req) - { - using (var db = new YLContext()) - { - if (req.trade.TradeType == "结构化交易") - { - req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - - var marginReq = req.GetRunMarginCalculationReq(); - if (req.trade.IsGroup == 1) - { - marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList(); - } - var tradeMargin = RunMarginCalculation(marginReq); - if (null != tradeMargin) - { - var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0); - return margin; - } - return 0.0; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ZhongCaiMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ZhongCaiMarginCalculation.cs deleted file mode 100644 index f33db7d0..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ZhongCaiMarginCalculation.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace YLErp.BLL.MarginCalculation -{ - /// - /// 中财预付金计算 - /// - public class ZhongCaiMarginCalculation : MarginCalculationBase - { - public static readonly ZhongCaiMarginCalculation Instance; - - static ZhongCaiMarginCalculation() - { - Instance = new ZhongCaiMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected ZhongCaiMarginCalculation() - { - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ZhongJinMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ZhongJinMarginCalculation.cs deleted file mode 100644 index 5d32b100..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ZhongJinMarginCalculation.cs +++ /dev/null @@ -1,294 +0,0 @@ -using YLErp.BLL.Calculation; -using YLErp.Helpers; -using YLErp.Modules; -using YLErp.Modules.CalculationModule; -using YLErp.Modules.EodModule; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class ZhongJinMarginCalculation : MarginCalculationBase - { - // 定义一个静态变量来保存类的实例 - public static readonly ZhongJinMarginCalculation Instance; - - static ZhongJinMarginCalculation() - { - Instance = new ZhongJinMarginCalculation(); - } - - // 定义私有构造函数,使外界不能创建该类实例 - protected ZhongJinMarginCalculation() - { - } - - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - var tradeSpans = RunMarginCalculationForCommodity(helper); - - return tradeSpans; - } - - //商品类预付金计算 - private static List RunMarginCalculationForCommodity(RunMarginCalculationHelper helper) - { - var resultMap = new Dictionary(); - - var reqConv = new CalculateRisksForTradesReq - { - valueDate = helper.req.settleDate, - tradeList = helper.req.tradeList, - priceProvider = helper.req.PriceProvider, - pricingRequest = QdpPricingRequest.PV_ONLY, - addVolRateDic = null, - volType = helper.req.volType, - isUseTradeVol = PS.Config.IsTradeVol, - PreciseTimeMode = helper.req.CalcMarginType != Enums.CalcMarginTypeEnum.EodMargin, - isAddVolPercent = true, - overrideVolsForTrade = null, - isMarginCalc = true - }; - - if (helper.req.CalcMarginType == Enums.CalcMarginTypeEnum.EodMargin) - { - reqConv.calcScenario = Enums.CalcScenarioEnum.EodSettlement; - } - - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(reqConv); - - foreach (var item in tradeRiskResult.Results) - { - resultMap[item.Trade.id] = helper.CreateTradeSpan(item.Trade); - resultMap[item.Trade.id].WorstCastClientPayable = item.ValueResult.Pv; - resultMap[item.Trade.id].Commission = item.ValueResult.ExtendInfo.Commission; - resultMap[item.Trade.id].VM = item.ValueResult.ExtendInfo.FloatingWinLoss + item.ValueResult.ExtendInfo.AnnualFee; - resultMap[item.Trade.id].IM = item.ValueResult.ExtendInfo.IM; - resultMap[item.Trade.id].PFE = item.ValueResult.ExtendInfo.PFE; - resultMap[item.Trade.id].Notional = item.Trade.Notional; - resultMap[item.Trade.id].StockEqvNotional = item.Trade.StockEqvNotional; - } - - return resultMap.Values.ToList(); - } - - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIds = tradeList.Select(x => x.UnderlyingId); - var underlyings = db.underlying_manager.AsNoTracking().Where(x => underlyingIds.Contains(x.id)); - var tradeSwaps = db.trade_swap.AsNoTracking().Where(x => tradeIds.Contains(x.TradeId)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - join tradeSwap in tradeSwaps on tradeSpan.TradeId equals tradeSwap.TradeId - join underlying in underlyings on trade.UnderlyingId equals underlying.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSwap, tradeSpan, underlying }).ToList(); - - if (req.tradeSpans != null && req.tradeSpans.Count > 0) - { - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var client = DataCacheProvider.GetClientDataSource().GetData(clientGroup.Key); - - var credit = db.credit.FirstOrDefault(x => x.CreditStartDate <= req.settleDate && x.CreditDeadLine >= req.settleDate && x.ClientId == clientGroup.Key && x.ProcessStatus == "已审批"); - var hasCredit = credit != null && credit.PFECredit > 0; - var IMCredit = credit != null ? credit.IMCredit : 0; - var PFECredit = credit != null ? credit.PFECredit : 0; - var ClientCredit = credit != null ? credit.Credit : 0; - - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }; - - //负数代表客户应缴预付金,正数代表客户应收预付金 - if (client.BoundSide == BoundSideEnum.北向) - { - var IM = Math.Max(clientGroup.Sum(x => x.tradeSpan.IM ?? 0) - (hasCredit ? (IMCredit ?? 0) : 0), 0); - clientSpan.IM = IM; - clientSpan.VM = clientGroup.Sum(x => x.tradeSpan.VM ?? 0); - clientSpan.Commission = clientGroup.Sum(x => x.tradeSpan.Commission ?? 0); - clientSpan.WorstCastClientPayable = -(Math.Max(IM + clientSpan.VM.Value + clientSpan.Commission.Value, 0)); - } - else - { - #region IM抵扣逻辑 - - var totalStockEqvNotional = credit == null ? 0 : credit.DeductStockEqvNotional ?? 0; - var imDeduct = 0.00; - if (totalStockEqvNotional > 0) - { - var varietyGroups = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT).GroupBy(t => t.underlying.UnderlyingTypeId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Notional = t.Sum(g => g.tradeSpan.Notional * (g.tradeSwap.PayLongShort == "多头" ? 1 : -1)), - StockEqvNotional = Math.Abs(t.Sum(g => g.tradeSpan.StockEqvNotional * new EodCurrencyRateService(OptUserInfo.SystemUser).GetCurrencyRate(g.trade.QuoteCurrency, g.trade.SettlementCurrency, req.settleDate) * (g.tradeSwap.PayLongShort == "多头" ? 1 : -1))), - IM = Math.Abs(t.Sum(g => (g.tradeSpan.IM ?? 0) * (g.tradeSwap.PayLongShort == "多头" ? 1 : -1))), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - var varietyMappingDeducts = db.variety_mapping_deduct.AsNoTracking().OrderBy(x => x.Index).ToList(); - varietyMappingDeducts.ForEach(x => - { - if (totalStockEqvNotional > 0) - { - var varietyGroup = varietyGroups.FirstOrDefault(y => y.VarietyId == x.VarietyId); - var varietyGroupOther = varietyGroups.FirstOrDefault(y => y.VarietyId == x.VarietyIdOther); - if (varietyGroup != null && varietyGroupOther != null && varietyGroup.Notional * varietyGroupOther.Notional < 0 && varietyGroup.StockEqvNotional > 0 && varietyGroupOther.StockEqvNotional > 0) - { - var deductRate = Math.Min(1, Math.Max(totalStockEqvNotional / 2 / (varietyGroup.StockEqvNotional ?? 0), totalStockEqvNotional / 2 / (varietyGroupOther.StockEqvNotional ?? 0))); - var stockEqvNotional = Math.Min(Math.Min(totalStockEqvNotional / 2, varietyGroup.StockEqvNotional ?? 0), varietyGroupOther.StockEqvNotional ?? 0); - varietyGroup.StockEqvNotional -= stockEqvNotional; - varietyGroupOther.StockEqvNotional -= stockEqvNotional; - totalStockEqvNotional -= (stockEqvNotional * 2); - - var deltaDeduct = Math.Min(Math.Abs(varietyGroup.Notional.Value * x.Unit / x.DPSR), Math.Abs(varietyGroupOther.Notional.Value * x.UnitOther / x.DPSROther)); - imDeduct += (varietyGroup.IM ?? 0) * deltaDeduct / Math.Abs(varietyGroup.Notional.Value * x.Unit / x.DPSR) * deductRate * x.ConcessionRate; - imDeduct += (varietyGroupOther.IM ?? 0) * deltaDeduct / Math.Abs(varietyGroupOther.Notional.Value * x.UnitOther / x.DPSROther) * deductRate * x.ConcessionRate; - } - } - }); - } - - #endregion - - #region PFE - - var pfe = 0.00; - - var varietyPFEDeduct = db.variety_pfe_deduct.AsNoTracking().ToList(); - List varietyIdsDeduct = new List(); - varietyPFEDeduct.ForEach(x => - { - var varietyIds = x.VarietyIds.Split(','); - varietyIdsDeduct.AddRange(varietyIds); - var underlyingGroups = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT && varietyIds.Contains(O.underlying.UnderlyingTypeId.ToString())).GroupBy(t => t.underlying.id).Select(t => new ClientSpan - { - UnderlyingId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - PFE = t.Sum(g => (g.tradeSpan.PFE ?? 0) * (g.tradeSwap.PayLongShort == "多头" ? 1 : -1)), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - pfe += Math.Sqrt(Math.Pow(x.Rate, 2) * Math.Pow(underlyingGroups.Sum(u => u.PFE ?? 0), 2) + (1 - Math.Pow(x.Rate, 2)) * underlyingGroups.Sum(u => Math.Pow(u.PFE ?? 0, 2))); - }); - - var underlyingGroupsOutOfDeduct = clientGroup.Where(O => O.trade.MarginType == DBModels.Enums.MarginTypeEnum.DEFAULT && !varietyIdsDeduct.Contains(O.underlying.UnderlyingTypeId.ToString())).GroupBy(t => new { underlyingId = t.underlying.id, varietyId = t.underlying.UnderlyingTypeId }).Select(t => new ClientSpan - { - VarietyId = t.Key.varietyId, - UnderlyingId = t.Key.underlyingId, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - PFE = t.Sum(g => (g.tradeSpan.PFE ?? 0) * (g.tradeSwap.PayLongShort == "多头" ? 1 : -1)), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - - var varietyIdsOutOfDeduct = underlyingGroupsOutOfDeduct.Select(x => x.VarietyId).ToList(); - varietyIdsOutOfDeduct.ForEach(x => - { - var underlyingGroups = underlyingGroupsOutOfDeduct.Where(y => y.VarietyId == x); - pfe += Math.Sqrt(Math.Pow(0.9, 2) * Math.Pow(underlyingGroups.Sum(u => u.PFE ?? 0), 2) + (1 - Math.Pow(0.9, 2)) * underlyingGroups.Sum(u => Math.Pow(u.PFE ?? 0, 2))); - }); - - #endregion - - clientSpan.PFE = pfe; - - var IM = Math.Max(clientGroup.Sum(x => x.tradeSpan.IM ?? 0) - (IMCredit ?? 0) - imDeduct, 0); - var PFE = Math.Max(pfe - (PFECredit ?? 0), 0); - var IMNeed = Math.Max(IM, PFE); - if (IM > PFE) - { - clientSpan.Deduct = imDeduct; - } - - clientSpan.IM = IMNeed; - - //远期标的未结算但已平仓的VM需要统计到预付金的VM里参与预付金计算 - var tradePres = db.trade.Where(x => x.ClientId == client.id && x.SettlementDate != null && x.SettlementDate > req.settleDate && x.ValidState != "InValid").ToList(); - var tradeCurrencyRates = tradePres.Select(x => new { TradeId = x.id, Rate = new EodCurrencyRateService(OptUserInfo.SystemUser).GetCurrencyRate(x.QuoteCurrency, x.SettlementCurrency, req.settleDate) }); - var tradeSettledIds = tradePres.Select(x => x.id); - var tradeCashPreIds = db.trade_cash_pre.Where(x => tradeSettledIds.Contains(x.TradeId) && x.HappenedDate != null && x.HappenedDate <= req.settleDate && x.Action == ClientCashInCashOut.系统操作_平仓费).Select(x => x.id).ToList(); - var tradeCashDetails = db.trade_cash_detail.Where(x => tradeCashPreIds.Contains(x.TradeCashPreId) && (x.TradeCashType == "浮动收益" || x.TradeCashType == "利息")).ToList(); - var tradeCashDetailsCommission = db.trade_cash_detail.Where(x => tradeCashPreIds.Contains(x.TradeCashPreId) && (x.TradeCashType == "了结手续费" || x.TradeCashType == "开仓手续费")).ToList(); - - clientSpan.VM = clientGroup.Sum(x => x.tradeSpan.VM ?? 0) + tradeCashDetails.Sum(x => (x.QuoteAmount ?? 0) * tradeCurrencyRates.FirstOrDefault(y => y.TradeId == x.TradeId).Rate); - clientSpan.Commission = clientGroup.Sum(x => x.tradeSpan.Commission ?? 0) + tradeCashDetailsCommission.Sum(x => (x.QuoteAmount ?? 0) * tradeCurrencyRates.FirstOrDefault(y => y.TradeId == x.TradeId).Rate); - clientSpan.PFEUsed = pfe + clientSpan.VM + clientSpan.Commission; - clientSpan.WorstCastClientPayable = -(Math.Max(IMNeed + (clientSpan.VM ?? 0) + (clientSpan.Commission ?? 0) - (ClientCredit ?? 0), 0)); - } - - clientSpanNews.Add(clientSpan); - } - } - - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - } -} diff --git a/YLErpDAL/BLL/MarginCalculation/ZhongLiangMarginCalculation.cs b/YLErpDAL/BLL/MarginCalculation/ZhongLiangMarginCalculation.cs deleted file mode 100644 index 7f14850e..00000000 --- a/YLErpDAL/BLL/MarginCalculation/ZhongLiangMarginCalculation.cs +++ /dev/null @@ -1,338 +0,0 @@ -using YLErp.Abstract.DataProviders; -using YLErp.BLL.Calculation; -using YLErp.Enums; -using YLErp.Helpers; -using YLErp.Model.Enum; -using YLErp.QdpModule; - -namespace YLErp.BLL.MarginCalculation -{ - public class ZhongLiangMarginCalculation : MarginCalculationBase - { - public static readonly ZhongLiangMarginCalculation Instance; - static ZhongLiangMarginCalculation() - { - Instance = new ZhongLiangMarginCalculation(); - - } - public ZhongLiangMarginCalculation() - { - } - public override List RunMarginCalculation(RunMarginCalculationReq req) - { - if (req?.tradeList == null || !req.tradeList.Any()) - { - return new List(); - } - - var calcTradeList = req.tradeList.ToList(); - - var resultMap = new Dictionary(); - - var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider); - helper.SetFieldsByTradeType(); - helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices); - helper.GetUpDownVolRateDic(out var tradeVolRateDicUp, out var tradeVolRateDicDown); - var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) }; - - var volRates = new (int, Dictionary)[] { - (0, null), - (1, tradeVolRateDicUp), - (2, tradeVolRateDicDown) - }; - - foreach (var price in prices) - { - foreach (var itemDic in volRates) - { - var key = $"{price.Item1}_{itemDic.Item1}"; - if (key == "normal_0") - { - continue; - } - var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( - valueDate: req.settleDate, - tradeList: calcTradeList, - calcScenario: req.GetCalcScenario(), - priceProvider: price.Item2, - pricingRequest: QdpPricingRequest.PV_ONLY, - addVolRateDic: itemDic.Item2, - volType: req.volType, - isUseTradeVol: PS.Config.IsTradeVol, - preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin, - isAddVolPercent: false); - - if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1) - { - continue; - } - - foreach (var item in tradeRiskResult.Results) - { - var client = helper.GetClient(item.Trade.ClientId); - var clientRatio = client?.Ratio ?? 1.0; - var clientRatio1 = client?.Ratio1 ?? 1.0; - - var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan); - - var pv = item.ValueResult.Pv; - - if (!helper.GetSpecialMargin(item.Trade, pv, out var value)) - { - if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin) - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio1; - } - else - { - value = double.IsNaN(pv) ? 0 : pv * clientRatio; - } - } - - - if (!contains) - { - resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade); - if (item.Trade.TradeType == "雪球期权" && item.Trade.BuySell == "买入") - { - resultMap[item.Trade.id].IsSingleMargin = true; - resultMap[item.Trade.id].Comment = "雪球买入"; - } - } - - switch (key) - { - case "up_1": - tempTradeSpan.Spv1 = value; break; - case "up_0": - tempTradeSpan.Spv2 = value; break; - case "up_2": - tempTradeSpan.Spv3 = value; break; - case "normal_1": - tempTradeSpan.Spv4 = value; break; - case "normal_2": - tempTradeSpan.Spv5 = value; break; - case "down_1": - tempTradeSpan.Spv6 = value; break; - case "down_0": - tempTradeSpan.Spv7 = value; break; - case "down_2": - tempTradeSpan.Spv8 = value; break; - } - - if (contains) - { - tempTradeSpan.SetWorstCastClientPayable(); - if (client != null) - { - var value2 = (double)tempTradeSpan.WorstCastClientPayable; - if (client.MarginOptionType == (int)MarginOptionEnum.单向追保) - { - value2 = item.Trade.BuySell == "卖出" ? 0 : Math.Max(value2, 0); - } - else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保 || client.MarginOptionType == (int)MarginOptionEnum.其他) - { - value2 = 0; - } - else if (client.MarginOptionType == (int)MarginOptionEnum.双向追保) - { - value2 = Math.Max(value2, 0); - } - tempTradeSpan.WorstCastClientPayable = value2; - } - } - - } - } - } - return resultMap.Values.ToList(); - } - public override List CalcClientMargin(CalcClientMarginReq req) - { - var clientSpanNews = new List(); - - var runMargin = new RunMarginCalculationReq(req.UserInfo); - runMargin.settleDate = req.settleDate; - var helper = new RunMarginCalculationHelper(runMargin, _underlyingDataProvider); - using (var db = new YLContext()) - { - var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList(); - var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); - var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList(); - - var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList(); - - var tradeSpanInfo = (from tradeSpan in req.tradeSpans - join trade in tradeList on tradeSpan.TradeId equals trade.id - where tradeSpan.ValueDate == req.settleDate - select new { trade, tradeSpan }).ToList(); - var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); - foreach (var clientGroup in clientGroups) - { - var varietyGroups = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan - { - VarietyId = t.Key, - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), - Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), - Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), - Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), - Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), - Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), - Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), - Spv8 = t.Sum(g => g.tradeSpan.Spv8) * (-1), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType - }).ToList(); - foreach (var item in varietyGroups) - { - - item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0), item.Spv8 ?? 0); - - #region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致 - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - - - - if (item.WorstCastClientPayable == item.Spv1) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1); - } - else if (item.WorstCastClientPayable == item.Spv2) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2); - } - else if (item.WorstCastClientPayable == item.Spv3) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3); - } - else if (item.WorstCastClientPayable == item.Spv4) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4); - } - else if (item.WorstCastClientPayable == item.Spv5) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5); - } - else if (item.WorstCastClientPayable == item.Spv6) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6); - } - else if (item.WorstCastClientPayable == item.Spv7) - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7); - } - else - { - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8); - } - - #endregion - } - var clientSpan = new ClientSpan - { - ClientId = clientGroup.Key, - ValueDate = req.settleDate, - Spv1 = varietyGroups.Sum(g => g.Spv1), - Spv2 = varietyGroups.Sum(g => g.Spv2), - Spv3 = varietyGroups.Sum(g => g.Spv3), - Spv4 = varietyGroups.Sum(g => g.Spv4), - Spv5 = varietyGroups.Sum(g => g.Spv5), - Spv6 = varietyGroups.Sum(g => g.Spv6), - Spv7 = varietyGroups.Sum(g => g.Spv7), - Spv8 = varietyGroups.Sum(g => g.Spv8), - //负数代表客户应缴预付金,正数代表客户应收预付金 - WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable), - OptId = req.userId, - OptName = req.userName, - OptDate = DateTime.Now, - SpanType = req.SpanType, - AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0 - }; - if (!HasTwoSideMargin(clientGroup.Key) && varietyGroups.Sum(g => g.WorstCastClientPayable) > 0) - { - clientSpan.WorstCastClientPayable = 0; - foreach (var item in varietyGroups) - { - var tradeIdList = clientGroup.Select(x => x.tradeSpan.TradeId); - var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList(); - tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0); - tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0); - } - } - clientSpanNews.Add(clientSpan); - } - //span类型为实时删除所有实时计算的交易的预付金信息 - if (req.SpanType == ClientSpan.SpanType_RealTime) - { - if (req.RefreshClientIds != null) - { - db.BulkDelete($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds }); - } - else - { - db.BulkDelete($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType }); - } - } - else - { - if (req.ClientIds != null) - { - var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql, new { ids = req.ClientIds }); - } - else - { - var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0"; - db.BulkDelete(sql); - } - - var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag) - .Select(n => new { n.ValueDate, n.ClientId }).ToList(); - //筛选出可以修改的clientSpan - clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); - } - if (clientSpanNews.Count > 0) - { - MySqlBulkExtensions.BulkInsert(db, clientSpanNews); - } - - db.SaveChanges(); - return req.tradeSpans; - } - } - public override double GetTradeMargin(GetTradeMarginReq req) - { - var trade = req.trade; - using (var db = new YLContext()) - { - if (trade.TradeType == "结构化交易") - { - trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); - } - } - var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq()); - if (null != tradeMargin && tradeMargin.FirstOrDefault() != null) - { - var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0; - - return margin; - } - return 0.0; - } - } -} diff --git a/YLErpUnitTest/Modules/MarginModule/GTJAMarginTest.cs b/YLErpUnitTest/Modules/MarginModule/GTJAMarginTest.cs deleted file mode 100644 index 12479bf6..00000000 --- a/YLErpUnitTest/Modules/MarginModule/GTJAMarginTest.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Linq; -using YLErp.BLL.MarginCalculation; -using YLErp.Modules.DataProviderModule; -using GTJAMarginCalculationNew = YLErp.BLL.MarginCalculation.GTJAMarginCalculation; -//using GTJAMarginCalculationOld = YLErp.BLL.MarginCalculationBak.GTJAMarginCalculation; - -namespace YLErp.Modules.MarginModule -{ - [TestClass] - public class GTJAMarginTest : UnitTestBase - { - [TestMethod("国君保证金比较新方法和老方法")] - public void TestOldNew() - { - var req = new RunMarginCalculationReq - { - forOtherSide = false, - forSingleTrade = true, - hasOptionInfo = false, - //isEodSettle = false, - //isInitialMargin = false, - settleDate = DateTime.Today, - userId = 1, - userName = "系统用户", - volType = "交易" - }; - - using (var db = DbContextFactory.GetYLDbContext()) - { - req.tradeList = db.trade.Where(n => n.id == 106969) - .Where(t => t.ValidState != ConsGlobal.InValid && t.ClientId > 0 - && t.TradeType != "结构化交易" && t.TradeStatus == "确认成交" && t.SpotPrice != null) - .OrderByDescending(n => n.id).Take(100).ToList(); - } - - var priceDic = new Dictionary(); - - foreach (var t in req.tradeList) - { - if (!priceDic.ContainsKey(t.UnderlyingCode)) - { - priceDic[t.UnderlyingCode] = t.SpotPrice.Value * 1.08; - } - } - - req.PriceProvider = (ManualPriceProvider)priceDic; - - var resultNew = GTJAMarginCalculationNew.Instance.RunMarginCalculation(req.Clone()) - .ToDictionary(n => n.TradeId); - - //var resultOld = GTJAMarginCalculationOld.Instance.RunMarginCalculation( - // req.userId, req.userName, req.tradeList, req.settleDate, priceDic, req.hasOptionInfo, req.isEodSettle, req.forOtherSide, req.volType, req.forOtherSide - // ); - - //foreach (var ro in resultOld) - //{ - // if (resultNew.TryGetValue(ro.TradeId, out var rn)) - // { - // Console.WriteLine("trade id: " + ro.TradeId); - // Assert.IsTrue(Math.Abs((ro.Spv1 ?? 0) - (rn.Spv1 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv2 ?? 0) - (rn.Spv2 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv3 ?? 0) - (rn.Spv3 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv4 ?? 0) - (rn.Spv4 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv5 ?? 0) - (rn.Spv5 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv6 ?? 0) - (rn.Spv6 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv7 ?? 0) - (rn.Spv7 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.Spv8 ?? 0) - (rn.Spv8 ?? 0)) < 1e-6); - // Assert.IsTrue(Math.Abs((ro.WorstCastClientPayable ?? 0) - (rn.WorstCastClientPayable ?? 0)) < 1e-6); - // } - // else - // { - // Assert.Fail(); - // System.Diagnostics.Debug.WriteLine("没有取到新保证金"); - // } - //} - } - } -} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/ALQHMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/ALQHMarginCalculation.cs deleted file mode 100644 index abf1c694..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/ALQHMarginCalculation.cs +++ /dev/null @@ -1,210 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.DBModels; -//using YLErp.Model; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 安粮 -// /// -// public class ALQHMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly ALQHMarginCalculation Instance; - -// static ALQHMarginCalculation() -// { -// Instance = new ALQHMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private ALQHMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// var tempStockTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); -// if (tempStockTradeList.Any()) -// { -// var stockTradeSpanlist = StockMarginCalculation(userId, userName, tempStockTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle); -// if (stockTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(stockTradeSpanlist); -// } -// } -// var tempFutureTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); -// if (tempFutureTradeList.Any()) -// { -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count > 0) -// { -// var futureTradeSpanlist = FutureMarginCalculation(userId, userName, tempFutureTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, volType); -// if (futureTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(futureTradeSpanlist); -// } -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 股票类期权计算保证金 -// /// -// public List StockMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// using (YLContext db = new YLContext()) -// { -// var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// if (clientList != null) -// { - -// tradeList.ForEach(t => -// { -// var client = clientList.FirstOrDefault(c => c.client.id == t.ClientId); -// if (client != null) -// { -// //未设置相关保证金系数默认为1.0 -// var clientRatio = client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0); -// //如果是股票去名义本金,如果是期货取:份额 * 即期价格 -// var value = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.client.HasTwoSideMargin == 1 ? -1 : 0)) * clientRatio; -// var twoSideMargin = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : -1) * clientRatio; -// tradeSpans.Add(new trade_span -// { -// TradeId = t.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = client.client.id, -// UnderlyingId = t.UnderlyingId, -// UnderlyingCode = t.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// TwoSideMargin = twoSideMargin -// }); -// } -// }); -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 商品期权计算保证金 -// /// -// public List FutureMarginCalculation(int userId, string userName, List futureTradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, string volType = "交易") -// { -// var tradeSpans = new List(); -// using (YLContext db = new YLContext()) -// { -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(futureTradeList); -// } - -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(userId + "", settleDate, futureTradeList, priceDict, ValueCalculator.BASIC_GREEKS, null, isEodSettle, volType, isUseTradeVol: PS.Config.IsTradeVol, PreciseTimeMode: !isEodSettle); -// var deltaCoefficient = valuedateBLL.SystemDate.FutureMarginDeltaCoefficient ?? 1; -// var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; -// var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; -// var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; -// //客户对应等级系数 -// var clientIds = futureTradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// foreach (var item in tradeRiskResult.Results) -// { -// var tempTrade = futureTradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var optionValue = item.ValueResult; -// var tempVariety = _underlyingDataProvider.GetVariety(tempTrade.UnderlyingId); -// var closePrice = priceDict.ContainsKey(tempTrade.UnderlyingId) ? priceDict[tempTrade.UnderlyingId] : 0.0; -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// if (tempTrade != null && item.ValueResult != null && tempVariety != null) -// { -// //未设置相关保证金系数默认为1.0 -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); -// //保证金 = ( a * DeltaCash + b* GammaCash * PricingVol / 16) * 当前标的保证金率 + c * Vega -// var value = ((optionValue.DeltaCash * deltaCoefficient -// + optionValue.GammaCash * 0.01 * (optionValue.Vol / 16) * omegaCoefficient) * tempVariety.Margin -// + optionValue.Vega * vegaCoefficient -// ) * alphaRate * (tempTrade.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.client.HasTwoSideMargin == 1 ? 1 : 0)) * clientRatio; -// var twoSideMargin = ((optionValue.DeltaCash * deltaCoefficient -// + optionValue.GammaCash * 0.01 * (optionValue.Vol / 16) * omegaCoefficient) * tempVariety.Margin -// + optionValue.Vega * vegaCoefficient -// ) * alphaRate * (tempTrade.BuySell == "买入" ? 1 : -1) * clientRatio; -// tradeSpans.Add(new trade_span -// { -// TradeId = tempTrade.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = tempTrade.ClientId, -// UnderlyingId = tempTrade.UnderlyingId, -// UnderlyingCode = tempTrade.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// TwoSideMargin = twoSideMargin -// }); -// } -// } - -// return tradeSpans; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BHRSMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BHRSMarginCalculation.cs deleted file mode 100644 index 101a186c..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BHRSMarginCalculation.cs +++ /dev/null @@ -1,415 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.BLL.Eod; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 渤海荣盛 -// /// -// public class BHRSMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly BHRSMarginCalculation Instance; - -// static BHRSMarginCalculation() -// { -// Instance = new BHRSMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private BHRSMarginCalculation() -// { -// } - -// public override bool MarginCalcNeedSpecial -// { -// get -// { -// return true; -// } -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return tradeSpans; -// } -// var tempStockTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); -// if (tempStockTradeList.Any()) -// { -// var stockTradeSpanlist = StockMarginCalculation(userId, userName, tempStockTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle); -// if (stockTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(stockTradeSpanlist); -// } -// } -// var tempFutureTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); -// if (tempFutureTradeList.Any()) -// { -// if (forSingleTrade) -// { -// var futureTradeSpanlist = FutureMarginCalculationForSingleTrade(userId, userName, tempFutureTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, volType); -// if (futureTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(futureTradeSpanlist); -// } -// } -// else -// { -// var futureTradeSpanlist = FutureMarginCalculation(userId, userName, tempFutureTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, volType); -// if (futureTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(futureTradeSpanlist); -// } -// } - -// } -// } -// return tradeSpans; -// } - -// /// -// /// 股票类期权计算保证金 -// /// -// public List StockMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// using (YLContext db = new YLContext()) -// { -// var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// if (clientList != null) -// { -// tradeList.ForEach(t => -// { -// var client = clientList.FirstOrDefault(c => c.client.id == t.ClientId); -// if (client != null) -// { -// var clientRatio = client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0); -// //如果是股票去名义本金,如果是期货取:份额 * 即期价格 -// var value = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.client.HasTwoSideMargin == 1 ? -1 : 0)) * clientRatio; -// var twoSideMargin = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : -1) * clientRatio; -// if (t.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == t.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{t.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// twoSideMargin = eodTradeRiskManual?.Margin ?? 0; -// } -// tradeSpans.Add(new trade_span -// { -// TradeId = t.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = client.client.id, -// UnderlyingId = t.UnderlyingId, -// UnderlyingCode = t.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// TwoSideMargin = twoSideMargin -// }); -// } -// }); -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 商品期权计算保证金 OLD -// /// -// public List FutureMarginCalculation(int userId, string userName, List futureTradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, string volType = "交易") -// { -// // -// List tradeSpans = new List(); -// using (YLContext db = new YLContext()) -// { -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(futureTradeList); -// } - -// var futureManualTradeList = futureTradeList.Where(x => x.TradeType == "自定义交易"); -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(userId + "", settleDate, futureTradeList, priceDict, ValueCalculator.BASIC_GREEKS, null, isEodSettle, volType, isUseTradeVol: PS.Config.IsTradeVol, PreciseTimeMode: !isEodSettle); -// logger.Info($"商品期货保证金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); -// //计算保证金包含错误信息时弹出错误信息 -// if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) -// { -// throw new Exception(tradeRiskResult.ErrorMessage); -// } -// var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; -// var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; -// var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; -// //客户对应等级系数 -// var clientIds = futureTradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// if (tradeRiskResult.Results.Count > 0) -// { -// var underlyingCodeLookup = futureTradeList.ToLookup(t => new { t.UnderlyingId, t.ClientId }); - -// foreach (var item in underlyingCodeLookup) -// { -// var tempTrades = item.ToList(); -// var tradeIds = tempTrades.Select(t => t.id).ToList(); -// var tempVariety = _underlyingDataProvider.GetVariety(item.Key.UnderlyingId); -// var closePrice = priceDict.ContainsKey(item.Key.UnderlyingId) ? priceDict[item.Key.UnderlyingId] : 0.0; -// var optionValueList = tradeRiskResult.Results.Where(t => tradeIds.Contains(t.Trade.id) && t.ValueResult != null && t.Trade != null && !double.IsNaN(t.ValueResult.Delta) && !double.IsNaN(t.ValueResult.Vega) && !double.IsNaN(t.ValueResult.Gamma)).ToList(); - -// //未设置相关保证金系数默认为1.0 -// var client = clientList.FirstOrDefault(c => c.client.id == item.Key.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// if (optionValueList.Any() && tempVariety != null) -// { -// var optionValueListWithOutManual = optionValueList.Where(x => x.Trade.TradeType != "自定义交易"); -// var deltaMerge = 0.0; -// var deltaLong = optionValueListWithOutManual.Sum(t => (t.ValueResult.Delta) * (t.Trade.BuySell == "卖出" ? 1 : 0)); -// var deltaShort = optionValueListWithOutManual.Sum(t => (t.ValueResult.Delta) * (t.Trade.BuySell == "买入" ? 1 : 0)); -// if (deltaLong * deltaShort == 0) -// { -// deltaMerge = Math.Abs(deltaShort); -// } -// else if (deltaLong * deltaShort < 0) -// { -// if (Math.Abs(deltaLong) >= Math.Abs(deltaShort)) -// { -// deltaMerge = 0; -// } -// else -// { -// deltaMerge = Math.Abs(deltaShort) - Math.Abs(deltaLong); -// } -// } -// else -// { -// deltaMerge = Math.Abs(deltaShort); -// } -// var vegaMerge = Math.Max(optionValueListWithOutManual.Sum(t => Math.Abs(t.ValueResult.Vega) * EodOperationBase.GetSign(t.Trade.BuySell)), 0); -// var gammaMerge = Math.Max(optionValueListWithOutManual.Sum(t => Math.Abs(t.ValueResult.Gamma) * EodOperationBase.GetSign(t.Trade.BuySell)), 0); -// //保证金 = SUM((DELTA值 * 数量 * 标的资产收盘价)场内期权保证金率 + Vega值 * 数量 * 0.01 * 3 + Gamma金额 * vol / 16 * 2.5 场内期权保证金率) -// var value = ((deltaMerge * closePrice) * (tempVariety.Margin) -// + vegaMerge * 0.01 * vegaCoefficient -// + gammaMerge * Math.Pow(closePrice, 2) * 0.01 * (optionValueListWithOutManual.First().ValueResult.Vol / 16) * omegaCoefficient * tempVariety.Margin -// ) * alphaRate * clientRatio; - -// //如果非自定义交易的保证金为负,会将其算作0,再加上自定义交易的保证金,算出总和,会使得得到的保证金高于实际保证金(暂时理解为对客户有利,不做处理) -// if (futureManualTradeList.Any()) -// { -// var manualTradeIds = futureManualTradeList.Select(x => x.id); -// var eodTradeRiskManuals = db.eod_trade_risk_manual.Where(x => manualTradeIds.Contains(x.id) && x.ValueDate <= settleDate).OrderByDescending(x => x.ValueDate); - -// foreach (var riskManual in eodTradeRiskManuals) -// { -// var trade = futureManualTradeList.FirstOrDefault(x => x.id == riskManual.TradeId); -// if (trade != null) -// { -// value += riskManual.Margin * EodOperationBase.GetSign(trade.BuySell); -// } -// } -// value = Math.Max(value ?? 0, 0); -// } - -// tradeSpans.Add(new trade_span -// { -// TradeId = tempTrades.First().id,//默认记录为第一条交易记录中 -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = item.Key.ClientId, -// ValueDate = settleDate, -// UnderlyingId = item.Key.UnderlyingId, -// UnderlyingCode = tempTrades.First().UnderlyingCode, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// Comment = $"标的{tempTrades.First().UnderlyingCode} 合计计算:{string.Join(",", tempTrades.Select(t => t.id).ToList())}" -// }); -// } -// else -// { -// var nanTradeValue = tradeRiskResult.Results.Where(t => tradeIds.Contains(t.Trade.id) && (double.IsNaN(t.ValueResult.Delta) || !double.IsNaN(t.ValueResult.Vega) || !double.IsNaN(t.ValueResult.Gamma))).Select(t => t.ValueResult).ToList(); -// nanTradeValue.ForEach(optionValue => -// { -// logger.Error($"交易ID:{item.Key.UnderlyingId},Delta:{optionValue.Delta},DeltaCash{optionValue.DeltaCash},Vega{optionValue.Vega},Gamma:{optionValue.Gamma},vol:{optionValue.Vol}"); -// }); -// } -// } -// } -// return tradeSpans; -// } -// } - -// /// -// /// 商品期权计算保证金 -// /// -// public List FutureMarginCalculationForSingleTrade(int userId, string userName, List futureTradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, string volType = "交易") -// { -// // -// List tradeSpans = new List(); -// using (YLContext db = new YLContext()) -// { -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(futureTradeList); -// } - -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(userId + "", settleDate, futureTradeList, priceDict, ValueCalculator.BASIC_GREEKS, null, isEodSettle, volType, isUseTradeVol: PS.Config.IsTradeVol, PreciseTimeMode: !isEodSettle); -// logger.Info($"商品期货保证金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); -// //计算保证金包含错误信息时弹出错误信息 -// if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) -// { -// throw new Exception(tradeRiskResult.ErrorMessage); -// } -// var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3; -// var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5; -// var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; -// //客户对应等级系数 -// var clientIds = futureTradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); -// if (tradeRiskResult.Results.Count > 0) -// { - -// var underlyingCodeLookup = futureTradeList.ToLookup(t => new { t.UnderlyingId, t.ClientId }); - -// foreach (var item in tradeRiskResult.Results) -// { -// var tempVariety = _underlyingDataProvider.GetVariety(item.Trade.UnderlyingId); -// var closePrice = priceDict.ContainsKey(item.Trade.UnderlyingId) ? priceDict[item.Trade.UnderlyingId] : 0.0; - -// //未设置相关保证金系数默认为1.0 -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// var deltaMerge = item.ValueResult.Delta; -// var vegaMerge = item.ValueResult.Vega; -// var gammaMerge = item.ValueResult.Gamma; -// //保证金 = SUM((DELTA值 * 数量 * 标的资产收盘价)场内期权保证金率 + Vega值 * 数量 * 0.01 * 3 + Gamma金额 * vol / 16 * 2.5 场内期权保证金率) -// var value = ((deltaMerge * closePrice) * (tempVariety.Margin ?? 0.0) -// + vegaMerge * 0.01 * vegaCoefficient -// + gammaMerge * Math.Pow(closePrice, 2) * 0.01 * (item.ValueResult.Vol / 16) * omegaCoefficient * (tempVariety.Margin ?? 0.0) -// ) * alphaRate * clientRatio; - -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } - -// tradeSpans.Add(new trade_span -// { -// TradeId = item.Trade.id,//默认记录为第一条交易记录中 -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = item.Trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = item.Trade.UnderlyingId, -// UnderlyingCode = item.Trade.UnderlyingCode, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// Comment = $"delta:{deltaMerge},closePrice:{closePrice},vega:{vegaMerge},gamma{gammaMerge},buySell:{item.Trade.BuySell}" -// }); -// } -// } -// return tradeSpans; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (var db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BXMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BXMarginCalculation.cs deleted file mode 100644 index e74c6c56..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/BXMarginCalculation.cs +++ /dev/null @@ -1,477 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation; -//using YLErp.BLL.Calculation.V2; -//using YLErp.Commons; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Enums; -//using YLErp.Model; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 伴兴保证金计算 -// /// -// public class BXMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly BXMarginCalculation Instance; - -// static BXMarginCalculation() -// { -// Instance = new BXMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// protected BXMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// List resultMap = new List(); -// var ignoreCalcArray = tradeList.FindAll(O => O.InitialMargin != null && O.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc); -// if (ignoreCalcArray.Count > 0) -// { -// ignoreCalcArray.ForEach(O => -// { -// var initMargin = O.InitialMargin * (O.Notional / O.OriginalNotional); -// trade_span ts = new trade_span() -// { -// TradeId = O.id, -// ClientId = O.ClientId, -// ValueDate = settleDate, -// UnderlyingId = O.UnderlyingId, -// UnderlyingCode = O.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = initMargin, -// Spv2 = initMargin, -// Spv3 = initMargin, -// Spv4 = initMargin, -// }; -// ts.setWorstCastClientPayable4(); -// resultMap.Add(ts); -// }); -// } -// var useCalcArray = tradeList.FindAll(O => O.InitialMargin == null || O.CalcFlag != (int)CalcFlagEnum.IgnoreMarginCalc); -// if (useCalcArray.Count > 0) -// { -// resultMap.AddRange(marginCalculation(userId, userName, useCalcArray, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide)); -// } -// return resultMap; -// } - -// public List marginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// Dictionary resultMap = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } -// var underlyingIds = priceDict.Keys.ToList(); -// //交易对应客户信息 -// var clientIds = tradeList.Select(t => t.ClientId ?? 0).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); -// Dictionary clientClassDict = new clientBLL().GetClients(clientIds).ToDictionary(K => K.id, V => V.ProperClientClass); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.CommodityCode equals variety.VarietyCode -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// defUpLimit = variety.UpLimit, -// defDownLimit = variety.DownLimit, -// defVolatilityRate = variety.VolatilityRate -// }).ToList(); - -// var UpLimitDict = new Dictionary(); -// var DownLimitDict = new Dictionary(); -// var umVolatilityRateDic = new Dictionary(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// //OTC-8856 Start -// //1.波动率变化 -// if (DataConvert.TryParsePercentValue(t.VolatilityRate, out double pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } -// else if (DataConvert.TryParsePercentValue(t.defVolatilityRate, out pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } -// }); -// } - -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// var tradeVolatilityRateDic = tradeList.ToDictionary(t => t.id, t => (umVolatilityRateDic.ContainsKey(t.UnderlyingId) ? umVolatilityRateDic[t.UnderlyingId] : 0) + (clientClassDict[t.ClientId ?? 0] != null && clientClassDict[t.ClientId ?? 0].Contains("普通投资者") ? 0.02 : 0)) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// Dictionary> eodPriceDict = new Dictionary>(); -// var upLimitPrices = new Dictionary(); -// var downLimitPrices = new Dictionary(); - -// //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 -// if (priceDict != null && priceDict.Count > 0) -// { -// Dictionary dict = base.GetUpDownLimitPrice(priceDict); - -// foreach (var t in dict) -// { -// upLimitPrices[t.Key] = t.Value[0]; -// downLimitPrices[t.Key] = t.Value[1]; -// } - -// eodPriceDict["up"] = upLimitPrices; -// eodPriceDict["down"] = downLimitPrices; -// } -// //波动率变化 -// var addVolRateList = new List> { null, tradeVolatilityRateDic }; - -// var userIdNew = UniqueTimeId.Get().ToString(); - -// try -// { -// foreach (var price in eodPriceDict) -// { -// addVolRateList.ForEach(addVolRateDic => -// { -// var key = $"{price.Key}_{(addVolRateDic == null ? 0 : 1)}"; -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userIdNew, // userId + "_" + price.Key, -// settleDate, -// tradeList, -// price.Value, -// ValueCalculator.PV_ONLY, -// addVolRateDic, -// isEodSettle, -// volType, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle, -// isAddVolPercent: false); -// if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) -// { -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// double value = 0; -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// if (resultMap.ContainsKey(item.Trade.id)) -// { -// switch (key) -// { -// case "up_0": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// resultMap[item.Trade.id].Spv1 = item.Trade.InitialMargin; -// } -// else -// { -// resultMap[item.Trade.id].Spv1 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "up_1": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// resultMap[item.Trade.id].Spv2 = item.Trade.InitialMargin; -// } -// else -// { -// resultMap[item.Trade.id].Spv2 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "down_0": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// resultMap[item.Trade.id].Spv3 = item.Trade.InitialMargin; -// } -// else -// { -// resultMap[item.Trade.id].Spv3 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "down_1": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// resultMap[item.Trade.id].Spv4 = item.Trade.InitialMargin; -// } -// else -// { -// resultMap[item.Trade.id].Spv4 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// default: -// break; -// } -// resultMap[item.Trade.id].setWorstCastClientPayable4(); -// } -// else -// { -// var trade = tradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var tempTradeSpan = new trade_span -// { -// TradeId = item.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now -// }; -// switch (key) -// { -// case "up_0": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// tempTradeSpan.Spv1 = item.Trade.InitialMargin; -// } -// else -// { -// tempTradeSpan.Spv1 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "up_1": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// tempTradeSpan.Spv2 = item.Trade.InitialMargin; -// } -// else -// { -// tempTradeSpan.Spv2 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "down_0": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// tempTradeSpan.Spv3 = item.Trade.InitialMargin; -// } -// else -// { -// tempTradeSpan.Spv3 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// case "down_1": -// if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc) -// { -// tempTradeSpan.Spv4 = item.Trade.InitialMargin; -// } -// else -// { -// tempTradeSpan.Spv4 = GetMargin(item.Trade, item.ValueResult, clientRatio); -// } -// break; -// default: -// break; -// } -// resultMap[item.Trade.id] = tempTradeSpan; -// } -// } -// } -// }); -// } -// } -// finally -// { -// //上面的计算用到静态生成market,需要清除 -// QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userIdNew); -// } - -// return resultMap.Values.ToList(); -// } -// } - -// private double GetMargin(trade trade, TradeValueResult valueResult, double clientRatio) -// { -// double value = 0.0; - -// if (trade.TradeType == "结构化交易") -// { -// if (trade.StructureType != null && trade.StructureType.Contains("跨式")) -// { -// value = valueResult.MaxAbsPv; -// } -// else -// { -// value = valueResult.SellPv; -// } -// } -// else if (trade.TradeType != "自定义交易") -// { -// value = valueResult.Pv; -// } - -// return (double.IsNaN(value) ? 0 : value) * clientRatio; -// } - -// public override bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = false, Dictionary clientAdditionalMarginDic = null) -// { -// using (YLContext db = new YLContext()) -// { -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// var clientSpanNews = new List(); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// if (PS.Config.ErpElement.NonInterBankMarginNetting) -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); -// } -// else -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), 0); -// } - -// item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); -// } -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = underlyingGroup.Sum(g => g.Spv1), -// Spv2 = underlyingGroup.Sum(g => g.Spv2), -// Spv3 = underlyingGroup.Sum(g => g.Spv3), -// Spv4 = underlyingGroup.Sum(g => g.Spv4), -// //负数代表客户应缴保证金,正数代表客户应收保证金 -// WorstCastClientPayable = (PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key) != null && clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin == 1) ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, -// TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic == null ? 0 : (clientAdditionalMarginDic.ContainsKey(clientGroup.Key ?? 0) ? clientAdditionalMarginDic[clientGroup.Key ?? 0] : 0) -// }; -// clientSpanNews.Add(clientSpan); -// } -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// //var clientIds = clientSpanNews.Select(t => t.ClientId).Distinct().ToList(); -// //var clientSpanOlds = db.client_span.Where(t => t.SpanType == SpanType); -// if (RefreshClientIds != null) -// { -// //clientSpanOlds = db.client_span.Where(t => RefreshClientIds.Contains(t.ClientId ?? 0)); -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}=@SpanType", new { SpanType }); -// } -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOlds); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// //var clientSpanOldsWithOutFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && !t.ModifiedFlag).ToList(); -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOldsWithOutFlag); -// db.BulkDelete($"{nameof(client_span.ValueDate)}=@settleDate and {nameof(client_span.SpanType)}=@SpanType and {nameof(client_span.ModifiedFlag)}=0", new { settleDate, SpanType }); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// if (trade.TradeType == "结构化交易" && trade.id > 0) -// { -// using (YLContext db = new YLContext()) -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/FDMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/FDMarginCalculation.cs deleted file mode 100644 index 2ec61164..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/FDMarginCalculation.cs +++ /dev/null @@ -1,338 +0,0 @@ -//using BaseOUDAL; -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation; -//using YLErp.BLL.Calculation.V2; -//using YLErp.BLL.Eod; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.Modules.DataCacheModule; -//using YLErp.Modules.TradeDalModule; -//using YLErp.Modules.VolatilityModule; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 方顿 -// /// -// public class FDMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly FDMarginCalculation Instance; - -// static FDMarginCalculation() -// { -// Instance = new FDMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private FDMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// List tradeSpans = new List();//结果集 -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return tradeSpans; -// } -// using (YLContext db = new YLContext()) -// { -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// var lastSettleDate = EodOperationBase.GetLastSettlementDate(settleDate, true); -// var tradeIds = tradeList.Select(t => t.id).ToList(); -// var tradeMetaDatas = db.TradeMeta.Where(m => tradeIds.Contains(m.TradeId)).ToList().GroupBy(t => t.TradeId).ToDictionary(g => g.Key, g => g.ToDictionary(m => m.MetaKey, m => m.MetaValue)); -// var positionMaginRatioDic = db.TradeMeta.Where(m => tradeIds.Contains(m.TradeId) && m.MetaKey == ConsTradeMetaKey.PositionMarginRate) -// .ToList().ToDictionary(m => m.TradeId, m => DataConvert.ToDouble(m.MetaValue)); - -// new TradeDalService(new OptUserInfo(userId, userName)).SetSubTradeList(tradeList); -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(userId + "", settleDate, tradeList, priceDict, ValueCalculator.BASIC_PRICING, null, isEodSettle, volType, isUseTradeVol: PS.Config.IsTradeVol); -// logger.Info($"商品期货保证金计算,交易入:[{tradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); - -// //客户对应等级系数 -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// //计算保证金包含错误信息时弹出错误信息 -// if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage)) -// { -// throw new ServiceException(tradeRiskResult.ErrorMessage); -// } -// if (tradeRiskResult.Results.Count > 0) -// { -// var lastTradeSpanList = db.trade_span.Where(s => s.ValueDate == lastSettleDate).ToList(); -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); - -// Dictionary metaDics = null; -// if (tradeMetaDatas.ContainsKey(item.Trade.id)) -// { -// metaDics = tradeMetaDatas[item.Trade.id]; -// } -// #region 维持保证金率 -// var positionMaginRatio = 0.0; -// if (metaDics != null && metaDics.ContainsKey(ConsTradeMetaKey.PositionMarginRate)) -// { -// positionMaginRatio = DataConvert.ToDouble(metaDics[ConsTradeMetaKey.PositionMarginRate]); -// } - -// #endregion - -// #region 当前保证金额 -// var cashDeposit = 0.0; -// var lastTradeSpan = lastTradeSpanList.FirstOrDefault(s => s.TradeId == item.Trade.id); -// if (lastTradeSpan != null) -// { -// cashDeposit = (lastTradeSpan.CashDeposit ?? 0) + (lastTradeSpan.Margin ?? 0); -// } -// else if (metaDics != null && metaDics.ContainsKey(ConsTradeMetaKey.InitialMarginMoney)) -// { -// cashDeposit = DataConvert.ToDouble(metaDics[ConsTradeMetaKey.InitialMarginMoney]); -// } - -// #endregion - -// var value = Math.Abs(item.ValueResult.DeltaCash) * positionMaginRatio * (item.Trade.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.client.HasTwoSideMargin == 1 ? -1 : 0)); -// var twoSideMargin = Math.Abs(item.ValueResult.DeltaCash) * positionMaginRatio * (item.Trade.BuySell == "买入" ? 1 : -1); - -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate:yyyy-MM-dd}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// twoSideMargin = eodTradeRiskManual?.Margin ?? 0; -// } - -// #region 风险敞口 -// var riskExposure = 0.0; -// if (item.Trade.BuySell == "买入") -// { -// //这个地方很诡异,GetAsianFinalPrice和ActualStrike使用了相同的逻辑取均价,不同的地方在于ActualStrike使用的是系统日期,但这样又会造成历史收盘的偏差 -// riskExposure = Math.Max(0, (trade_asian_optionBLL.GetAsianFinalPrice(item.Trade, settleDate) - item.Trade.ActualStrike ?? 0) * (item.Trade.OptionType == "看涨" ? 1 : -1)) * item.Trade.Notional; -// } -// #endregion -// //是否需要追保 -// var needMargin = (riskExposure - cashDeposit) > 0; - -// tradeSpans.Add(new trade_span -// { -// TradeId = item.Trade.id,//默认记录为第一条交易记录中 -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = item.Trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = item.Trade.UnderlyingId, -// UnderlyingCode = item.Trade.UnderlyingCode, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// TwoSideMargin = twoSideMargin, -// RiskExposure = riskExposure, -// CashDeposit = cashDeposit, -// Margin = needMargin ? (riskExposure - cashDeposit + Math.Max(value, 0)) : 0, -// Comment = $"DeltaCash:{item.ValueResult.DeltaCash},PositionMaginRatio:{positionMaginRatio}" -// }); -// } -// } -// return tradeSpans; -// } -// } - -// /// -// /// 获取初始保证金率 -// /// -// /// -// /// -// public double? GetInitialMarginRatio(trade trade) -// { -// if (trade == null) -// { -// return 0; -// } -// if (!trade.VarietyId.HasValue || trade.VarietyId <= 0) -// { -// return 0; -// } -// if (!trade.StockEqvNotional.HasValue) -// { -// return 0; -// } -// var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0); -// if (variety == null) -// { -// return 0; -// } - -// //OTC-8856 Start -// var UpLimitValue = variety.UpLimitValue; -// //var UpLimitValue =((Math.Abs(trade.Underlying.UpDownLimitValue) > 1e-5) ? trade.Underlying.UpDownLimitValue : variety.UpLimitValue); -// //End - -// if (trade.StockEqvNotional <= 5000000) -// { -// return 2 * UpLimitValue; -// } -// else if (trade.StockEqvNotional <= 10000000) -// { -// return 2.5 * UpLimitValue; -// } -// else if (trade.StockEqvNotional <= 20000000) -// { -// return 3 * UpLimitValue; -// } -// return null; -// } - -// /// -// /// 获取维持保证金率 -// /// -// /// -// /// -// public double? GetPositionMarginRatio(trade trade) -// { -// if (trade == null) -// { -// return 0; -// } -// if (!trade.VarietyId.HasValue || trade.VarietyId <= 0) -// { -// return 0; -// } -// if (!trade.StockEqvNotional.HasValue) -// { -// return 0; -// } - -// //underlying_manager - - -// var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0); -// if (variety == null) -// { -// return 0; -// } -// if (trade.StockEqvNotional <= 5000000) -// { -// return 1.5 * variety.UpLimitValue; -// } -// else if (trade.StockEqvNotional <= 10000000) -// { -// return 2 * variety.UpLimitValue; -// } -// else if (trade.StockEqvNotional <= 20000000) -// { -// return 2.5 * variety.UpLimitValue; -// } -// return null; -// } - -// /// -// /// 获取初始保证金 -// /// -// /// -// /// -// public double GetInitialMargin(trade trade) -// { -// return DoInitialMarginCalculationV2(trade); -// } - -// public double DoInitialMarginCalculationV2(trade trade) -// { -// if (trade.BuySell == "卖出") -// { -// return 0; -// } - -// var underlying = DataCacheManager.GetUnderlyingDataSource().GetData(trade.UnderlyingId); -// underlying.QuotationDate = trade.TradeDate; - -// var spotPrices = new double[] { trade.SpotPrice ?? 0 }; - -// string userGroup = UserBLL.GetUserGroup(trade.TraderId ?? 0); -// var volSurfaceData = VolatilityHelper.GetVol(underlying.QuotationDate.Value, "交易", underlying.UnderlyingCode, userGroup); - -// var vol = OptionCalculator.GetInterpolatedVol( -// VolConstructionType.Normal, -// trade.OptId.ToString(), -// volSurfaceData, -// underlying.QuotationDate?.ToString("yyyy-MM-dd"), -// underlying.UnderlyingCode, -// trade.ExerciseDate?.ToString("yyyy-MM-dd"), -// trade.Strike ?? 0.0, -// isBuy: true, -// isCall: trade.CallPut == "Call", -// spotPrice: spotPrices[0], -// isMoneynessOption: trade.IsMoneynessOptionData, -// timeToMaturityDays: trade.TTMDays ?? double.NaN); - -// if (!trade.NoRiskRate.HasValue) -// { -// trade.NoRiskRate = (valuedateBLL.SystemDate.RiskFreeRate ?? 0) * 0.01; -// } - -// string fixing = null; -// //亚式期权 -// if (trade.TradeType == "亚式期权" || trade.StructureType == "亚式熊市价差") -// { -// fixing = CalculatorHelper.GetFixingStringForAsianOption(trade, trade.TradeDate); -// } -// var optionValue = ValueCalculator.GetOptionValueResultV2( -// trade.OptId.ToString(), -// underlying, -// trade, -// new double[] { vol }, -// spotPrices, -// fixing, -// commodityFuturesPreciseTimeMode: true); -// //保证金初始价值=期初期权价值+CashDelta(t)*保证金初始比例(保证金初始比例) -// return (trade.TradePrice ?? 0) + ((optionValue == null) ? 0 : Math.Abs(optionValue.DeltaCash)) * (trade.InitialMarginRatio ?? 0); -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GDGZMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GDGZMarginCalculation.cs deleted file mode 100644 index e4e809a8..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GDGZMarginCalculation.cs +++ /dev/null @@ -1,608 +0,0 @@ -//using BaseOUDAL; -//using Qdp.Foundation.Implementations; -//using Qdp.Pricing.Base.Implementations; -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.Commons; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.Modules.DataCacheModule; -//using YLErp.Modules.VolatilityModule; -//using YLErp.Modules.VolatilityModule.SkewMapVolModule; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// public class GDGZMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例(单例模式) -// public static readonly GDGZMarginCalculation Instance; - -// static GDGZMarginCalculation() -// { -// Instance = new GDGZMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private GDGZMarginCalculation() -// { - -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// Dictionary resultMap = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// //为了算客户角度的一个保证金数值 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } -// var underlyingIds = priceDict.Keys.ToList(); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.CommodityCode equals variety.VarietyCode -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// defUpLimit = variety.UpLimit, -// defDownLimit = variety.DownLimit, -// defVolatilityRate = variety.VolatilityRate -// }).ToList(); - -// var UpLimitDict = new Dictionary(); -// var DownLimitDict = new Dictionary(); -// var umVolatilityRateDic = new Dictionary(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// //OTC-8856 Start -// //1.波动率变化 -// if (DataConvert.TryParsePercentValue(t.VolatilityRate, out double pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } -// else if (DataConvert.TryParsePercentValue(t.defVolatilityRate, out pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } - -// //2.涨跌停板幅度 -// if (!string.IsNullOrWhiteSpace(t.UpDownLimit)) -// { -// UpLimitDict[t.id] = t.UpDownLimit;//百分比或绝对值 -// DownLimitDict[t.id] = t.UpDownLimit; -// } -// else -// { -// UpLimitDict[t.id] = t.defUpLimit?.ToString() ?? "5%"; -// DownLimitDict[t.id] = t.defDownLimit?.ToString() ?? "5%"; -// } -// }); -// } - -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// var tradeVolatilityRateDic = tradeList.ToDictionary(t => t.id, t => umVolatilityRateDic.ContainsKey(t.UnderlyingId) ? umVolatilityRateDic[t.UnderlyingId] : 0) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// Dictionary> eodPriceDict = new Dictionary>(); -// var upLimitPrices = new Dictionary(); -// var downLimitPrices = new Dictionary(); -// double tempDouble; -// //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 -// foreach (var t in priceDict) -// { -// //OTC-8856 Start -// //UpLimit -// if (UpLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = UpLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// upLimitPrices[t.Key] = t.Value * (1 + (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// upLimitPrices[t.Key] = t.Value + Math.Abs(tempAbs); -// } -// } -// else -// { -// upLimitPrices[t.Key] = t.Value * 1.05; -// } - -// //DownLimit -// if (DownLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = DownLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// downLimitPrices[t.Key] = t.Value * (1 - (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// downLimitPrices[t.Key] = t.Value - Math.Abs(tempAbs); -// } -// } -// else -// { -// downLimitPrices[t.Key] = t.Value * 0.95; -// } -// //End -// } -// eodPriceDict["up"] = upLimitPrices; -// eodPriceDict["down"] = downLimitPrices; - -// //波动率变化 -// var addVolRateList = new List> { null, tradeVolatilityRateDic }; - -// //交易对应客户信息 -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// var userIdNew = UniqueTimeId.Get().ToString(); - -// try -// { -// foreach (var price in eodPriceDict) -// { -// addVolRateList.ForEach(addVolRateDic => -// { -// var key = $"{price.Key}_{(addVolRateDic == null ? 0 : 1)}"; -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userIdNew, // userId + "_" + price.Key, -// settleDate, -// tradeList, -// price.Value, -// ValueCalculator.PV_ONLY, -// addVolRateDic, -// isEodSettle, -// volType, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle, -// isAddVolPercent: false); -// if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) -// { -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// var noMinusPv = !PS.Config.ErpElement.TwoSideMargin || client == null || client.client == null || client.client.HasTwoSideMargin != 1; - -// double value = 0; -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// if (resultMap.ContainsKey(item.Trade.id)) -// { -// switch (key) -// { -// case "up_0": -// resultMap[item.Trade.id].Spv1 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_1": -// resultMap[item.Trade.id].Spv2 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// resultMap[item.Trade.id].Spv3 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// resultMap[item.Trade.id].Spv4 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// //非双向保证金,pv为负的情况置为0 -// if (noMinusPv) -// { -// resultMap[item.Trade.id].Spv1 = Math.Max(resultMap[item.Trade.id].Spv1 ?? 0, 0); -// resultMap[item.Trade.id].Spv2 = Math.Max(resultMap[item.Trade.id].Spv2 ?? 0, 0); -// resultMap[item.Trade.id].Spv3 = Math.Max(resultMap[item.Trade.id].Spv3 ?? 0, 0); -// resultMap[item.Trade.id].Spv4 = Math.Max(resultMap[item.Trade.id].Spv4 ?? 0, 0); -// } -// resultMap[item.Trade.id].setWorstCastClientPayable4(); -// } -// else -// { -// var trade = tradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var tempTradeSpan = new trade_span -// { -// TradeId = item.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now -// }; -// switch (key) -// { -// case "up_0": -// tempTradeSpan.Spv1 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_1": -// tempTradeSpan.Spv2 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// tempTradeSpan.Spv3 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// tempTradeSpan.Spv4 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// //非双向保证金,pv为负的情况置为0 -// if (noMinusPv) -// { -// tempTradeSpan.Spv1 = Math.Max(tempTradeSpan.Spv1 ?? 0, 0); -// tempTradeSpan.Spv2 = Math.Max(tempTradeSpan.Spv2 ?? 0, 0); -// tempTradeSpan.Spv3 = Math.Max(tempTradeSpan.Spv3 ?? 0, 0); -// tempTradeSpan.Spv4 = Math.Max(tempTradeSpan.Spv4 ?? 0, 0); -// } -// resultMap[item.Trade.id] = tempTradeSpan; -// } -// } -// } -// }); -// } -// } -// finally -// { -// //上面的计算用到静态生成market,需要清除 -// QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userIdNew); -// } - -// //为了保持原有交易买卖方向不变 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } - -// return resultMap.Values.ToList(); -// } -// } - -// public override bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = false, Dictionary clientAdditionalMarginDic = null) -// { -// using (YLContext db = new YLContext()) -// { -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// var clientSpanNews = new List(); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// UnderlyingId = t.Key, -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - -// item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - -// #region 更新tradeSpan,使得每笔交易的持仓保证金和客户保证金计算用的Spv组保持一致 - -// var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == settleDate).ToList(); -// if (item.WorstCastClientPayable == item.Spv1) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); -// } -// else if (item.WorstCastClientPayable == item.Spv2) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); -// } -// else if (item.WorstCastClientPayable == item.Spv3) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); -// } -// else -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); -// } - -// #endregion - -// if (!PS.Config.ErpElement.TwoSideMargin || clientList.FirstOrDefault(x => x.id == clientGroup.Key) == null || clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin != 1) -// { -// item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable.Value, 0); -// } -// } -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = underlyingGroup.Sum(g => g.Spv1), -// Spv2 = underlyingGroup.Sum(g => g.Spv2), -// Spv3 = underlyingGroup.Sum(g => g.Spv3), -// Spv4 = underlyingGroup.Sum(g => g.Spv4), -// //负数代表客户应缴保证金,正数代表客户应收保证金 -// WorstCastClientPayable = (PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key) != null && clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin == 1) ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, -// TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic == null ? 0 : (clientAdditionalMarginDic.ContainsKey(clientGroup.Key ?? 0) ? clientAdditionalMarginDic[clientGroup.Key ?? 0] : 0) -// }; -// clientSpanNews.Add(clientSpan); -// } - -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// //var clientIds = clientSpanNews.Select(t => t.ClientId).Distinct().ToList(); -// //var clientSpanOlds = db.client_span.Where(t => t.SpanType == SpanType); -// if (RefreshClientIds != null) -// { -// //clientSpanOlds = db.client_span.Where(t => RefreshClientIds.Contains(t.ClientId ?? 0)); -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}=@SpanType", new { SpanType }); -// } -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOlds); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// //var clientSpanOldsWithOutFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && !t.ModifiedFlag).ToList(); -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOldsWithOutFlag); -// db.BulkDelete($"{nameof(client_span.ValueDate)}=@settleDate and {nameof(client_span.SpanType)}=@SpanType and {nameof(client_span.ModifiedFlag)}=0", new { settleDate, SpanType }); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } - -// /// -// /// 获取初始保证金 -// /// -// public double GetInitialMargin(trade trade) -// { -// return DoInitialMarginCalculationV2(trade); -// } - -// public double DoInitialMarginCalculationV2(trade trade) -// { -// if (trade.BuySell == "卖出") -// { -// return 0; -// } - -// //string userId = "0"; - -// var underlying = DataCacheManager.GetUnderlyingDataSource().GetData(trade.UnderlyingId); -// var under = underlying.Clone(); -// under.QuotationDate = trade.TradeDate; -// var variety = DataCacheManager.GetVarietyDataSource().GetData(under.UnderlyingTypeId); -// double clientRatio = 1; -// if (trade.ClientId > 0) -// { -// using (YLContext db = new YLContext()) -// { -// var query = from c in db.client -// join cl in db.clientlevel on c.LevelId equals cl.id -// where c.id == trade.ClientId -// select cl.Ratio; -// clientRatio = query.FirstOrDefault() ?? 1; -// } -// } - -// if (PS.Config.IsTradeVol) -// { -// //如果没有开仓波动率,则调用接口计算出一个开仓波动率 -// if (trade.TradeOpenVolatility == null || trade.TradeOpenVolatility == 0) -// { - -// string userGroup = UserBLL.GetUserGroup(trade.TraderId ?? 0); -// var vol = VolatilityHelper.GetVol( -// trade.TradeDate.Value, -// "交易", -// under.UnderlyingCode, -// userGroup); -// var baseVol = BaseVolService.GetBaseVol(new BaseVolReq(under, trade), trade.TraderId ?? 0); -// var skewvol = new SkewVolReq -// { -// AskVar = vol.GetAskVar(), -// BidVar = vol.GetBidVar(), -// BaseVol = baseVol -// }; -// trade.TradeOpenVolatility = SingleVolService.GetSingleVol(new SingleVolReq(trade, under, skewvol), trade.TraderId ?? 0); -// } -// } -// else -// { -// throw new ServiceException("光大光子仅支持TradeVol"); -// } - -// if (under.QuotationDate != valuedateBLL.ValueDate.Date) -// { -// //为了暂时修复一个QDP计算方式与客户需求不匹配的情况 -// //在非精确模式下,QDP不包括交易日当天的时间价值,但根据报价需求,需要将交易日当天的时间价值计算在内, -// //所以要将交易日向前移动一天。未来QDP支持传递TTM来计算时,可以直接在TTM上加1,而不用移动交易日 -// //注意:当前这个临时修改必须在InitializeMarketProxy之前调用,这样才能正确设置波动率日期 -// var calendar = CalendarImpl.Get("chn"); -// var qdpDate = new Date(DateTime.Parse(under.QuotationDate.ToString())); -// under.QuotationDate = calendar.PrevBizDay(qdpDate).DateTime; -// } - -// //OTC-8856 Start -// //UpLimit -// double priceUp = 0; -// if (!string.IsNullOrWhiteSpace(under.UpDownLimit)) -// { -// var tempVaue = under.UpDownLimit; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out double tempDouble); -// priceUp = (trade.SpotPrice ?? 0) * (1 + (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// priceUp = (trade.SpotPrice ?? 0) + Math.Abs(tempAbs); -// } -// } -// else -// { -// double.TryParse(variety?.UpLimit?.Replace("%", ""), out double tempDouble); -// priceUp = (trade.SpotPrice ?? 0) * (1 + (tempDouble * 0.01)); -// } - -// // -// double priceDown = 0; -// if (!string.IsNullOrWhiteSpace(under.UpDownLimit)) -// { -// var tempVaue = under.UpDownLimit; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out double tempDouble); -// priceDown = (trade.SpotPrice ?? 0) * (1 - (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// priceDown = (trade.SpotPrice ?? 0) - Math.Abs(tempAbs); -// } -// } -// else -// { -// double.TryParse(variety?.DownLimit?.Replace("%", ""), out double tempDouble); -// priceDown = (trade.SpotPrice ?? 0) * (1 - (tempDouble * 0.01)); -// } - -// DataConvert.TryParsePercentValue(under.VolatilityRate, out double volatilityRate); -// if (Math.Abs(volatilityRate) < 1e-5) -// { -// volatilityRate = variety.VolatilityRateValue; -// } - -// var tradeSpan = new trade_span(); -// var userId = Guid.NewGuid().ToString(); - -// var result = ValueCalculator.GetOptionValueResultV2(userId, under, trade, new double[] { trade.TradeOpenVolatility.Value }, new double[] { priceUp }, request: ValueCalculator.PV_ONLY); -// tradeSpan.Spv1 = (double.IsNaN(result.Pv) ? 0 : result.Pv) * clientRatio; -// result = ValueCalculator.GetOptionValueResultV2(userId, under, trade, new double[] { trade.TradeOpenVolatility.Value * (1 + volatilityRate) }, new double[] { priceUp }, request: ValueCalculator.PV_ONLY); -// tradeSpan.Spv2 = (double.IsNaN(result.Pv) ? 0 : result.Pv) * clientRatio; -// result = ValueCalculator.GetOptionValueResultV2(userId, under, trade, new double[] { trade.TradeOpenVolatility.Value }, new double[] { priceDown }, request: ValueCalculator.PV_ONLY); -// tradeSpan.Spv3 = (double.IsNaN(result.Pv) ? 0 : result.Pv) * clientRatio; -// result = ValueCalculator.GetOptionValueResultV2(userId, under, trade, new double[] { trade.TradeOpenVolatility.Value * (1 + volatilityRate) }, new double[] { priceDown }, request: ValueCalculator.PV_ONLY); -// tradeSpan.Spv4 = (double.IsNaN(result.Pv) ? 0 : result.Pv) * clientRatio; - -// tradeSpan.setWorstCastClientPayable4(); - -// return tradeSpan.WorstCastClientPayable ?? 0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GTJAMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GTJAMarginCalculation.cs deleted file mode 100644 index 8e22c10e..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/GTJAMarginCalculation.cs +++ /dev/null @@ -1,487 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.Commons; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 国泰君安保证金计算 -// /// -// public class GTJAMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly GTJAMarginCalculation Instance; - -// static GTJAMarginCalculation() -// { -// Instance = new GTJAMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// protected GTJAMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, -// Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// Dictionary resultMap = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// //为了算客户角度的一个保证金数值 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = GetSettlePrice(codes, settleDate, "收盘价"); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } -// var underlyingIds = priceDict.Keys.ToList(); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.UnderlyingTypeId equals variety.id into t_variety -// from variety in t_variety.DefaultIfEmpty() -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// defUpLimit = variety == null ? null : variety.UpLimit, -// defDownLimit = variety == null ? null : variety.DownLimit, -// defVolatilityRate = variety == null ? null : variety.VolatilityRate -// }).ToList(); - -// var UpLimitDict = new Dictionary(); -// var DownLimitDict = new Dictionary(); -// var umVolatilityRateDic = new Dictionary(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// //OTC-8856 Start -// //1.波动率变化 -// if (DataConvert.TryParsePercentValue(t.VolatilityRate, out double pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } -// else if (DataConvert.TryParsePercentValue(t.defVolatilityRate, out pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } - -// //2.涨跌停板幅度 -// if (!string.IsNullOrWhiteSpace(t.UpDownLimit)) -// { -// UpLimitDict[t.id] = t.UpDownLimit;//百分比或绝对值 -// DownLimitDict[t.id] = t.UpDownLimit; -// } -// else -// { -// UpLimitDict[t.id] = t.defUpLimit?.ToString() ?? "5%"; -// DownLimitDict[t.id] = t.defDownLimit?.ToString() ?? "5%"; -// } -// }); -// } - -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// //判断当日结算价是否已经入库 -// //if (priceDict == null || priceDict.Count == 0) -// //{ -// // throw new Exception("当日结算价还未同步,请等待结算价自动同步完成或手动同步后再执行收盘操作!"); -// //} - -// var tradeVolatilityRateDic = tradeList.ToDictionary(t => t.id, t => umVolatilityRateDic.ContainsKey(t.UnderlyingId) ? umVolatilityRateDic[t.UnderlyingId] : 0) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// Dictionary> eodPriceDict = new Dictionary>(); -// var upLimitPrices = new Dictionary(); -// var downLimitPrices = new Dictionary(); -// double tempDouble; -// //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 -// if (priceDict != null && priceDict.Count > 0) -// { -// foreach (var t in priceDict) -// { -// //OTC-8856 Start -// //UpLimit -// if (UpLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = UpLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// upLimitPrices[t.Key] = t.Value + Math.Abs(t.Value * tempDouble * 0.01); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// upLimitPrices[t.Key] = t.Value + Math.Abs(tempAbs); -// } -// } -// else -// { -// upLimitPrices[t.Key] = t.Value * 1.05; -// } - -// //DownLimit -// if (DownLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = DownLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// downLimitPrices[t.Key] = t.Value - Math.Abs(t.Value * tempDouble * 0.01); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// downLimitPrices[t.Key] = t.Value - Math.Abs(tempAbs); -// } -// } -// else -// { -// downLimitPrices[t.Key] = t.Value * 0.95; -// } -// //End -// } -// eodPriceDict["up"] = upLimitPrices; -// eodPriceDict["down"] = downLimitPrices; -// } -// //波动率变化 -// var addVolRateList = new List> { null, tradeVolatilityRateDic }; -// //交易对应客户信息 -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// var userIdNew = UniqueTimeId.Get().ToString(); - -// try -// { -// foreach (var price in eodPriceDict) -// { -// addVolRateList.ForEach(addVolRateDic => -// { -// var key = $"{price.Key}_{(addVolRateDic == null ? 0 : 1)}"; -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userIdNew, // userId + "_" + price.Key, -// settleDate, -// tradeList, -// price.Value, -// ValueCalculator.PV_ONLY, -// addVolRateDic, -// isEodSettle, -// volType, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle, -// isAddVolPercent: false); -// if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) -// { -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// double value = 0; -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// else if (item.Trade.TradeType == "权益互换") -// { -// value = (item.Trade.trade_swap.GetMarginRate ?? 0) * (item.Trade.StockEqvNotional ?? 0) + Math.Max((double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv), 0); -// } -// if (resultMap.ContainsKey(item.Trade.id)) -// { -// switch (key) -// { -// case "up_0": -// resultMap[item.Trade.id].Spv1 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_1": -// resultMap[item.Trade.id].Spv2 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// resultMap[item.Trade.id].Spv3 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// resultMap[item.Trade.id].Spv4 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id].setWorstCastClientPayable4(); -// } -// else -// { -// var trade = tradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var tempTradeSpan = new trade_span -// { -// TradeId = item.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now -// }; -// switch (key) -// { -// case "up_0": -// tempTradeSpan.Spv1 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_1": -// tempTradeSpan.Spv2 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// tempTradeSpan.Spv3 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// tempTradeSpan.Spv4 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id] = tempTradeSpan; -// } -// } -// } -// }); -// } -// } -// finally -// { -// //上面的计算用到静态生成market,需要清除 -// QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userIdNew); -// } - -// //为了保持原有交易买卖方向不变 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } - -// return resultMap.Values.ToList(); -// } -// } - -// public override bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = false, Dictionary clientAdditionalMarginDic = null) -// { -// using (YLContext db = new YLContext()) -// { -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); -// var tradeSpanInfoOtherSide = (from tradeSpan in tradeSpansOtherSide -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// var clientSpanNews = new List(); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// UnderlyingId = t.Key, -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - -// item.TwoSideMargin = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); - -// #region 更新tradeSpan,使得每笔交易的持仓保证金和客户保证金计算用的Spv组保持一致 - -// var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == settleDate).ToList(); -// if (item.WorstCastClientPayable == item.Spv1) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); -// } -// else if (item.WorstCastClientPayable == item.Spv2) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); -// } -// else if (item.WorstCastClientPayable == item.Spv3) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); -// } -// else -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); -// } - -// #endregion - -// if (!PS.Config.ErpElement.NonInterBankMarginNetting) -// { -// item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable.Value, 0); -// } -// } -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = underlyingGroup.Sum(g => g.Spv1), -// Spv2 = underlyingGroup.Sum(g => g.Spv2), -// Spv3 = underlyingGroup.Sum(g => g.Spv3), -// Spv4 = underlyingGroup.Sum(g => g.Spv4), -// //负数代表客户应缴保证金,正数代表客户应收保证金 -// WorstCastClientPayable = (PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key) != null && clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin == 1) ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, -// TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic == null ? 0 : (clientAdditionalMarginDic.ContainsKey(clientGroup.Key ?? 0) ? clientAdditionalMarginDic[clientGroup.Key ?? 0] : 0) -// }; -// clientSpanNews.Add(clientSpan); -// } - -// //处理从客户角度的保证金计算(将交易买卖方向反向处理) -// var clientGroupsOtherSide = tradeSpanInfoOtherSide.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroupsOtherSide) -// { -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// if (PS.Config.ErpElement.NonInterBankMarginNetting) -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0); -// } -// else -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), 0); -// } -// } - -// var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == settleDate); -// clientSpan.OtherSideMargin = (PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key) != null && clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin == 1) ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0; -// } - -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// if (RefreshClientIds != null) -// { -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}=@SpanType", new { SpanType }); -// } -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.ValueDate)}=@settleDate and {nameof(client_span.SpanType)}=@SpanType and {nameof(client_span.ModifiedFlag)}=0", new { settleDate, SpanType }); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag) -// .Select(n => new { n.ValueDate, n.ClientId }).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HaiTongMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HaiTongMarginCalculation.cs deleted file mode 100644 index 0233ba0f..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HaiTongMarginCalculation.cs +++ /dev/null @@ -1,502 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.Commons; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 国泰君安保证金计算 -// /// -// public class HaiTongMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly HaiTongMarginCalculation Instance; - -// static HaiTongMarginCalculation() -// { -// Instance = new HaiTongMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// protected HaiTongMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// Dictionary resultMap = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// //为了算客户角度的一个保证金数值 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } - -// var underlyingIds = priceDict.Keys.ToList(); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.CommodityCode equals variety.VarietyCode -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// defUpLimit = variety.UpLimit, -// defDownLimit = variety.DownLimit, -// defVolatilityRate = variety.VolatilityRate -// }).ToList(); - -// var UpLimitDict = new Dictionary(); -// var DownLimitDict = new Dictionary(); -// var umVolatilityRateDic = new Dictionary(); -// var downVolatilityRateDic = new Dictionary(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// //OTC-8856 Start -// //1.波动率变化 -// if (DataConvert.TryParsePercentValue(t.VolatilityRate, out double pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// downVolatilityRateDic[t.id] = -pvalue; -// } -// else if (DataConvert.TryParsePercentValue(t.defVolatilityRate, out pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// downVolatilityRateDic[t.id] = -pvalue; -// } - -// //2.涨跌停板幅度 -// if (!string.IsNullOrWhiteSpace(t.UpDownLimit)) -// { -// UpLimitDict[t.id] = t.UpDownLimit;//百分比或绝对值 -// DownLimitDict[t.id] = t.UpDownLimit; -// } -// else -// { -// UpLimitDict[t.id] = t.defUpLimit?.ToString() ?? "5%"; -// DownLimitDict[t.id] = t.defDownLimit?.ToString() ?? "5%"; -// } -// }); -// } - -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// var tradeVolatilityRateDicUp = tradeList.ToDictionary(t => t.id, t => umVolatilityRateDic.ContainsKey(t.UnderlyingId) ? umVolatilityRateDic[t.UnderlyingId] : 0) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// var tradeVolatilityRateDicDown = tradeList.ToDictionary(t => t.id, t => downVolatilityRateDic.ContainsKey(t.UnderlyingId) ? downVolatilityRateDic[t.UnderlyingId] : 0) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// Dictionary> eodPriceDict = new Dictionary>(); -// var upLimitPrices = new Dictionary(); -// var downLimitPrices = new Dictionary(); -// var normalLimitPrices = new Dictionary(); -// double tempDouble; -// //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 -// foreach (var t in priceDict) -// { -// //UpLimit -// if (UpLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = UpLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// upLimitPrices[t.Key] = t.Value * (1 + (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// upLimitPrices[t.Key] = t.Value + Math.Abs(tempAbs); -// } -// } -// else -// { -// upLimitPrices[t.Key] = t.Value * 1.05; -// } - -// //DownLimit -// if (DownLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = DownLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// downLimitPrices[t.Key] = t.Value * (1 - (tempDouble * 0.01)); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// downLimitPrices[t.Key] = t.Value - Math.Abs(tempAbs); -// } -// } -// else -// { -// downLimitPrices[t.Key] = t.Value * 0.95; -// } - -// //Normal -// normalLimitPrices[t.Key] = t.Value; -// } -// eodPriceDict["up"] = upLimitPrices; -// eodPriceDict["down"] = downLimitPrices; -// eodPriceDict["normal"] = normalLimitPrices; - -// //波动率变化 -// var addVolRateDic = new Dictionary>(); -// addVolRateDic[0] = null; -// addVolRateDic[1] = tradeVolatilityRateDicUp; -// addVolRateDic[2] = tradeVolatilityRateDicDown; - -// //交易对应客户信息 -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// var userIdNew = UniqueTimeId.Get().ToString(); - -// try -// { -// foreach (var price in eodPriceDict) -// { -// foreach (var itemDic in addVolRateDic) -// { -// var key = $"{price.Key}_{itemDic.Key}"; -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userIdNew, // userId + "_" + price.Key, -// settleDate, -// tradeList, -// price.Value, -// ValueCalculator.PV_ONLY, -// itemDic.Value, -// isEodSettle, -// volType, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle, -// isAddVolPercent: false); -// if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) -// { -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// double value = 0; -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// if (resultMap.ContainsKey(item.Trade.id)) -// { -// switch (key) -// { -// case "up_1": -// resultMap[item.Trade.id].Spv1 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_0": -// resultMap[item.Trade.id].Spv2 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_2": -// resultMap[item.Trade.id].Spv3 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_1": -// resultMap[item.Trade.id].Spv4 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_2": -// resultMap[item.Trade.id].Spv5 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// resultMap[item.Trade.id].Spv6 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// resultMap[item.Trade.id].Spv7 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_2": -// resultMap[item.Trade.id].Spv8 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id].setWorstCastClientPayable8(); -// } -// else -// { -// var trade = tradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var tempTradeSpan = new trade_span -// { -// TradeId = item.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now -// }; -// switch (key) -// { -// case "up_1": -// tempTradeSpan.Spv1 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_0": -// tempTradeSpan.Spv2 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "up_2": -// tempTradeSpan.Spv3 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_1": -// tempTradeSpan.Spv4 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_2": -// tempTradeSpan.Spv5 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// tempTradeSpan.Spv6 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_0": -// tempTradeSpan.Spv7 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_2": -// tempTradeSpan.Spv8 = item.Trade.TradeType == "自定义交易" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id] = tempTradeSpan; -// } -// } -// } -// } -// } -// } -// finally -// { -// //上面的计算用到静态生成market,需要清除 -// QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userIdNew); -// } - -// //为了保持原有交易买卖方向不变 -// if (forOtherSide) -// { -// tradeList.ForEach(x => x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"); -// } - -// return resultMap.Values.ToList(); -// } -// } - -// public override bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = false, Dictionary clientAdditionalMarginDic = null) -// { -// using (YLContext db = new YLContext()) -// { -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// var clientSpanNews = new List(); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// UnderlyingId = t.Key, -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), -// Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), -// Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), -// Spv8 = t.Sum(g => g.tradeSpan.Spv8) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// item.WorstCastClientPayable = new double[] { -// item.Spv1 ?? 0, item.Spv2 ?? 0, item.Spv3 ?? 0, item.Spv4 ?? 0, item.Spv5 ?? 0, item.Spv6 ?? 0, item.Spv7 ?? 0, item.Spv8 ?? 0 -// }.Min(); - -// #region 更新tradeSpan,使得每笔交易的持仓保证金和客户保证金计算用的Spv组保持一致 - -// var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == settleDate).ToList(); -// if (item.WorstCastClientPayable == item.Spv1) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); -// } -// else if (item.WorstCastClientPayable == item.Spv2) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); -// } -// else if (item.WorstCastClientPayable == item.Spv3) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); -// } -// else if (item.WorstCastClientPayable == item.Spv4) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); -// } -// else if (item.WorstCastClientPayable == item.Spv5) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); -// } -// else if (item.WorstCastClientPayable == item.Spv6) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); -// } -// else if (item.WorstCastClientPayable == item.Spv7) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); -// } -// else -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8); -// } - -// #endregion - -// if (!PS.Config.ErpElement.NonInterBankMarginNetting) -// { -// item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable.Value, 0); -// } -// } -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = underlyingGroup.Sum(g => g.Spv1), -// Spv2 = underlyingGroup.Sum(g => g.Spv2), -// Spv3 = underlyingGroup.Sum(g => g.Spv3), -// Spv4 = underlyingGroup.Sum(g => g.Spv4), -// Spv5 = underlyingGroup.Sum(g => g.Spv5), -// Spv6 = underlyingGroup.Sum(g => g.Spv6), -// Spv7 = underlyingGroup.Sum(g => g.Spv7), -// Spv8 = underlyingGroup.Sum(g => g.Spv8), -// //负数代表客户应缴保证金,正数代表客户应收保证金 -// WorstCastClientPayable = (PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key) != null && clientList.FirstOrDefault(x => x.id == clientGroup.Key).HasTwoSideMargin == 1) ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, -// TwoSideMargin = underlyingGroup.Sum(g => g.TwoSideMargin), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic == null ? 0 : (clientAdditionalMarginDic.ContainsKey(clientGroup.Key ?? 0) ? clientAdditionalMarginDic[clientGroup.Key ?? 0] : 0) -// }; -// clientSpanNews.Add(clientSpan); -// } - -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// //var clientIds = clientSpanNews.Select(t => t.ClientId).Distinct().ToList(); -// //var clientSpanOlds = db.client_span.Where(t => t.SpanType == SpanType); -// if (RefreshClientIds != null) -// { -// //clientSpanOlds = db.client_span.Where(t => RefreshClientIds.Contains(t.ClientId ?? 0)); -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}=@SpanType", new { SpanType }); -// } -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOlds); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// //var clientSpanOldsWithOutFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && !t.ModifiedFlag).ToList(); -// //MySqlBulkExtensions.BulkDelete(db, clientSpanOldsWithOutFlag); -// db.BulkDelete($"{nameof(client_span.ValueDate)}=@settleDate and {nameof(client_span.SpanType)}=@SpanType and {nameof(client_span.ModifiedFlag)}=0", new { settleDate, SpanType }); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HongYuanMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HongYuanMarginCalculation.cs deleted file mode 100644 index f63130c3..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/HongYuanMarginCalculation.cs +++ /dev/null @@ -1,202 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.DBModels; -//using YLErp.Model; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// public class HongYuanMarginCalculation : MarginCalculationBase -// { -// //定义一个静态变量来保存类的实例(单例模式) -// public static readonly HongYuanMarginCalculation Instance; - -// static HongYuanMarginCalculation() -// { -// Instance = new HongYuanMarginCalculation(); -// } - -// //定义私有构造函数,使外界不能创建该类实例 -// private HongYuanMarginCalculation() -// { - -// } - -// private List CalculationSingleTrade(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool isInitialMargin = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易") -// { -// //结果集 -// var resultMap = new Dictionary(); -// var tempTradeList = new List(); -// var codes = new HashSet(tradeList.Select(O => O.UnderlyingCode).ToArray()); -// if (!(priceDict?.Count > 0)) -// { -// //结算的时候价格列表一定是空的; -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// else -// { -// //价格列表不是空的说明是计算实时保证金或期初保证金 -// //宏源在计算实时保证金的时候使用前一天的收盘价这个逻辑是一开始确认的,后续对数据的时候要再次确认 --时嬴政 -// var lastDate = QdpCalendarHelper.GetNonHolidayDefore(settleDate.AddDays(-1)); -// priceDict = base.GetSettlePrice(codes, lastDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } -// var clientIds = new HashSet(tradeList.Select(O => O.ClientId ?? 0).ToArray()); -// var clientClassDict = new clientBLL().GetClients(clientIds.ToList()).ToDictionary(K => K.id, V => V.ProperClientClass); -// var ratioDict = new clientlevelBLL().GetClientlevels(clientIds).ToDictionary(K => K.Key, V => isInitialMargin ? (V.Value.Ratio1 ?? 1) : (V.Value.Ratio ?? 1)); -// var vols = new Dictionary(); -// tradeList.ForEach(t => -// { -// double vol = t.TradeOpenVolatility ?? 0; -// if (!clientClassDict.ContainsKey(t.ClientId ?? 0)) -// { -// throw new Exception($"交易编号为{t.TradeNumber}的客户适当性类型不存在,无法计算保证金!"); -// } -// if (clientClassDict[t.ClientId ?? 0].Contains("普通投资者")) -// { -// vol = vol * 1.2; -// } -// vols[t.id] = vol; -// tempTradeList.Add(t.Clone()); -// if (!priceDict.ContainsKey(t.UnderlyingId)) -// { priceDict[t.UnderlyingId] = t.SpotPrice ?? 0; } -// }); -// Action changeUmIdFunction = (t) => -// { -// if (t.OptionType == "看跌") -// { -// t.UnderlyingId = t.UnderlyingId * -1; -// if (t.trade_spread_option != null) -// { -// t.trade_spread_option.UnderlyingId1 = t.trade_spread_option.UnderlyingId1 * -1; -// t.trade_spread_option.UnderlyingId2 = t.trade_spread_option.UnderlyingId2 * -1; -// t.trade_spread_option.UnderlyingId3 = t.trade_spread_option.UnderlyingId3 * -1; -// t.trade_spread_option.UnderlyingId4 = t.trade_spread_option.UnderlyingId4 * -1; -// } -// if (t.trade_rainbow_option != null) -// { -// t.trade_rainbow_option.UnderlyingId1 = t.trade_rainbow_option.UnderlyingId1 * -1; -// t.trade_rainbow_option.UnderlyingId2 = t.trade_rainbow_option.UnderlyingId2 * -1; -// } -// } -// }; -// Dictionary dict = base.GetUpDownLimitPrice(priceDict); -// Dictionary underlyingPrice = new Dictionary(); -// tempTradeList.ForEach(t => -// { -// changeUmIdFunction(t); -// underlyingPrice[t.UnderlyingId] = t.OptionType == "看涨" ? dict[t.UnderlyingId][0] : dict[t.UnderlyingId][1]; -// }); -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userId.ToString(), // userId + "_" + price.Key, -// settleDate, -// tempTradeList, -// underlyingPrice, -// ValueCalculator.PV_ONLY, -// null, -// isEndOfDate: true, -// volType: volType, -// overrideVolsForTrade: vols, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle); - -// tradeRiskResult.Results.ForEach(r => -// { -// System.Diagnostics.Debug.WriteLine($"{r.Trade.StructureType}-{r.Trade.SpotPrice}-{r.Trade.TradeOpenVolatility}-{r.ValueResult.Pv}"); -// //保证金= 次日最大亏损; -// double value = ratioDict[r.Trade.ClientId ?? 0] * r.ValueResult.Pv; -// if (r.Trade.BuySell == "买入") { value = Math.Abs(value); } else { value = 0 - Math.Abs(value); } -// var tempTradeSpan = new trade_span -// { -// TradeId = r.Trade.id, -// ClientId = r.Trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = Math.Abs(r.Trade.UnderlyingId), -// UnderlyingCode = r.Trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value -// }; -// resultMap[r.Trade.id] = tempTradeSpan; -// }); -// return resultMap.Values.ToList(); -// } - -// private List CalcMargin(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool isInitialMargin = false, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易") -// { -// //结果集 -// List resultMap = new List(); - -// List tList = tradeList.Where(O => O.TradeType == "结构化交易").ToList(); -// if (tList.Count > 0) -// { -// for (int i = 0; i < tList.Count; i++) -// { -// int tempId = int.MaxValue; -// tList[i].SubTrades.ToList().ForEach(t => t.id = tempId--); -// List spans = CalculationSingleTrade(userId, userName, tList[i].SubTrades.ToList(), settleDate, priceDict, isInitialMargin, isEodSettle, forSingleTrade, volType); -// double margin = 0; -// if (tList[i].StructureType.Contains("跨式")) -// { margin = spans.Max(O => O.WorstCastClientPayable ?? 0); } -// else -// { margin = spans.Sum(O => O.WorstCastClientPayable ?? 0); } -// resultMap.Add(new trade_span -// { -// TradeId = tList[i].id, -// ClientId = tList[i].ClientId, -// ValueDate = settleDate, -// UnderlyingId = tList[i].UnderlyingId, -// UnderlyingCode = tList[i].UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = margin, -// Spv2 = margin, -// Spv3 = margin, -// Spv4 = margin, -// WorstCastClientPayable = margin -// }); -// } -// } -// tList = tradeList.Where(O => O.TradeType != "结构化交易").ToList(); -// if (tList.Count > 0) -// { -// resultMap.AddRange(CalculationSingleTrade(userId, userName, tList, settleDate, priceDict, isInitialMargin, isEodSettle, forSingleTrade, volType)); -// } -// return resultMap; -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// return CalcMargin(userId, userName, tradeList, settleDate, priceDict, false, hasOptionInfo, isEodSettle, forSingleTrade, volType); -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) -// { -// using (YLContext db = new YLContext()) -// { trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); } -// } - -// var tradeMargin = CalcMargin(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, price == 0 ? null : new Dictionary { { trade.UnderlyingId, price } }, isInitialMargin, hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/CalculatorHelperOld.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/CalculatorHelperOld.cs deleted file mode 100644 index 7af5e109..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/CalculatorHelperOld.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace YLErp.BLL.Calculation -{ - public static class CalculatorHelperOld - { - - } -} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/eod_commodity_future_priceBLL.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/eod_commodity_future_priceBLL.cs deleted file mode 100644 index 56dff46f..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/Inner/eod_commodity_future_priceBLL.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using YLErp.BLL; - -namespace YLErp.Modules.MarginModule -{ - public class eod_commodity_future_priceBLLBak - { - private readonly YLContext db = new YLContext(); - - public static List DataSources = new List { "系统", "人工" }; - - /// - /// 获取指定日期的收盘价或结算价 - /// - /// 标的代码 - /// 日期 - /// - /// 价格类型: - /// 0:最高价; - /// 1:最低价; - /// 2:收盘价; - /// 3:结算价; - /// - /// - public Dictionary GetEodPrice(IEnumerable codes, DateTime date, int priceType) - { - if (priceType < 0 || priceType > 3) { throw new ArgumentOutOfRangeException("priceType"); } - var result = new Dictionary(); - #region 商品期货 - var futurePirce = - (from priceDb in db.eod_commodity_future_price - where priceDb.ValueDate == date - && codes.Contains(priceDb.UnderlyingCode) - select new { priceDb.UnderlyingCode, priceDb.HighPrice, priceDb.LowPrice, priceDb.ClosePrice, priceDb.SettlePrice }) - .ToDictionary( - K => K.UnderlyingCode, - V => { switch (priceType) { case 0: return V.HighPrice ?? 0; case 1: return V.LowPrice ?? 0; case 2: return V.ClosePrice; case 3: return V.SettlePrice; default: return 0; } } - , StringComparer.OrdinalIgnoreCase); - #endregion - #region 股票 - var stockPirce = - (from priceDb in db.eod_stock_price - where priceDb.ValueDate == date - && codes.Contains(priceDb.UnderlyingCode) - select new { priceDb.UnderlyingCode, priceDb.HighPrice, priceDb.LowPrice, priceDb.ClosePrice }) - .ToDictionary( - K => K.UnderlyingCode, - V => { switch (priceType) { case 0: return V.HighPrice ?? 0; case 1: return V.LowPrice ?? 0; case 2: return V.ClosePrice; case 3: return V.ClosePrice; default: return 0; } } - , StringComparer.OrdinalIgnoreCase); - #endregion - #region 场内期权 - var exchangePirce = - (from priceDb in db.eod_exchange_option_price - where priceDb.ValueDate == date - && codes.Contains(priceDb.UnderlyingCode) - select new { priceDb.UnderlyingCode, priceDb.HighPrice, priceDb.LowPrice, priceDb.ClosePrice, priceDb.SettlePrice }) - .ToDictionary( - K => K.UnderlyingCode, - V => { switch (priceType) { case 0: return V.HighPrice ?? 0; case 1: return V.LowPrice ?? 0; case 2: return V.ClosePrice; case 3: return V.SettlePrice; default: return 0; } } - , StringComparer.OrdinalIgnoreCase); - #endregion - var errorCode = new List(); - foreach (var item in codes) - { - if (!futurePirce.ContainsKey(item) && - !stockPirce.ContainsKey(item) && - !exchangePirce.ContainsKey(item)) - { errorCode.Add(item); } - if (futurePirce.ContainsKey(item)) - { result[item] = futurePirce[item]; } - else if (stockPirce.ContainsKey(item)) - { result[item] = stockPirce[item]; } - else if (exchangePirce.ContainsKey(item)) - { result[item] = exchangePirce[item]; } - else { result[item] = 0; } - } - if (errorCode.Count > 0) - { throw new Exception($"{string.Join(",", errorCode)} 价格缺失"); } - - return result; - } - - /// - /// 获取指定日期的收盘价或结算价 - /// - /// 标的代码 - /// 日期 - /// - /// 价格类型: - /// 0:最高价; - /// 1:最低价; - /// 2:收盘价; - /// 3:结算价; - /// - /// - public Dictionary GetEodPriceToId(IEnumerable codes, DateTime date, int priceType) - { - var result = new Dictionary(); - var dict = GetEodPrice(codes, date, priceType); - foreach (var item in dict) - { - var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.Key); - if (um == null) - { - continue; - } - result[um.id] = item.Value; - } - return result; - } - } -} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MaoChuanMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MaoChuanMarginCalculation.cs deleted file mode 100644 index 9bb07927..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MaoChuanMarginCalculation.cs +++ /dev/null @@ -1,338 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.DBModels; -//using YLErp.Model; -//using YLErp.Modules.MarginModule; -//using YLErp.Modules.VolatilityModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// public class MaoChuanMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例(单例模式) -// public static readonly MaoChuanMarginCalculation Instance; - -// static MaoChuanMarginCalculation() -// { -// Instance = new MaoChuanMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private MaoChuanMarginCalculation() -// { - -// } - -// /// -// /// 计算香草期权和亚式期权保证金 -// /// -// private List CalculationNormalOptionMargin(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易") -// { -// var resultMap = new Dictionary(); - -// var codes = tradeList.Select(O => O.UnderlyingCode).ToHashSet(); -// var mpProvider = new MarginParamProvider(new OptUserInfo(0, "系统"), settleDate) -// .Initialize(codes, MarginParamTypeEnum.MarginRate); -// //客户要求用AskVol计算保证金,所以先把所有交易方向改为卖出并把VolType赋值为 BidAskVol; -// //Dictionary buySellDict = tradeList.ToDictionary(K => K.id, V => V.BuySell); -// //tradeList.ForEach(t => t.BuySell = "卖出"); -// var vols = new Dictionary(); -// foreach (var t in tradeList) -// { -// string vType = t.VolType; -// t.VolType = "报价Ask"; -// var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); -// if (um == null) -// { -// throw new MarginCalcException($"[保证金计算]找不到标的数据(交易编号:{t.TradeNumber},标的代码:{t.UnderlyingCode})"); -// } -// double vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), userId); -// vols[t.id] = vol; -// t.VolType = vType; -// } - -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userId.ToString(), -// settleDate, -// tradeList, -// priceDict, -// ValueCalculator.BASIC_PRICING, -// null, -// isEndOfDate: true, -// volType: null, -// overrideVolsForTrade: vols, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle); - -// //tradeList.ForEach(t => t.BuySell = buySellDict[t.id]); - -// foreach (var r in tradeRiskResult.Results) -// { -// if (!mpProvider.TryGetMarginRate(r.Trade.UnderlyingCode, out var marginRate)) -// { -// throw new MarginCalcException($"{r.Trade.UnderlyingCode} 保证金比率不存在"); -// } -// var trade = tradeList.FirstOrDefault(t => t.id == r.Trade.id); -// double price = priceDict == null ? r.Trade.SpotPrice ?? 0 : priceDict[r.Trade.UnderlyingId]; -// logger.Info($"茂川标准保证金计算:[{r.Trade.TradeType}_{r.Trade.BuySell}_{r.Trade.OptionType}_{r.Trade.Strike}] => Vol:{r.ValueResult.Vol};Delta:{r.ValueResult.Delta}"); -// //保证金= Delta*标的期货保证金比率*标的期货价格*持仓规模 (qdp计算出的Delta已经乘过数量了,所以这里不用再乘了); -// double value = Math.Abs(r.ValueResult.Delta) * marginRate * price;// * r.Trade.Notional; -// if (r.Trade.BuySell == "买入") { value = Math.Abs(value); } else { value = 0 - Math.Abs(value); } -// var tempTradeSpan = new trade_span -// { -// TradeId = r.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value -// }; -// resultMap[r.Trade.id] = tempTradeSpan; -// } - -// return resultMap.Values.ToList(); -// } - -// /// -// /// 计算其他期权保证金 -// /// -// private List CalculationOtherOptionMargin(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易") -// { -// var resultMap = new Dictionary(); -// var tempTradeList = new List(); -// var vols = new Dictionary(); -// foreach (var t in tradeList) -// { -// string vType = t.VolType; -// t.VolType = "报价Ask"; -// var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode); -// double vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), userId); -// vols[t.id] = vol; -// t.VolType = vType; -// tempTradeList.Add(t.Clone()); -// } - -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userId.ToString(), // userId + "_" + price.Key, -// settleDate, -// tempTradeList, -// priceDict, -// ValueCalculator.BASIC_PRICING, -// null, -// isEndOfDate: true, -// volType: null, -// overrideVolsForTrade: vols, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle); -// Action changeUmIdFunction = (t) => -// { -// if (t.OptionType == "看跌") -// { -// t.UnderlyingId = t.UnderlyingId * -1; -// if (t.trade_spread_option != null) -// { -// t.trade_spread_option.UnderlyingId1 = t.trade_spread_option.UnderlyingId1 * -1; -// t.trade_spread_option.UnderlyingId2 = t.trade_spread_option.UnderlyingId2 * -1; -// t.trade_spread_option.UnderlyingId3 = t.trade_spread_option.UnderlyingId3 * -1; -// t.trade_spread_option.UnderlyingId4 = t.trade_spread_option.UnderlyingId4 * -1; -// } -// if (t.trade_rainbow_option != null) -// { -// t.trade_rainbow_option.UnderlyingId1 = t.trade_rainbow_option.UnderlyingId1 * -1; -// t.trade_rainbow_option.UnderlyingId2 = t.trade_rainbow_option.UnderlyingId2 * -1; -// } -// } -// }; -// if (priceDict == null) -// { -// priceDict = new Dictionary(); -// Dictionary rateDict = base.GetUpDownLimitRate(tradeList.Select(O => O.UnderlyingId).ToArray()); -// tempTradeList.ForEach(t => -// { -// double[] arr = base.GetUpDownLimitPrice(rateDict[t.id], (t.SpotPrice ?? 0), double.Parse(rateDict[t.id][2])); -// changeUmIdFunction(t); -// priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? arr[1] : arr[0]; -// }); -// } -// else -// { -// Dictionary dict = base.GetUpDownLimitPrice(priceDict); -// tempTradeList.ForEach(t => -// { -// changeUmIdFunction(t); -// priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? dict[t.id][1] : dict[t.id][0]; -// }); -// } - -// var newTradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userId.ToString(), // userId + "_" + price.Key, -// settleDate, -// tempTradeList, -// priceDict, -// ValueCalculator.BASIC_PRICING, -// null, -// isEndOfDate: true, -// volType: null, -// overrideVolsForTrade: vols, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle); -// tempTradeList.ForEach(t => -// { -// double cPv = tradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; -// double nPv = newTradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv; -// //保证金= 次日最大亏损; -// double value = t.OptionType == "看涨" ? cPv - nPv : cPv + nPv; -// logger.Info($"茂川奇异保证金计算:[{t.TradeType}_{t.BuySell}_{t.OptionType}_{t.Strike}] => 当日Pv:{cPv};次日Pv:{nPv}"); -// var tempTradeSpan = new trade_span -// { -// TradeId = t.id, -// ClientId = t.ClientId, -// ValueDate = settleDate, -// UnderlyingId = Math.Abs(t.UnderlyingId), -// UnderlyingCode = t.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value -// }; -// resultMap[t.id] = tempTradeSpan; -// }); -// return resultMap.Values.ToList(); -// } - - -// private List CalculationStructureOptionMargin(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易") -// { -// List resultMap = new List(); -// for (int i = 0; i < tradeList.Count; i++) -// { -// int tempId = int.MaxValue; -// tradeList[i].SubTrades.ToList().ForEach(t => t.id = tempId--); -// List childrenSpans = RunMarginCalculation(userId, userName, tradeList[i].SubTrades.ToList(), settleDate, null, hasOptionInfo, isEodSettle, forSingleTrade, volType); - -// double margin = 0; -// switch (tradeList[i].StructureType) -// { -// case "牛市价差": -// case "熊市价差": -// case "亚式熊市价差": -// case "三领口组合": -// for (int j = 0; j < childrenSpans.Count; j++) -// { -// margin += childrenSpans[j].WorstCastClientPayable ?? 0; -// } -// break; -// case "跨式组合": -// case "宽跨式组合": -// for (int j = 0; j < childrenSpans.Count; j++) -// { -// double absMargin = Math.Abs(childrenSpans[j].WorstCastClientPayable ?? 0); -// if (margin < absMargin) -// { -// margin = absMargin; -// } -// } -// break; -// case "复制标的资产": -// case "蝶式组合": -// case "飞鹰式组合": -// case "比例价差": -// case "日历价差": -// case "箱式价差": -// case "风险逆转": -// default: -// break; -// } -// var tempTradeSpan = new trade_span -// { -// TradeId = tradeList[i].id, -// ClientId = tradeList[i].ClientId, -// ValueDate = settleDate, -// UnderlyingId = tradeList[i].UnderlyingId, -// UnderlyingCode = tradeList[i].UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// Spv1 = margin, -// Spv2 = margin, -// Spv3 = margin, -// Spv4 = margin, -// WorstCastClientPayable = margin -// }; -// resultMap.Add(tempTradeSpan); -// } -// return resultMap; -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// List resultMap = new List(); -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap; -// } -// if (forOtherSide) -// { -// return RunMarginCalculationOtherSide(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType); -// } - - -// List tList = tradeList.Where(O => O.TradeType == "结构化交易").ToList(); -// if (tList.Count > 0) -// { -// resultMap.AddRange(CalculationStructureOptionMargin(userId, userName, tList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType)); -// } - -// tList = tradeList.Where(O => O.TradeType == "香草期权" || O.TradeType == "亚式期权").ToList(); -// if (tList.Count > 0) -// { -// resultMap.AddRange(CalculationNormalOptionMargin(userId, userName, tList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType)); -// } -// tList = tradeList.Where(O => O.TradeType != "结构化交易" && O.TradeType != "香草期权" && O.TradeType != "亚式期权").ToList(); -// if (tList.Count > 0) -// { -// resultMap.AddRange(CalculationOtherOptionMargin(userId, userName, tList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType)); -// } -// return resultMap; -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 0)) -// { -// using (YLContext db = new YLContext()) -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalcException.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalcException.cs deleted file mode 100644 index b7f2e3b4..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalcException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace YLErp.BLL.MarginCalculationBak -{ - /// - /// 保证金计算错误 - /// - public class MarginCalcException : Exception - { - public MarginCalcException(string message, Exception innerException = null) : base(message, innerException) - { - - } - } -} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculation.cs deleted file mode 100644 index d69c4e32..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculation.cs +++ /dev/null @@ -1,209 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.Configuration; -//using YLErp.DBModels; -//using YLErp.Model; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// -// /// -// public static class MarginDefault -// { -// /// -// /// 计算日终保证金 -// /// -// /// -// /// -// /// -// /// -// /// 如需要根据不同客户配置选取价格,应传null -// /// -// /// -// /// -// /// -// /// -// /// -// public static List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// switch (PS.Config.Company) -// { -// case CompanyEnum.国泰君安: -// case CompanyEnum.上期资本: -// case CompanyEnum.中财资本: -// return GTJAMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.光大光子: -// return GDGZMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.渤海: -// case CompanyEnum.安粮: -// return BHRSMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.申万: -// return SYWGMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.格林大华: -// return UniversalMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.方顿: -// return FDMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.茂川资本: -// return MaoChuanMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.宏源: -// return HongYuanMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.伴兴: -// return BXMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.海通: -// return HaiTongMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// case CompanyEnum.瑞达: -// return RDMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// default: -// return GTJAMarginCalculation.Instance.RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, forOtherSide); -// } -// } - -// public static bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, Dictionary clientAdditionalMarginDic = null) -// { -// switch (PS.Config.Company) -// { -// case CompanyEnum.国泰君安: -// return GTJAMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// case CompanyEnum.光大光子: -// return GDGZMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// case CompanyEnum.渤海: -// return BHRSMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// case CompanyEnum.安粮: -// return BHRSMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false, clientAdditionalMarginDic); -// case CompanyEnum.申万: -// return SYWGMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, !PS.Config.ErpElement.TwoSideMargin); -// case CompanyEnum.格林大华: -// return UniversalMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, !PS.Config.ErpElement.TwoSideMargin); -// case CompanyEnum.伴兴: -// return BXMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// case CompanyEnum.海通: -// return HaiTongMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// case CompanyEnum.瑞达: -// return RDMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// default: -// return GTJAMarginCalculation.Instance.CalcClientMargin(userId, userName, settleDate, tradeSpans, tradeSpansOtherSide, SpanType, RefreshClientIds, false); -// } -// } - -// public static bool isMarginCalcNeedSpecial() -// { -// switch (YLErp.PS.Config.Company) -// { -// case CompanyEnum.渤海: -// case CompanyEnum.安粮: -// return BHRSMarginCalculation.Instance.MarginCalcNeedSpecial; -// case CompanyEnum.国泰君安: -// case CompanyEnum.申万: -// case CompanyEnum.格林大华: -// default: -// return SYWGMarginCalculation.Instance.MarginCalcNeedSpecial; -// } -// } - -// public static double? GetInitialMarginRatio(trade trade) -// { -// switch (PS.Config.Company) -// { -// case CompanyEnum.方顿: -// return FDMarginCalculation.Instance.GetInitialMarginRatio(trade); -// default: -// return 0; -// } -// } - -// public static double? GetPositionMarginRatio(trade trade) -// { -// switch (PS.Config.Company) -// { -// case CompanyEnum.方顿: -// return FDMarginCalculation.Instance.GetPositionMarginRatio(trade); -// default: -// return 0; -// } -// } - -// public static double GetInitialMargin(trade trade, bool hasOptionInfo = false) -// { -// if (trade is null) -// { -// return 0; -// } - -// switch (PS.Config.Company) -// { -// case CompanyEnum.方顿: -// return FDMarginCalculation.Instance.GetInitialMargin(trade); -// case CompanyEnum.光大光子: -// return GDGZMarginCalculation.Instance.GetInitialMargin(trade); -// default: -// return GetTradeMargin(trade, (trade.SpotPrice ?? 0), true, hasOptionInfo); -// } -// } - -// /// -// /// isInitialMargin为true: 为初始保证金 -// /// isInitialMargin为false: 为实时保证金 -// /// -// public static double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// if (trade.TradeType == "结构化交易") -// { -// var option = StructureOption_Code.StructureOptions.FirstOrDefault(o => o.Name == trade.StructureType || o.CnName == trade.StructureType); -// //自由组合时不在变更StructureType字段值,保持原有结构化交易的内容; -// if (option != null) -// { trade.StructureType = option.CnName; } -// } -// double? tempInitialMargin = null; -// if (!isInitialMargin && trade.CalcFlag == 1) -// { -// tempInitialMargin = trade.InitialMargin; -// trade.InitialMargin = null; -// } -// try -// { -// switch (PS.Config.Company) -// { -// case CompanyEnum.国泰君安: -// case CompanyEnum.上期资本: -// case CompanyEnum.光大光子: -// return GTJAMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.渤海: -// return BHRSMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.安粮: -// return BHRSMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.申万: -// return SYWGMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.格林大华: -// return UniversalMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.茂川资本: -// return MaoChuanMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.宏源: -// return HongYuanMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.伴兴: -// return BXMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.海通: -// return HaiTongMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// case CompanyEnum.瑞达: -// return RDMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// default: -// return GTJAMarginCalculation.Instance.GetTradeMargin(trade, price, isInitialMargin, hasOptionInfo); -// } -// } -// finally -// { -// if (isInitialMargin && trade.CalcFlag == 1 && trade.InitialMargin == null) -// { -// trade.InitialMargin = tempInitialMargin; -// } -// } -// } -// } - -// public class MarginResult -// { -// public trade trade; -// public double Margin; -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculationBase.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculationBase.cs deleted file mode 100644 index 1bd81e87..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/MarginCalculationBase.cs +++ /dev/null @@ -1,381 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text.RegularExpressions; -//using YLErp.DBModels; -//using YLErp.Helpers; -//using YLErp.Model; -//using YLErp.Modules.DataProviderModule; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 保证金计算 -// /// -// public class MarginCalculationBase -// { -// protected static readonly Abstract.ILogger logger = LogFactory.GetLogger("保证金计算"); - -// protected readonly UnderlyingDataProvider _underlyingDataProvider; - -// protected MarginCalculationBase() -// { -// _underlyingDataProvider = new UnderlyingDataProvider(); -// } - -// public virtual bool MarginCalcNeedSpecial => false; - -// public virtual bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = true, Dictionary clientAdditionalMarginDic = null) -// { -// using (var db = new YLContext()) -// { -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); -// if (OnlyBuyer) -// { -// tradeSpanInfo = tradeSpanInfo.Where(t => t.trade.BuySell == "买入").ToList(); -// } - -// var clientSpanNews = new List(100); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// var spvList = new[] { -// clientGroup.Sum(g => g.tradeSpan.Spv1??0), -// clientGroup.Sum(g => g.tradeSpan.Spv2??0), -// clientGroup.Sum(g => g.tradeSpan.Spv3??0), -// clientGroup.Sum(g => g.tradeSpan.Spv4??0) -// }; -// var maxSpv = spvList.Max(); -// var twoSideMargin = PS.Config.ErpElement.TwoSideMargin && clientList.FirstOrDefault(x => x.id == clientGroup.Key)?.HasTwoSideMargin == 1; -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = -spvList[0], -// Spv2 = -spvList[1], -// Spv3 = -spvList[2], -// Spv4 = -spvList[3], -// WorstCastClientPayable = twoSideMargin ? -maxSpv : -Math.Max(maxSpv, 0), -// TwoSideMargin = -maxSpv, -// RiskExposure = -clientGroup.Sum(g => g.tradeSpan.RiskExposure), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic != null && clientAdditionalMarginDic.TryGetValue(clientGroup.Key ?? 0, out var dd) ? dd : 0 -// }; -// clientSpanNews.Add(clientSpan); -// } - -// var tradeSpanInfoOtherSide = (from tradeSpan in tradeSpansOtherSide -// join trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// //处理从客户角度的保证金计算(将交易买卖方向反向处理) -// var compareZero = !PS.Config.ErpElement.NonInterBankMarginNetting; -// var clientGroupsOtherSide = tradeSpanInfoOtherSide.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroupsOtherSide) -// { -// var clientSpan = clientSpanNews.FirstOrDefault(x => x.ClientId == clientGroup.Key && x.ValueDate == settleDate); -// if (clientSpan != null) -// { -// clientSpan.OtherSideMargin = clientGroup.Sum(g => -// { -// var arr = new[] { g.tradeSpan.Spv1 ?? 0, g.tradeSpan.Spv2 ?? 0, g.tradeSpan.Spv3 ?? 0, g.tradeSpan.Spv4 ?? 0 }; -// return compareZero ? Math.Min(arr.Min(), 0) : arr.Min(); -// }); -// } -// } - -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// if (RefreshClientIds != null) -// { -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}={SpanType}"); -// } - -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// var sql = $"{nameof(client_span.ValueDate)}='{settleDate.ToSqlDate()}' and {nameof(client_span.SpanType)}={SpanType} and {nameof(client_span.ModifiedFlag)}=0"; -// db.BulkDelete(sql); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag) -// .Select(n => new { n.ValueDate, n.ClientId }).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public virtual List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// var tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// using (var db = new YLContext()) -// { -// var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// if (clientList != null) -// { - -// tradeList.ForEach(t => -// { -// var client = clientList.FirstOrDefault(c => c.client.id == t.ClientId); -// if (client != null) -// { -// //未设置相关保证金系数默认为1.0 -// var clientRatio = client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0); -// //如果是股票去名义本金,如果是期货取:份额 * 即期价格 -// var value = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.client.HasTwoSideMargin == 1 ? -1 : 0)) * clientRatio; -// var twoSideMargin = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : -1) * clientRatio; -// tradeSpans.Add(new trade_span -// { -// TradeId = t.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = client.client.id, -// UnderlyingId = t.UnderlyingId, -// UnderlyingCode = t.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// TwoSideMargin = twoSideMargin -// }); -// } -// }); -// } -// } -// } -// return tradeSpans; -// } - -// public virtual double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } - -// private double GetUpDownValue(string upDownLimit, double settlePrice, double minPriceChange) -// { -// double result = 0, haifPrice = minPriceChange / 2; -// if (upDownLimit.Contains("%")) -// { -// //百分比 -// double.TryParse(upDownLimit.Replace("%", ""), out result); -// result = settlePrice * (result * 0.01); -// } -// else -// { -// //绝对值 -// double.TryParse(upDownLimit, out result); -// } -// double diff = result % minPriceChange; -// result -= diff; -// if (diff >= haifPrice) { result += minPriceChange; } -// return result; -// } - -// /// -// /// 获取涨跌幅 -// /// -// /// 标的Id -// /// -// /// Key:标的Id; -// /// Value:[0]:涨幅; -// /// Value:[1]:跌幅; -// /// Value:[2]:最小价格变动; -// /// -// protected Dictionary GetUpDownLimitRate(IEnumerable underlyingId) -// { -// Dictionary result = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// var underlyingIds = underlyingId.ToList(); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.UnderlyingTypeId equals variety.id -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// variety.MinPriceChange, -// defUpLimit = variety.UpLimit, -// defDownLimit = variety.DownLimit, -// defVolatilityRate = variety.VolatilityRate -// }).ToList(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// string[] limitArr = new string[3]; -// if (!string.IsNullOrWhiteSpace(t.UpDownLimit)) -// { -// limitArr[0] = t.UpDownLimit;//百分比或绝对值 -// limitArr[1] = t.UpDownLimit; -// } -// else -// { -// limitArr[0] = t.defUpLimit?.ToString() ?? "5%"; -// limitArr[1] = t.defDownLimit?.ToString() ?? "5%"; -// } -// if (string.IsNullOrEmpty(t.MinPriceChange)) -// { -// limitArr[2] = "0.01"; -// } -// else -// { -// limitArr[2] = Regex.Match(t.MinPriceChange, @"\d+(?=元.+)").Value; -// if (string.IsNullOrEmpty(t.MinPriceChange)) -// { -// limitArr[2] = "0.01"; -// } -// } -// result[t.id] = limitArr; -// }); -// } -// } -// return result; -// } - -// /// -// /// 获取涨跌幅价格 -// /// -// /// -// /// [0]:涨幅; -// /// [1]:跌幅; -// /// -// /// 基准价 -// /// 最小价格变动 -// /// -// /// [0]:涨停价; -// /// [1]:跌停价; -// /// -// protected double[] GetUpDownLimitPrice(string[] upDownLimit, double price, double minPriceChange) -// { -// double[] priceArr = new double[2]; -// double tempDouble, haifPrice = minPriceChange / 2; -// #region 涨幅 -// tempDouble = GetUpDownValue(upDownLimit[0], price, minPriceChange); -// priceArr[0] = price + Math.Abs(tempDouble); -// #endregion -// #region 跌幅 -// tempDouble = GetUpDownValue(upDownLimit[1], price, minPriceChange); -// priceArr[1] = price - Math.Abs(tempDouble); -// #endregion -// return priceArr; -// } - -// /// -// /// 获取涨跌停价格 -// /// -// /// -// /// 当前价格 -// /// Key:标的Id; -// /// Value:标的价格; -// /// -// /// -// /// Key:标的Id; -// /// Value:[0]:涨停价; -// /// Value:[1]:跌停价; -// /// -// protected Dictionary GetUpDownLimitPrice(Dictionary priceDict) -// { -// Dictionary result = new Dictionary(); -// Dictionary upDownLimitRate = GetUpDownLimitRate(priceDict.Keys); -// foreach (var item in upDownLimitRate) -// { result[item.Key] = GetUpDownLimitPrice(item.Value, priceDict[item.Key], double.Parse(item.Value[2])); } -// return result; -// } - -// //为了算客户角度的一个保证金数值 -// //RunMarginCalculation时forOtherSide为true时调用 -// protected List RunMarginCalculationOtherSide(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo, bool isEodSettle, bool forSingleTrade, string volType) -// { -// void RevertBuySell() -// { -// foreach (var x in tradeList) -// { -// x.BuySell = x.BuySell == "买入" ? "卖出" : "买入"; -// if (x.SubTrades != null && x.SubTrades.Any()) -// { -// foreach (var xs in x.SubTrades) -// { -// xs.BuySell = xs.BuySell == "买入" ? "卖出" : "买入"; -// } -// } -// } -// } - -// RevertBuySell(); -// var results = RunMarginCalculation(userId, userName, tradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, forSingleTrade, volType, false); -// RevertBuySell(); -// return results; -// } - -// /// -// /// 获取currentDate参数前一日的结算价 -// /// -// /// -// /// 当前日期 -// /// -// /// 结算价模式,默认为结算价模式 -// /// valuedate.EodSettlePriceMode_*** -// /// -// /// -// protected Dictionary GetSettlePrice(IEnumerable codes, DateTime currentDate, string settlePriceMode = "") -// { -// //默认情况选择结算价 -// bool isClosePrice = "收盘价".Equals(settlePriceMode ?? ""); -// codes = codes.ToHashSet(); -// Dictionary priceDict = new Modules.MarginModule.eod_commodity_future_priceBLLBak().GetEodPriceToId(codes, currentDate, isClosePrice ? 2 : 3); -// return priceDict; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/RDMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/RDMarginCalculation.cs deleted file mode 100644 index ab3f9095..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/RDMarginCalculation.cs +++ /dev/null @@ -1,578 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.Commons; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.Modules.DataCacheModule; -//using YLErp.Modules.MarginModule; -//using YLErp.QdpModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 瑞达保证金计算 -// /// -// public class RDMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly RDMarginCalculation Instance; - -// static RDMarginCalculation() -// { -// Instance = new RDMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// protected RDMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, -// Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// //结果集 -// Dictionary resultMap = new Dictionary(); -// using (YLContext db = new YLContext()) -// { -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = GetSettlePrice(codes, settleDate, "收盘价"); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return resultMap.Values.ToList(); -// } -// var underlyingIds = priceDict.Keys.ToList(); - -// //获取标的涨跌幅限制 -// var umDatas = (from um in db.underlying_manager -// join variety in db.variety on um.CommodityCode equals variety.VarietyCode -// where underlyingIds.Contains(um.id) -// select new -// { -// um.id, -// um.VolatilityRate, -// um.UpDownLimit, -// defUpLimit = variety.UpLimit, -// defDownLimit = variety.DownLimit, -// defVolatilityRate = variety.VolatilityRate -// }).ToList(); - -// var UpLimitDict = new Dictionary(); -// var DownLimitDict = new Dictionary(); -// var umVolatilityRateDic = new Dictionary(); - -// if (umDatas != null && umDatas.Count > 0) -// { -// umDatas.ForEach(t => -// { -// //OTC-8856 Start -// //1.波动率变化 -// if (DataConvert.TryParsePercentValue(t.VolatilityRate, out double pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } -// else if (DataConvert.TryParsePercentValue(t.defVolatilityRate, out pvalue) && (Math.Abs(pvalue) >= 1e-5)) -// { -// umVolatilityRateDic[t.id] = pvalue; -// } - -// //2.涨跌停板幅度 -// if (!string.IsNullOrWhiteSpace(t.UpDownLimit)) -// { -// UpLimitDict[t.id] = t.UpDownLimit;//百分比或绝对值 -// DownLimitDict[t.id] = t.UpDownLimit; -// } -// else -// { -// UpLimitDict[t.id] = t.defUpLimit?.ToString() ?? "5%"; -// DownLimitDict[t.id] = t.defDownLimit?.ToString() ?? "5%"; -// } -// }); -// } - -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(tradeList); -// } - -// //判断当日结算价是否已经入库 -// //if (priceDict == null || priceDict.Count == 0) -// //{ -// // throw new Exception("当日结算价还未同步,请等待结算价自动同步完成或手动同步后再执行收盘操作!"); -// //} - -// var tradeVolatilityRateDic = tradeList.ToDictionary(t => t.id, t => priceDict[t.UnderlyingId] / t.ActualStrike < 0.9 && t.OptionType == "看涨" || priceDict[t.UnderlyingId] / t.ActualStrike > 1.1 && t.OptionType == "看跌" ? 0.2 : (umVolatilityRateDic.ContainsKey(t.UnderlyingId) ? umVolatilityRateDic[t.UnderlyingId] : 0)) -// .Where(d => d.Value > 0).ToDictionary(d => d.Key, d => d.Value); -// Dictionary> eodPriceDict = new Dictionary>(); -// var upLimitPrices = new Dictionary(); -// var upLimitPricesTwoThirds = new Dictionary(); -// var upLimitPricesOneThird = new Dictionary(); -// var downLimitPrices = new Dictionary(); -// var downLimitPricesTwoThirds = new Dictionary(); -// var downLimitPricesOneThird = new Dictionary(); -// var normalLimitPrices = new Dictionary(); -// double tempDouble; -// //根据涨跌幅限制以及当日结算价计算涨停价以及跌停价 -// if (priceDict != null && priceDict.Count > 0) -// { -// foreach (var t in priceDict) -// { -// //OTC-8856 Start -// //UpLimit -// if (UpLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = UpLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// upLimitPrices[t.Key] = t.Value * (1 + (tempDouble * 0.01)); -// upLimitPricesTwoThirds[t.Key] = t.Value * (1 + (tempDouble * 0.01) * 2.0 / 3.0); -// upLimitPricesOneThird[t.Key] = t.Value * (1 + (tempDouble * 0.01) / 3.0); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// upLimitPrices[t.Key] = t.Value + Math.Abs(tempAbs); -// upLimitPricesTwoThirds[t.Key] = t.Value + Math.Abs(tempAbs) * 2.0 / 3.0; -// upLimitPricesOneThird[t.Key] = t.Value + Math.Abs(tempAbs) / 3.0; -// } -// } -// else -// { -// upLimitPrices[t.Key] = t.Value * (1 + 0.05); -// upLimitPricesTwoThirds[t.Key] = t.Value * (1 + 0.05 * 2.0 / 3.0); -// upLimitPricesOneThird[t.Key] = t.Value * (1 + 0.05 / 3.0); -// } - -// //DownLimit -// if (DownLimitDict.ContainsKey(t.Key)) -// { -// var tempVaue = DownLimitDict[t.Key]; -// if (tempVaue.Contains("%")) -// { -// //百分比 -// double.TryParse(tempVaue.Replace("%", ""), out tempDouble); -// downLimitPrices[t.Key] = t.Value * (1 - (tempDouble * 0.01)); -// downLimitPricesTwoThirds[t.Key] = t.Value * (1 - (tempDouble * 0.01) * 2.0 / 3.0); -// downLimitPricesOneThird[t.Key] = t.Value * (1 - (tempDouble * 0.01) / 3.0); -// } -// else -// { -// //绝对值 -// double.TryParse(tempVaue, out double tempAbs); -// downLimitPrices[t.Key] = t.Value - Math.Abs(tempAbs); -// downLimitPricesTwoThirds[t.Key] = t.Value - Math.Abs(tempAbs) * 2.0 / 3.0; -// downLimitPricesOneThird[t.Key] = t.Value - Math.Abs(tempAbs) / 3.0; -// } -// } -// else -// { -// downLimitPrices[t.Key] = t.Value * (1 - 0.05); -// downLimitPricesTwoThirds[t.Key] = t.Value * (1 - 0.05 * 2.0 / 3.0); -// downLimitPricesOneThird[t.Key] = t.Value * (1 - 0.05 / 3.0); -// } - -// //Normal -// normalLimitPrices[t.Key] = t.Value; -// } -// eodPriceDict["up"] = upLimitPrices; -// eodPriceDict["upTwoThirds"] = upLimitPricesTwoThirds; -// eodPriceDict["upOneThird"] = upLimitPricesOneThird; -// eodPriceDict["down"] = downLimitPrices; -// eodPriceDict["downTwoThirds"] = downLimitPricesTwoThirds; -// eodPriceDict["downOneThird"] = downLimitPricesOneThird; -// eodPriceDict["normal"] = normalLimitPrices; -// } -// //波动率变化 -// var addVolRateList = new List> { null, tradeVolatilityRateDic }; -// //交易对应客户信息 -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// var userIdNew = UniqueTimeId.Get().ToString(); - -// try -// { -// foreach (var price in eodPriceDict) -// { -// addVolRateList.ForEach(addVolRateDic => -// { -// var key = $"{price.Key}_{(addVolRateDic == null ? 0 : 1)}"; -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( -// userIdNew, // userId + "_" + price.Key, -// settleDate, -// tradeList, -// price.Value, -// ValueCalculator.PV_ONLY, -// addVolRateDic, -// isEodSettle, -// volType, -// isUseTradeVol: PS.Config.IsTradeVol, -// PreciseTimeMode: !isEodSettle, -// isAddVolPercent: false); -// if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0) -// { -// foreach (var item in tradeRiskResult.Results) -// { -// var client = clientList.FirstOrDefault(c => c.client.id == item.Trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); - -// double value = 0; -// if (item.Trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == item.Trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(item.Trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{item.Trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// else if (item.Trade.TradeType == "权益互换") -// { -// value = (item.Trade.trade_swap.GetMarginRate ?? 0) * (item.Trade.StockEqvNotional ?? 0) + Math.Max((double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv), 0); -// } -// if (resultMap.ContainsKey(item.Trade.id)) -// { -// switch (key) -// { -// case "up_1": -// resultMap[item.Trade.id].Spv1 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "upTwoThirds_1": -// resultMap[item.Trade.id].Spv2 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "upOneThird_1": -// resultMap[item.Trade.id].Spv3 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_1": -// resultMap[item.Trade.id].Spv4 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// resultMap[item.Trade.id].Spv5 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "downTwoThirds_1": -// resultMap[item.Trade.id].Spv6 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "downOneThird_1": -// resultMap[item.Trade.id].Spv7 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_0": -// resultMap[item.Trade.id].Delta = item.ValueResult.Delta; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id].setWorstCastClientPayable8(); -// } -// else -// { -// var trade = tradeList.FirstOrDefault(t => t.id == item.Trade.id); -// var underlying = DataCacheManager.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); -// var tempTradeSpan = new trade_span -// { -// TradeId = item.Trade.id, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// VarietyId = underlying.UnderlyingTypeId, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now -// }; -// switch (key) -// { -// case "up_1": -// tempTradeSpan.Spv1 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "upTwoThirds_1": -// tempTradeSpan.Spv2 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "upOneThird_1": -// tempTradeSpan.Spv3 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_1": -// tempTradeSpan.Spv4 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "down_1": -// tempTradeSpan.Spv5 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "downTwoThirds_1": -// tempTradeSpan.Spv6 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "downOneThird_1": -// tempTradeSpan.Spv7 = item.Trade.TradeType == "自定义交易" || item.Trade.TradeType == "权益互换" ? value : (double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv) * clientRatio; -// break; -// case "normal_0": -// tempTradeSpan.Delta = item.ValueResult.Delta; -// break; -// default: -// break; -// } -// resultMap[item.Trade.id] = tempTradeSpan; -// } - -// resultMap[item.Trade.id].UnderlyingPrice = priceDict[item.Trade.UnderlyingId]; -// } -// } -// }); -// } -// } -// finally -// { -// //上面的计算用到静态生成market,需要清除 -// QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userIdNew); -// } - -// return resultMap.Values.ToList(); -// } -// } - -// public override bool CalcClientMargin(int userId, string userName, DateTime settleDate, List tradeSpans, List tradeSpansOtherSide, int SpanType = 0, List RefreshClientIds = null, bool OnlyBuyer = false, Dictionary clientAdditionalMarginDic = null) -// { -// using (YLContext db = new YLContext()) -// { -// var underlyingCodes = tradeSpans.Select(t => t.UnderlyingCode).ToHashSet(); -// var mpProvider = new MarginParamProvider(new OptUserInfo(0, "系统"), settleDate).Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - -// //删除 -// if (tradeSpans != null && tradeSpans.Count > 0) -// { -// var tradeIds = tradeSpans.Select(t => t.TradeId).ToList(); -// var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); -// var clientIds = tradeSpans.Select(t => t.ClientId).Distinct().ToList(); -// var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList(); -// var tradeSpanInfo = (from tradeSpan in tradeSpans -// join -// trade in tradeList on tradeSpan.TradeId equals trade.id -// where tradeSpan.ValueDate == settleDate -// select new { trade, tradeSpan }).ToList(); - -// var clientSpanNews = new List(); -// var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId); -// foreach (var clientGroup in clientGroups) -// { -// #region Span Margin Method - -// var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new client_span -// { -// UnderlyingId = t.Key, -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1), -// Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1), -// Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1), -// Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1), -// Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1), -// Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1), -// Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); -// foreach (var item in underlyingGroup) -// { -// item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0); - -// #region 更新tradeSpan,使得每笔交易的持仓保证金和客户保证金计算用的Spv组保持一致 - -// var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == settleDate).ToList(); -// if (item.WorstCastClientPayable == item.Spv1) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1); -// } -// else if (item.WorstCastClientPayable == item.Spv2) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2); -// } -// else if (item.WorstCastClientPayable == item.Spv3) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3); -// } -// else if (item.WorstCastClientPayable == item.Spv4) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4); -// } -// else if (item.WorstCastClientPayable == item.Spv5) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5); -// } -// else if (item.WorstCastClientPayable == item.Spv6) -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6); -// } -// else -// { -// tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7); -// } - -// #endregion - -// if (!PS.Config.ErpElement.NonInterBankMarginNetting) -// { -// item.WorstCastClientPayable = Math.Min(item.WorstCastClientPayable.Value, 0); -// } -// } - -// #endregion - -// #region Delta Margin Method - -// var varietyGroup = clientGroup.GroupBy(t => t.trade.VarietyId).Select(t => new client_span -// { -// VarietyId = t.Key, -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// MaxSpotPrice = t.Max(g => g.tradeSpan.UnderlyingPrice), -// DeltaSell = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "买入" ? 1 : 0)), -// DeltaBuy = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta < 0 ? 1 : 0)), -// DeltaBuyMinus = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta > 0 ? 1 : 0)), -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType -// }).ToList(); - -// foreach (var item in varietyGroup) -// { -// #region 更新tradeSpan,通过Delta品种级别求和算法,给tradeSpan的deltaMargin赋值 - -// var marginRate = mpProvider.GetVarietyData(item.VarietyId ?? 0, MarginParamTypeEnum.MarginRate); - -// var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.VarietyId == item.VarietyId && x.ValueDate == settleDate).ToList(); -// //DeltaSell为客户角度卖出,且为客户角度看Delta -// if (item.DeltaSell > 0) -// { -// tradeSpansUpdate.ForEach(x => -// { -// var trade = tradeSpanInfo.FirstOrDefault(y => y.trade.id == x.TradeId).trade; -// //客户角度卖出的交易 -// //客户角度买入的交易,客户角度Delta<0,即交易员角度Delta>0 -// if (trade.BuySell == "买入" || x.Delta > 0) -// { -// x.DeltaMargin = -x.Delta * item.MaxSpotPrice * marginRate; -// } -// }); -// item.DeltaMargin = -Math.Max((item.DeltaSell ?? 0 + item.DeltaBuyMinus ?? 0), 0) * item.MaxSpotPrice * marginRate; -// } -// else -// { -// tradeSpansUpdate.ForEach(x => -// { -// var trade = tradeSpanInfo.FirstOrDefault(y => y.trade.id == x.TradeId).trade; -// //客户角度卖出的交易 -// //客户角度买入的交易,客户角度Delta>0,即交易员角度Delta<0 -// if (trade.BuySell == "买入" || x.Delta < 0) -// { -// x.DeltaMargin = x.Delta * item.MaxSpotPrice * marginRate; -// } -// }); -// item.DeltaMargin = Math.Min((item.DeltaSell ?? 0 + item.DeltaBuyMinus ?? 0), 0) * item.MaxSpotPrice * marginRate; -// } - -// #endregion -// } - -// #endregion - -// var clientSpan = new client_span -// { -// ClientId = clientGroup.Key, -// ValueDate = settleDate, -// Spv1 = underlyingGroup.Sum(g => g.Spv1), -// Spv2 = underlyingGroup.Sum(g => g.Spv2), -// Spv3 = underlyingGroup.Sum(g => g.Spv3), -// Spv4 = underlyingGroup.Sum(g => g.Spv4), -// Spv5 = underlyingGroup.Sum(g => g.Spv5), -// Spv6 = underlyingGroup.Sum(g => g.Spv6), -// Spv7 = underlyingGroup.Sum(g => g.Spv7), -// DeltaMargin = varietyGroup.Sum(g => g.DeltaMargin), -// //负数代表客户应缴保证金,正数代表客户应收保证金 -// WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0, -// OptId = userId, -// OptName = userName, -// OptDate = DateTime.Now, -// SpanType = SpanType, -// AdditionalWorstCastClientPayable = clientAdditionalMarginDic == null ? 0 : (clientAdditionalMarginDic.ContainsKey(clientGroup.Key ?? 0) ? clientAdditionalMarginDic[clientGroup.Key ?? 0] : 0) -// }; -// if (clientSpan.WorstCastClientPayable > clientSpan.DeltaMargin) -// { -// clientSpan.WorstCastClientPayable = clientSpan.DeltaMargin; -// } -// clientSpanNews.Add(clientSpan); -// } - -// //span类型为实时删除所有实时计算的交易的保证金信息 -// if (SpanType == client_span.SpanType_RealTime) -// { -// if (RefreshClientIds != null) -// { -// db.BulkDelete($"{nameof(client_span.ClientId)} in @ids", new { ids = RefreshClientIds }); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.SpanType)}=@SpanType", new { SpanType }); -// } -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } -// else -// { -// db.BulkDelete($"{nameof(client_span.ValueDate)}=@settleDate and {nameof(client_span.SpanType)}=@SpanType and {nameof(client_span.ModifiedFlag)}=0", new { settleDate, SpanType }); - -// var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == settleDate && t.SpanType == SpanType && t.ModifiedFlag) -// .Select(n => new { n.ValueDate, n.ClientId }).ToList(); -// //筛选出可以修改的clientSpan -// clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList(); -// MySqlBulkExtensions.BulkInsert(db, clientSpanNews); -// } - -// db.SaveChanges(); -// } -// return true; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/SYWGMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/SYWGMarginCalculation.cs deleted file mode 100644 index bec7d45d..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/SYWGMarginCalculation.cs +++ /dev/null @@ -1,288 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.BLL.Calculation.V2; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.Modules.MarginModule; -//using CalculatorHelper = YLErp.BLL.Calculation.CalculatorHelperOld; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// /// -// /// 申银万国 -// /// -// public class SYWGMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly SYWGMarginCalculation Instance; - -// static SYWGMarginCalculation() -// { -// Instance = new SYWGMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private SYWGMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// var tempStockTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); -// if (tempStockTradeList.Any()) -// { -// var stockTradeSpanlist = StockMarginCalculation(userId, userName, tempStockTradeList, settleDate, isEodSettle); -// if (stockTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(stockTradeSpanlist); -// } -// } -// var tempFutureTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); -// if (tempFutureTradeList.Any()) -// { -// if (!(priceDict?.Count > 0)) -// { -// var codes = tempFutureTradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count > 0) -// { -// var futureTradeSpanlist = FutureMarginCalculation(userId, userName, tempFutureTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle, volType); -// if (futureTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(futureTradeSpanlist); -// } -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 股票类期权计算保证金 -// /// -// public List StockMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, bool isEodSettle) -// { -// List tradeSpans = new List(); -// if (tradeList != null && tradeList.Count > 0) -// { -// using (YLContext db = new YLContext()) -// { -// var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15; -// var clientIds = tradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// if (clientList != null) -// { -// tradeList.ForEach(t => -// { -// var client = clientList.FirstOrDefault(c => c.client.id == t.ClientId); -// if (client != null) -// { -// var clientRatio = client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0); -// //如果是股票去名义本金,如果是期货取:份额 * 即期价格 -// var value = (t.StockEqvNotional ?? (t.Notional * t.SpotPrice ?? 0.0)) * marginRation * (t.BuySell == "买入" ? 1 : 0) * clientRatio; - -// if (t.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == t.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{t.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } -// tradeSpans.Add(new trade_span -// { -// TradeId = t.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = client.client.id, -// UnderlyingId = t.UnderlyingId, -// UnderlyingCode = t.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value -// }); -// } -// }); -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 商品期权计算保证金 -// /// -// public List FutureMarginCalculation(int userId, string userName, List futureTradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, string volType = "交易") -// { -// if (futureTradeList == null || !futureTradeList.Any()) -// { -// return new List(0); -// } - -// var tradeSpans = new List(); -// using (var db = new YLContext()) -// { -// if (!hasOptionInfo) -// { -// tradeBLL.SetFieldsByTradeType(futureTradeList); -// } - -// var underlyingCodes = futureTradeList.Select(t => t.UnderlyingCode).ToHashSet(); -// var mpProvider = new MarginParamProvider(new OptUserInfo(0, "系统"), settleDate).Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - -// var overrideVolsForTrades = VolCaculator.Instance.GetVol(futureTradeList, settleDate); -// var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(userId + "", settleDate, futureTradeList, priceDict, ValueCalculator.BASIC_GREEKS, null, isEodSettle, volType, overrideVolsForTrade: overrideVolsForTrades, isUseTradeVol: PS.Config.IsTradeVol, PreciseTimeMode: !isEodSettle); -// logger.Info($"商品期货保证金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}"); -// var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1; -// var FutureMarginAddRatio = valuedateBLL.SystemDate.FutureMarginAddRatio ?? 0; -// //客户对应等级系数 -// var clientIds = futureTradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); -// if (tradeRiskResult.Results.Count > 0) -// { -// var underlyingCodeLookup = futureTradeList.ToLookup(t => new { t.UnderlyingId, t.ClientId }); - -// foreach (var trade in futureTradeList) -// { -// var closePrice = priceDict.ContainsKey(trade.UnderlyingId) ? priceDict[trade.UnderlyingId] : 0.0; -// var optionValueList = tradeRiskResult.Results.Where(t => t.Trade.id == trade.id && t.ValueResult != null && t.Trade != null && !double.IsNaN(t.ValueResult.Delta) && !double.IsNaN(t.ValueResult.Vega) && !double.IsNaN(t.ValueResult.Gamma)).ToList(); - -// //未设置相关保证金系数默认为1.0 -// var client = clientList.FirstOrDefault(c => c.client.id == trade.ClientId); -// var clientRatio = client == null ? 1.0 : (client.clientlevel == null ? 1.0 : (client.clientlevel.Ratio ?? 1.0)); -// var clientAddRatio = client == null ? 0.0 : (client.clientlevel == null ? 0.0 : (client.clientlevel.AddRatio ?? 0.0)); - -// if (optionValueList.Any()) -// { -// var deltaMerge = 0.0; -// var deltaShort = optionValueList.Sum(t => t.ValueResult.Delta * (t.Trade.BuySell == "买入" ? 1 : 0)); -// var deltaMax = optionValueList.Sum(t => t.ValueResult.DeltaMax * (t.Trade.BuySell == "买入" ? 1 : 0)); -// //跨式组合和宽跨式组合用到的是组合交易里面的Max Delta作为deltaMerge参与保证金的计算 -// deltaMerge = trade.TradeType == "结构化交易" && (trade.StructureType == "跨式组合" || trade.StructureType == "宽跨式组合") ? Math.Abs(deltaMax) : Math.Abs(deltaShort); -// logger.Info("交易id为" + trade.id + "的delta:" + deltaMerge); -// //if (deltaLong * deltaShort == 0) -// //{ -// // deltaMerge = Math.Abs(deltaShort); -// //} -// //else if (deltaLong * deltaShort < 0) -// //{ -// // if (Math.Abs(deltaLong) >= Math.Abs(deltaShort)) -// // { -// // deltaMerge = 0; -// // } -// // else -// // { -// // deltaMerge = Math.Abs(deltaShort) - Math.Abs(deltaLong); -// // } -// //} -// //else -// //{ -// // deltaMerge = Math.Abs(deltaShort); -// //} -// mpProvider.TryGetMarginRate(trade.UnderlyingCode, out double marginRate); -// //保证金 = (交易保证金率+公司保证金率加点)*合约名义金额(期货价格*数量)*delta -// var value = deltaMerge * closePrice * (marginRate + FutureMarginAddRatio + clientAddRatio) * alphaRate * clientRatio; - -// if (trade.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == trade.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{trade.TradeNumber}在{settleDate.ToString("yyyy-MM-dd")}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } - -// tradeSpans.Add(new trade_span -// { -// TradeId = trade.id,//默认记录为第一条交易记录中 -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = trade.ClientId, -// ValueDate = settleDate, -// UnderlyingId = trade.UnderlyingId, -// UnderlyingCode = trade.UnderlyingCode, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value, -// Comment = $"标的{trade.UnderlyingCode},deltaMerge:{deltaMerge},closePrice:{closePrice},Margin:{marginRate},FutureMarginAddRatio:{FutureMarginAddRatio},clientAddRatio:{clientAddRatio},alphaRate:{alphaRate},clientRatio:{clientRatio}" -// }); -// } -// else -// { -// var nanTradeValue = tradeRiskResult.Results.Where(t => t.Trade.id == trade.id && (double.IsNaN(t.ValueResult.Delta) || !double.IsNaN(t.ValueResult.Vega) || !double.IsNaN(t.ValueResult.Gamma))).Select(t => t.ValueResult).ToList(); -// nanTradeValue.ForEach(optionValue => -// { -// logger.Error($"交易ID:{trade.UnderlyingId},Delta:{optionValue.Delta},DeltaCash{optionValue.DeltaCash},Vega{optionValue.Vega},Gamma:{optionValue.Gamma},vol:{optionValue.Vol}"); -// }); - -// } -// } -// } -// return tradeSpans; -// } -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//} diff --git a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/UniversalMarginCalculation.cs b/YLErpUnitTest/Modules/MarginModule/MarginCalculation/UniversalMarginCalculation.cs deleted file mode 100644 index d7e06987..00000000 --- a/YLErpUnitTest/Modules/MarginModule/MarginCalculation/UniversalMarginCalculation.cs +++ /dev/null @@ -1,182 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using YLErp.DBModels; -//using YLErp.DBModels.Consts; -//using YLErp.Model; -//using YLErp.Modules.MarginModule; - -//namespace YLErp.BLL.MarginCalculationBak -//{ -// public class UniversalMarginCalculation : MarginCalculationBase -// { -// // 定义一个静态变量来保存类的实例 -// public static readonly UniversalMarginCalculation Instance; - -// static UniversalMarginCalculation() -// { -// Instance = new UniversalMarginCalculation(); -// } - -// // 定义私有构造函数,使外界不能创建该类实例 -// private UniversalMarginCalculation() -// { -// } - -// public override List RunMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false, bool forSingleTrade = true, string volType = "交易", bool forOtherSide = false) -// { -// List tradeSpans = new List(); -// if (!(priceDict?.Count > 0)) -// { -// var codes = tradeList.Select(O => O.UnderlyingCode).ToArray(); -// priceDict = base.GetSettlePrice(codes, settleDate); -// } -// if (priceDict.Count == 0) -// { -// //如果价格没有传入也没从数据库获取到,就直接返回,没必要往下运行了。但不应该报错; -// return tradeSpans; -// } -// if (tradeList != null && tradeList.Count > 0) -// { -// var tempStockTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList(); -// if (tempStockTradeList.Any()) -// { -// var stockTradeSpanlist = StockMarginCalculation(userId, userName, tempStockTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle); -// if (stockTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(stockTradeSpanlist); -// } -// } -// var tempFutureTradeList = tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList(); -// if (tempFutureTradeList.Any()) -// { -// var futureTradeSpanlist = FutureMarginCalculation(userId, userName, tempFutureTradeList, settleDate, priceDict, hasOptionInfo, isEodSettle); -// if (futureTradeSpanlist.Count > 0) -// { -// tradeSpans.AddRange(futureTradeSpanlist); -// } -// } -// } -// return tradeSpans; -// } - -// /// -// /// 股票类期权计算保证金 -// /// -// public List StockMarginCalculation(int userId, string userName, List tradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false) -// { -// throw new Exception("未实现"); -// } - -// /// -// /// 商品期权计算保证金 -// /// -// public List FutureMarginCalculation(int userId, string userName, List futureTradeList, DateTime settleDate, Dictionary priceDict, bool hasOptionInfo = false, bool isEodSettle = false) -// { -// List tradeSpans = new List(); -// if (futureTradeList != null && futureTradeList.Count > 0) -// { -// using (YLContext db = new YLContext()) -// { -// var clientIds = futureTradeList.Select(t => t.ClientId).ToList(); -// var clientList = (from client in db.client -// join clientlevel in db.clientlevel -// on client.LevelId equals clientlevel.id into tempClientlevel -// from clientlevelTT in tempClientlevel.DefaultIfEmpty() -// where clientIds.Contains(client.id) -// select new -// { -// client, -// clientlevel = clientlevelTT -// }).ToList(); - -// var underlyingCodes = futureTradeList.Select(O => O.UnderlyingCode).ToHashSet(); -// var mpProvider = new MarginParamProvider(new OptUserInfo(0, "系统"), settleDate) -// .Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate); - -// if (clientList != null) -// { -// foreach (var t in futureTradeList) -// { -// priceDict.TryGetValue(t.UnderlyingId, out double price); -// mpProvider.TryGetMarginRate(t.UnderlyingCode, out double marginRate); -// var contractSize = (_underlyingDataProvider.GetUnderlying(t.UnderlyingCode)?.ContractSize) ?? 0; -// double diffPrice = 0; -// switch (t.OptionType) -// { -// case "看涨": -// diffPrice = (t.Strike ?? 0) - price; -// break; -// case "看跌": -// diffPrice = price - (t.Strike ?? 0); -// break; -// } -// double visualValue = Math.Max(diffPrice, 0) * contractSize; -// double futureMargin = price * marginRate * contractSize; -// double optionMargin1 = (t.StockEqvNotional ?? 0) + futureMargin - 0.5 * visualValue; -// double optionMargin2 = (t.StockEqvNotional ?? 0) + futureMargin * 0.5; - -// var client = clientList.FirstOrDefault(c => c.client.id == t.ClientId); -// if (client != null) -// { -// var value = Math.Max(optionMargin1, optionMargin2); - -// if (t.TradeType == "自定义交易") -// { -// var eodTradeRiskManual = db.eod_trade_risk_manual.Where(x => x.ValueDate <= settleDate && x.TradeId == t.id).OrderByDescending(x => x.ValueDate).FirstOrDefault(); -// //收盘时如果自定义交易还活着且没有维护当日风险,并且收的时系统日期当日的盘,抛出exception -// if (isEodSettle && !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && settleDate == valuedateBLL.SystemDate.ValueDate) -// { -// if (eodTradeRiskManual == null || eodTradeRiskManual.ValueDate != settleDate) -// { -// var error = $"TradeNumber:{t.TradeNumber}在{settleDate:yyyy-MM-dd}需先进行交易风险维护"; -// throw new Exception(error); -// } -// } - -// value = eodTradeRiskManual?.Margin ?? 0; -// } - -// tradeSpans.Add(new trade_span -// { -// TradeId = t.id, -// OptDate = DateTime.Now, -// OptId = userId, -// OptName = userName, -// ClientId = client.client.id, -// UnderlyingId = t.UnderlyingId, -// UnderlyingCode = t.UnderlyingCode, -// ValueDate = settleDate, -// Spv1 = value, -// Spv2 = value, -// Spv3 = value, -// Spv4 = value, -// WorstCastClientPayable = value -// }); -// } -// } -// } -// } -// } -// return tradeSpans; -// } - -// public override double GetTradeMargin(trade trade, double price, bool isInitialMargin = false, bool hasOptionInfo = false) -// { -// using (YLContext db = new YLContext()) -// { -// if (trade.TradeType == "结构化交易") -// { -// trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList(); -// } -// } - -// var tradeMargin = RunMarginCalculation(0, "系统", new List { trade }, isInitialMargin ? (trade.TradeDate ?? valuedateBLL.ValueDate) : valuedateBLL.ValueDate, new Dictionary { { trade.UnderlyingId, price } }, hasOptionInfo: hasOptionInfo); -// if (null != tradeMargin) -// { -// return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0; -// } -// return 0.0; -// } -// } -//}