using YLErp.BLL; using YLErp.DBModels.Converts; using YLErp.Model; using YLErp.Modules.CalculationModule; using YLErp.Modules.TradeModule; using YLErp.Modules.TradeModule.DealModule; using YLErp.Modules.UnderlyingModule; using YLErp.QdpModule; namespace YLErp.Modules.EodModule.SettlementModule { /// /// 日终互换自动结息 /// internal class EodSwapSettleService : TradeCashService { public EodSwapSettleService(OptUserInfo userInfo) : base(userInfo) { } /// /// 定期结算互换 /// public void BalanceSwapTrade(DateTime settleDate, IEnumerable clientIds = null) { var dateStr = settleDate.ToString("yyyy-MM-dd"); var observateTrades = new List(); #region 第一步 获取当前观察日交易 var tradePredicate = PredicateBuilder.Create(n => n.ValidState != ConsGlobal.InValid && n.TradeType == "收益互换" && n.IsGroup != 2 && n.StartDate <= settleDate && n.ExerciseDate >= settleDate && n.TradeStatus == ConsTrade.确认成交); if (clientIds != null && clientIds.Any()) { tradePredicate = tradePredicate.And(l => clientIds.Contains(l.ClientId)); } var tradeQueryList = DbContext.trade.Where(tradePredicate).ToList(); var tradeIds = tradeQueryList.Select(s => s.id).ToList(); var tradeSwapList = DbContext.trade_swap.Where(t => tradeIds.Contains(t.TradeId) && ((t.GetSwapTimeAndRate != null && t.GetSwapTimeAndRate.Contains(dateStr)) || (t.PaySwapTimeAndRate != null && t.PaySwapTimeAndRate.Contains(dateStr))) ).ToList(); foreach (var trade in tradeQueryList) { var tradeSwap = tradeSwapList.FirstOrDefault(x => x.TradeId == trade.id); var tradeExerciseDate = trade.ExerciseDate.Value.ToString("yyyy-MM-dd"); if (tradeExerciseDate != dateStr && tradeSwap != null && ((tradeSwap.GetSwapTimeAndRate != null && tradeSwap.GetSwapTimeAndRate.Contains(dateStr)) || (tradeSwap.PaySwapTimeAndRate != null && tradeSwap.PaySwapTimeAndRate.Contains(dateStr)))) { var getCalc = CalcDate(tradeSwap.GetSwapTimeAndRate, dateStr); var payCalc = CalcDate(tradeSwap.PaySwapTimeAndRate, dateStr); if (getCalc || payCalc) { trade.trade_swap = tradeSwap; observateTrades.Add(trade); } } } #endregion if (!observateTrades.Any()) { return; } #region 第二步 计算观察日收益 var tradeObservateIds = observateTrades.Select(s => s.id).ToList(); var tradeCashPredicate = PredicateBuilder.Create(n => tradeObservateIds.Contains(n.TradeId) && !n.IsDeleted && n.Action == ClientCashInCashOut.系统操作_互换); var tradeCashList = DbContext.trade_cash.Where(tradeCashPredicate).ToList(); var tradeCashIds = tradeCashList.Select(x => x.id); var cashSwaps = DbContext.trade_cash_swap.Where(x => tradeObservateIds.Contains(x.TradeId) && tradeCashIds.Contains(x.TradeCashId)).ToArray(); foreach (var trade in observateTrades) { //历史收盘时,如果已进行过互换则排除 if (tradeCashList.Any(x => x.TradeId == trade.id && x.ValidState != ConsGlobal.InValid && x.ValueDate >= settleDate)) { continue; } tradeBLL.SetFieldsByTradeType(trade); var tradeCashNotInvalid = tradeCashList.Where(x => x.TradeId == trade.id && x.ValidState != ConsGlobal.InValid).OrderByDescending(y => y.id).FirstOrDefault(); var um = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); var commodity = ConsGlobal.InstrumentType.CalcTypeIsFutures(um.UnderlyingInstrumentType); trade.trade_cash = InitTradeCash(trade, um); trade.trade_cash.ValueDate = settleDate; trade.trade_cash.UnwindMethod = commodity ? 1 : 0; InitTradeAndTradeCash(trade, trade.trade_cash, um, tradeCashNotInvalid); var oldMaturityDate = new ExtensionTimeService(UserInfo).QueryExtensionTimeList(trade.id).OrderByDescending(x => x.OldMaturityDate)?.FirstOrDefault()?.OldMaturityDate; trade.trade_swap.GetSwapRate = GetSwapRateByDate(trade.trade_swap.GetSwapTimeAndRate, trade.trade_cash.ValueDate, 1, trade.trade_swap.IsGetFloatingProfit, oldMaturityDate); trade.trade_swap.PaySwapRate = GetSwapRateByDate(trade.trade_swap.PaySwapTimeAndRate, trade.trade_cash.ValueDate, 1, trade.trade_swap.IsPayFloatingProfit, oldMaturityDate); trade.trade_cash.trade_cash_swap = new trade_cash_swap() { GetFinalPrice = trade.trade_swap.GetSpotPrice, PayFinalPrice = trade.trade_swap.PaySpotPrice, GetCostFee = 0, PayCostFee = 0, GetExtraAmount = 0, PayExtraAmount = 0, PayAmount = 0, PayInitialAmount = 0, GetSwapRate = 0, PaySwapRate = 0, IsAuto = true, GetInitialAmount = 0, GetAmount = 0 }; //取最后一次手动收益; var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto && x.TradeId == trade.id); var lastManualCash = lastManualCashSwap != null ? tradeCashList.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null; if (!trade.trade_swap.IsGetFloatingProfit)//收取 利息 { DateTime endDate; var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(trade, trade.trade_swap, trade.trade_cash.ValueDate, tradeCashNotInvalid, lastManualCash, trade.trade_swap.IsGetFloatingProfit, out endDate); trade.trade_cash.trade_cash_swap.GetExtraAmount = PayoffSwapCalcService.GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, trade.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, trade.trade_swap.AnnualDays ?? 0, (trade.OriginalStockEqvNotional ?? 0) * (trade.trade_cash.UnwindPercentRate ?? 0)); trade.trade_cash.trade_cash_swap.GetInitialAmount = PayoffSwapCalcService.GetInitialAmountSwapGet(trade, trade.trade_swap, trade.trade_swap.GetSpotPrice ?? 0 , trade.trade_swap.GetSpotPrice ?? 0, (trade.OriginalStockEqvNotional ?? 0) * (trade.trade_cash.UnwindPercentRate ?? 0), trade.trade_cash.ValueDate, tradeCashNotInvalid?.ValueDate); } if (!trade.trade_swap.IsPayFloatingProfit)//支付 利息 { DateTime endDate; var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(trade, trade.trade_swap, trade.trade_cash.ValueDate, tradeCashNotInvalid, lastManualCash, trade.trade_swap.IsPayFloatingProfit, out endDate); trade.trade_cash.trade_cash_swap.PayInitialAmount = PayoffSwapCalcService.GetInitialAmountSwapPay(trade, trade.trade_swap, trade.trade_swap.PaySpotPrice ?? 0 , trade.trade_swap.PaySpotPrice ?? 0, (trade.OriginalStockEqvNotional ?? 0) * (trade.trade_cash.UnwindPercentRate ?? 0), trade.trade_cash.ValueDate, tradeCashNotInvalid?.ValueDate); trade.trade_cash.trade_cash_swap.PayExtraAmount = PayoffSwapCalcService.GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, trade.trade_swap.PaySwapTimeAndRate, preSwapDate, trade.trade_cash.ValueDate, trade.trade_swap.AnnualDays ?? 0, (trade.OriginalStockEqvNotional ?? 0) * (trade.trade_cash.UnwindPercentRate ?? 0)); } trade.trade_cash.trade_cash_swap.PaySwapRate = trade.trade_swap.PaySwapRate; trade.trade_cash.trade_cash_swap.GetSwapRate = trade.trade_swap.GetSwapRate; trade.trade_cash.trade_cash_swap.GetAmount = trade.trade_cash.trade_cash_swap.GetInitialAmount + trade.trade_cash.trade_cash_swap.GetExtraAmount + trade.trade_cash.trade_cash_swap.GetCostFee; trade.trade_cash.trade_cash_swap.PayAmount = trade.trade_cash.trade_cash_swap.PayInitialAmount + trade.trade_cash.trade_cash_swap.PayExtraAmount + trade.trade_cash.trade_cash_swap.PayCostFee; trade.trade_cash.Amount = (trade.trade_cash.trade_cash_swap.GetAmount ?? 0) - (trade.trade_cash.trade_cash_swap.PayAmount ?? 0); trade.trade_cash.Notional = trade.trade_cash.TradeAmount.Value * (um.CountRatio == 0 ? 1 : um.CountRatio); #region 第三步 单个封装对象保存 var req = new TradeCashReq { TradeId = trade.id, ValueDate = trade.trade_cash.ValueDate, Amount = trade.trade_cash.Amount, UnwindFee = trade.trade_cash.Amount, InitialAmount = trade.trade_cash.InitialAmount, ExtraAmount = trade.trade_cash.ExtraAmount ?? 0, UnwindMethod = trade.trade_cash.UnwindMethod ?? 0, UnwindStockEqvNotional = trade.trade_cash.UnwindStockEqvNotional, UnwindPrice = trade.trade_cash.UnwindPrice, FinalPrice = trade.trade_cash.FinalPrice, SpotPrice = trade.trade_cash.SpotPrice, UnwindVol = trade.trade_cash.UnwindVol, HappenedDate = trade.trade_cash.HappenedDate, BarrierPrice = trade.trade_cash.BarrierPrice, VolType = trade.trade_cash.VolType, UnwindType = trade.trade_cash.UnwindType, UnwindPercentRate = (trade.trade_cash.UnwindPercentRate * 100) ?? 0, UnwindPricePercentRate = trade.trade_cash.UnwindPercentRate ?? 0, TradePremium = trade.trade_cash.TradePremium, AdvanceMoney = trade.trade_cash.AdvanceMoney, trade_cash_swap = trade.trade_cash.trade_cash_swap }; var result = new TradeUnwindService(this).SwapTrade(req); #endregion } #endregion } /// /// 初始化收益互换值 /// private trade_cash InitTradeCash(trade td, underlying_manager um) { var r = new trade_cash { TradeId = td.id, FinalPrice = um.UnderlyingType == "组合标的" ? new SyntheticUnderlyingPriceService(UserInfo).GetPrice(td.UnderlyingCode) : (um.Price ?? 0), ExceciseType = "现金", CallPut = td.CallPut, Strike = td.IsMoneynessOptionData ? (td.Strike * td.SpotPrice) : td.Strike, Notional = td.Notional, UnwindType = "全部平仓", UnwindNotional = td.Notional, UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional, Amount = 0 }; r.TradeAmount = r.Notional / um.CountRatio; r.UnwindTradeAmount = r.UnwindNotional / um.CountRatio; return r; } /// /// 初始化收益互换值 /// private void InitTradeAndTradeCash(trade td, trade_cash r, underlying_manager um, trade_cash notInvalid) { r.StockEqvNotional = td.StockEqvNotional; r.OriginalStockEqvNotional = td.OriginalStockEqvNotional ?? 0; r.IsUsePremiumRate = td.IsUsePremiumRate; r.IsTradePricePayType = td.IsTradePricePayType; if (td.IsUsePremiumRate != null && td.IsUsePremiumRate.Value) { //r.UnwindPercentRate *= 100; } else { r.UnwindPercentRate = 0; } r.TradeOriginalAmount = td.OriginalNotional / um.CountRatio; r.OriginalNotional = td.OriginalNotional; r.UnderlyingCode = td.UnderlyingCode; r.UnderlyingId = um.id; r.UnderlyingInstrumentType = td.UnderlyingInstrumentType; r.TradeType = BuySellConvert.GetClientBuySell(td.BuySell); r.BondType = td.TradeType; r.ClientName = td.ClientName; r.TraderName = td.TraderName; r.UnwindStockEqvNotional = r.UnwindStockEqvNotional ?? 0; r.StartDate = notInvalid?.ValueDate ?? td.StartDate.Value; r.ExtraAmount = td.OriginalStockEqvNotional > 0 ? (td.trade_swap.IsTradePriceWhenOpen ? ((td.trade_swap.GetTradePrice ?? 0) - (td.trade_swap.PayTradePrice ?? 0)) : ((td.trade_swap.GetTradePrice ?? 0) - (td.trade_swap.PayTradePrice ?? 0)) * 2) * td.StockEqvNotional / td.OriginalStockEqvNotional : 0; //td.trade_swap.GetSpotPrice = td.trade_swap.GetFinalPrice ?? td.trade_swap.GetSpotPrice ?? 0; //td.trade_swap.PaySpotPrice = td.trade_swap.PayFinalPrice ?? td.trade_swap.PaySpotPrice ?? 0; } /// /// 校验某观察日是否结算 /// private bool CalcDate(string swapTime, string dataStr) { if (string.IsNullOrEmpty(swapTime)) { return false; } var calc = false; var filedArr = swapTime.Split(';'); var dateListArr = filedArr[0]; if (filedArr.Length > 2) { var calcListArr = filedArr[2];//是否结算 var calcList = calcListArr.Split(','); var dateList = dateListArr.Split(','); for (var i = 0; i < dateList.Length; i++) { if (dateList[i] == dataStr && i <= calcList.Length - 1 && calcList[i] == "true") { calc = true; break; } } } return calc; } private double GetSwapRateByDate(string swapTimeAndRate, DateTime valueDate, int IsSwap, bool IsFloatingProfit = true, DateTime? oldMaturityDate = null) { double swapRate = 0; var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(swapTimeAndRate); var dates = customizedResults.Item1; if (dates == null) { return swapRate; } var getSwapRates = customizedResults.Item2; var latestDate = dates.Where(x => x.DateTime >= valueDate).OrderBy(x => x.DateTime).FirstOrDefault(); //展期情况互换利率获取最后一个日期的互换利率 if (latestDate == null) { latestDate = dates.Max(); } if (latestDate != null) { if (getSwapRates != null && getSwapRates.Any()) { swapRate = getSwapRates[TradeObservationHelper.GetDateIndex(dates, latestDate)]; } } return swapRate; } } }