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