using NPOI.SS.Formula.Functions; using OfficeOpenXml; using System; using YLErp.BLL.EodSettlement; using YLErp.Modules.CalculationModule; using YLErp.Modules.EodModule.QueryModule; using YLErp.Modules.MarginModule; using YLErp.Modules.SwapModule; using YLErp.Office; using static YLErp.Modules.MarginModule.MarginRateSwapService; namespace YLErp.Web.Controllers { public class MarginRateSwapController : BaseController { [MyAuthorize("互换簿记预设-互换预付金率维护")] public ActionResult MarginRateSwapList() { var MarginRateSwaps = yldb.client_marginrate.ToList(); GetExtendInfo(MarginRateSwaps); return View(MarginRateSwaps); } [MyAuthorize("互换簿记预设-互换预付金率修改")] public ActionResult MarginRateSwapEdit(string enid, string type) { var id = DecryptInt(enid); if (id == 0) { return View(new client_marginrate() { Type = type }); } var MarginRateSwap = yldb.client_marginrate.Find(id); GetExtendInfo(new List { MarginRateSwap }); return View(MarginRateSwap); } [MyAuthorize("互换簿记预设-互换预付金率修改")] public JsonResult ImportMagrinRate() { if (Request.Form.Files.Count == 0) { return JsonError("上传文件不存在"); } var file = Request.Form.Files[0]; if (!Path.GetExtension(file.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase)) { return JsonError("请上传Excel(.xlsx)格式文件"); } using var stream = file.OpenReadStream(); new MarginRateSwapService(CurUser).ImportMarginRate(stream, out var TotalNum, out var SuccessNum); return Json(new { success = true, totalNum = TotalNum, successNum = SuccessNum, }); } [MyAuthorize("互换簿记预设-互换预付金率修改")] public JsonResult MarginRateSwapDelete(string enid) { var id = DecryptInt(enid); var MarginRateSwap = yldb.client_marginrate.Find(id); if (MarginRateSwap == null) { throw new ServiceException("数据库中未找到"); } yldb.client_marginrate.Remove(MarginRateSwap); yldb.SaveChanges(); return JsonSuccess("已删除"); } [MyAuthorize("互换簿记预设-互换预付金率修改")] public JsonResult MarginRateSwapEditJson(client_marginrate MarginRateSwap) { MarginRateSwap.InitMarginRate /= 100; MarginRateSwap.ClosePositionLine /= 100; MarginRateSwap.WarningLine /= 100; MarginRateSwap.InitMarginRebateRate /= 100; MarginRateSwap.AddToMarginRebateRate /= 100; MarginRateSwap.LongInitMarginRate /= 100; MarginRateSwap.ShortInitMarginRate /= 100; MarginRateSwap.MaintenanceRate /= 100; new MarginRateSwapService(CurUser).saveMarginRate(MarginRateSwap); return JsonSuccess("已修改"); } [HttpPost] public JsonResult MarginRateSwapQuery(MarginRateSwapReq req) { var sList = new MarginRateSwapService(CurUser).SearchList(req); GetExtendInfo(sList.rows); return Json(sList); } private void GetExtendInfo(IEnumerable MarginRateSwaps) { foreach (var item in MarginRateSwaps) { if (item.ClientId != 0) { var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId); if (client != null) { item.ClientName = client.Name; } } var variety = DataCacheProvider.GetVarietyDataSource().GetData(item.VarietyId ?? 0); if (variety != null) { item.VarietyCode = variety.VarietyCode; item.VarietyName = variety.VarietyName; } } } public ActionResult MarginRateSwapMonitor() { ViewBag.valueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd"); return View(); } [HttpPost] public JsonResult MarginRateSwapMonitorQuery(MarginRateSwapMonitorReq req) { return Json(monitorQuery(req)); } private List monitorQuery(MarginRateSwapMonitorReq req) { var valueDate = valuedateBLL.ValueDate; var tradePredicate = PredicateBuilder.Create(t => t.TradeStatus.Equals(ConsTrade.确认成交) && t.ValidState != "InValid" && t.TradeType.Equals("收益互换")); if (req.ClientIds != null && req.ClientIds.Count() > 0) { tradePredicate = tradePredicate.And(t => req.ClientIds.Contains(t.ClientId)); } if (req.AssetIds != null && req.AssetIds.Count() > 0) { tradePredicate = tradePredicate.And(t => req.AssetIds.Contains(t.AssetId)); } if (req.TradeNumber != null) { tradePredicate = tradePredicate.And(t => t.TradeNumber.Contains(req.TradeNumber)); } if (req.DateFromTradeDate != null) { tradePredicate = tradePredicate.And(t => t.TradeDate >= req.DateFromTradeDate); } if (req.DateToTradeDate != null) { tradePredicate = tradePredicate.And(t => t.TradeDate <= req.DateToTradeDate); } //获取所有确认成交的收益互换 var query = from trade in yldb.trade.Where(tradePredicate) join tradeSwap in yldb.trade_swap on trade.id equals tradeSwap.TradeId join tradeSwapDetailTemp1 in yldb.trade_swap_detail.Where(t => t.ValidState != "InValid" || t.ValidState == null) on tradeSwap.TradeId equals tradeSwapDetailTemp1.TradeId into tradeSwapDetailTemp from tradeSwapDetail in tradeSwapDetailTemp.DefaultIfEmpty() join tradeSwapDetailSonTemp1 in yldb.trade_swap_detail on tradeSwap.TradeId equals tradeSwapDetailSonTemp1.ChildTradeId into tradeSwapDetailSonTemp from tradeSwapDetailSon in tradeSwapDetailSonTemp.DefaultIfEmpty() where tradeSwapDetailSon == null select new { trade, tradeSwap, tradeSwapDetail }; if (req.SwapType != null) { query = query.Where(t => t.tradeSwap.SwapType.Equals(req.SwapType)); } if (req.SwapType != null) { query = query.Where(t => t.tradeSwap.SwapType.Equals(req.SwapType)); } var tradeSwapList = query.AsEnumerable().GroupBy(t => new { t.trade.id }).Select(t => new TradeSwapMarginMonitorModel { TradeId = t.FirstOrDefault().trade.id, TradeNumber = t.FirstOrDefault().trade.TradeNumber, TradeDate = t.FirstOrDefault().trade.TradeDate, ClientId = t.FirstOrDefault().trade.ClientId, ClientName = t.FirstOrDefault().trade.ClientName, AssetId = t.FirstOrDefault().trade.AssetId, AssetBookName = t.FirstOrDefault().trade.AssetBookName, SwapType = t.FirstOrDefault().tradeSwap.SwapType, LongShort = t.FirstOrDefault().tradeSwap.SwapType.Equals(SwapTypeEnum.多空组合.ToString()) ? null : t.FirstOrDefault().tradeSwap.PayLongShort, StockEqvNotional = t.FirstOrDefault().trade.OriginalStockEqvNotional ?? 0, tradeAmount = t.FirstOrDefault().trade.OriginalNotional ?? 0, PositionNotional = t.FirstOrDefault().trade.StockEqvNotional, PositionAmount = t.FirstOrDefault().trade.Notional, UnderlyingCode = t.FirstOrDefault().trade.UnderlyingCode, SpotPrice = t.FirstOrDefault().tradeSwap.PaySpotPrice ?? 0.0, //Price InitMarginRate = t.FirstOrDefault().tradeSwap.GetMarginRate ?? 0.0, InitMargin = (t.FirstOrDefault().tradeSwap.GetMarginRate ?? 0.0) * t.FirstOrDefault().trade.StockEqvNotional, //PostionProfitLoss //PositionValue //PositionMarginRate //PositionMargin //CreditOccupy //Margin Trade = t.FirstOrDefault().trade, TradeSwap = t.FirstOrDefault().tradeSwap, TradeSwapDetails = t.Where(a => a.tradeSwapDetail != null).Select(a => a.tradeSwapDetail).ToList() }).OrderByDescending(t => new { t.TradeId }).ToList(); #region 交易层面授信暂不计算 ////所有客户id列表 //var clientIds = tradeSwapList.Select(t => t.ClientId).Distinct().ToList(); ////获取客户所有互换授信信息 //var creditList = yldb.credit.Where(t => // clientIds.Contains(t.ClientId ?? 0) && t.ProcessStatus == "已审批" && // (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate) && (t.DerivativesInvestmentVarieties == null || t.DerivativesInvestmentVarieties.Contains(DerivativesInvestmentVarietiesEnum.场外互换.ToString()))).ToList(); #endregion //所有客户id列表 var clientIds = tradeSwapList.Select(t => t.ClientId).Distinct().ToList(); //增加clientId=0,默认为全部 clientIds.Add(0); //获取客户互换预付金预警设置 var marginRateList = yldb.client_marginrate.Where(t => clientIds.Contains(t.ClientId) && t.ValueDate <= valueDate).ToList(); TradeValueResult valueResult; tradeSwapList.ForEach(t => { //计算利息收入 利息 增强收益 var swapStartDate = (t.Trade.StartDate ?? t.Trade.TradeDate).Value.AddDays(t.TradeSwap.IncludeFirstDay ? -1 : 0); t.InterestIncome = PayoffSwapCalcService.GetExtraAmountBySwapRate(t.Trade.ClientId, t.Trade.TradeDate, t.TradeSwap.GetSwapTimeAndRate, swapStartDate, valuedateBLL.ValueDate, t.TradeSwap.AnnualDays ?? 0, t.PositionNotional) - PayoffSwapCalcService.GetExtraAmountBySwapRate(t.Trade.ClientId, t.Trade.TradeDate, t.TradeSwap.PaySwapTimeAndRate, swapStartDate, valuedateBLL.ValueDate, t.TradeSwap.AnnualDays ?? 0, t.PositionNotional); //手续费 t.Commission = ((t.TradeSwap.GetTradePrice ?? 0) - (t.TradeSwap.PayTradePrice ?? 0)) * (t.Trade.OriginalStockEqvNotional == null ? 1.0 : (t.PositionNotional / t.Trade.OriginalStockEqvNotional.Value)); //预付金率 取Get Pay双向 t.InitMarginRate = (t.TradeSwap.GetMarginRate ?? 0.0) - (t.TradeSwap.PayMarginRate ?? 0); t.InitMargin = t.InitMarginRate * t.PositionNotional; t.SpotPrice = t.TradeSwap.IsGetFloatingProfit ? (t.TradeSwap.GetSpotPrice ?? 0.0) : (t.TradeSwap.IsPayFloatingProfit ? (t.TradeSwap.PaySpotPrice ?? 0.0) : 0.0); if (SwapTypeEnum.多空组合.ToString().Equals(t.SwapType)) { //浮动收益年化利率 var annualRate = PayoffSwapCalcService.GetAnnualVarIncomeRate(t.TradeSwap, valueDate, null, t.Trade.StartDate.Value, t.Trade.ExerciseDate.Value)??1.0; var longNotional = 0.0; var shotNotional = 0.0; t.FloatingProfitTypeStr = "--"; if (t.TradeSwapDetails != null && t.TradeSwapDetails.Count > 0) { t.TradeSwapDetailList = t.TradeSwapDetails.Select(d => new TradeSwapDetailExtend(d)).ToList(); t.TradeSwapDetailList.ForEach(a => { if (a.LongShort == "多头") { longNotional += (a.Notional ?? 0.0) * (a.SpotPrice ?? 0.0); } else if (a.LongShort == "空头") { shotNotional += (a.Notional ?? 0.0) * (a.SpotPrice ?? 0.0); } a.price = DataCacheProvider.GetUnderlyingDataSource().GetPrice(a.UnderlyingCode); a.pv = t.InterestIncome * ((a.Notional ?? 0.0) * (a.SpotPrice ?? 0.0) / t.PositionNotional) + annualRate * (a.price - (a.SpotPrice ?? 0.0)) * (a.Notional ?? 0.0) * ("空头".Equals(a.LongShort) ? -1.0 : 1.0) * (a.IsForGet ? 1 : -1) + (t.TradeSwap.IsTradePriceWhenOpen ? 0 : ((a.TradePrice ?? 0.0) * (a.IsForGet ? -1 : 1))); a.profitLoss = a.pv + (t.TradeSwap.IsTradePriceWhenOpen ? ((a.TradePrice ?? 0.0) * (a.IsForGet ? -1 : 1)) : 0); }); t.PositionLongNotional = longNotional; t.PositionShortNotional = shotNotional; } else { t.TradeSwapDetailList = new List(); } t.InitMargin = t.InitMarginRate * Math.Max(longNotional, shotNotional); t.LongShort = string.Format("多头({0}),空头({1})", t.TradeSwapDetailList.Where(a => "多头".Equals(a.LongShort)).Count(), t.TradeSwapDetailList.Where(a => "空头".Equals(a.LongShort)).Count()); t.PositionValue = t.TradeSwapDetailList.Sum(a => a.pv); t.PostionProfitLoss = t.TradeSwapDetailList.Sum(a => a.profitLoss); t.PositionMargin = t.InitMargin - t.PositionValue; t.PositionMarginRate = t.PositionMargin / Math.Max(longNotional, shotNotional); t.Margin = Math.Max(t.InitMargin - t.PositionMargin, 0); t.waringLine = t.PositionMarginRate; t.closepPositionLine = 0.0; var marginRate1 = marginRateList.Where(a => a.Type.Equals("多空组合") && a.ClientId == t.ClientId).OrderByDescending(a => a.ClientId).ThenByDescending(a => a.ValueDate).FirstOrDefault(); if (marginRateList.Any(a => a.Type.Equals("多空组合") && (a.ClientId == t.ClientId || a.ClientId == 0))) { var marginRate = marginRateList.Where(a => a.Type.Equals("多空组合") && (a.ClientId == t.ClientId || a.ClientId == 0)).OrderByDescending(a => a.ClientId).ThenByDescending(a => a.ValueDate).FirstOrDefault(); t.waringLine = marginRate.WarningLine; t.closepPositionLine = marginRate.ClosePositionLine; } } else { t.LongShort = t.TradeSwap.IsGetFloatingProfit ? t.TradeSwap.GetLongShort : (t.TradeSwap.IsPayFloatingProfit ? t.TradeSwap.PayLongShort : ""); t.PositionLongNotional = t.LongShort == "多头" ? t.PositionNotional : 0.0; t.PositionShortNotional = t.LongShort == "空头" ? t.PositionNotional : 0.0; valueResult = PayoffSwapCalcService.CalcValue(t.Trade, valueDate, null, false); t.FloatingProfitTypeStr = t.TradeSwap.IsGetFloatingProfit ? "收取" : "支付"; t.Price = DataCacheProvider.GetUnderlyingDataSource().GetPrice(t.UnderlyingCode); t.PositionValue = valueResult.Pv; //t.Commission = valueResult.ExtendInfo.Commission; //开仓支付手续费是盈亏计算手续费 t.PostionProfitLoss = valueResult.Pv + (t.TradeSwap.IsTradePriceWhenOpen ? (t.Commission) : 0); t.PositionMargin = t.InitMargin - t.PositionValue; t.PositionMarginRate = t.PositionNotional == 0 ? 0 : t.PositionMargin / t.PositionNotional; t.Margin = Math.Max(t.InitMargin - t.PositionMargin, 0); t.waringLine = t.PositionMarginRate; t.closepPositionLine = 0.0; var variety = DataCacheProvider.GetVariety(t.UnderlyingCode); if (variety != null) { if (marginRateList.Any(a => a.Type.Equals("品种") && (a.ClientId == t.ClientId || a.ClientId == 0) && a.VarietyId == variety.id)) { var marginRate = marginRateList.Where(a => a.Type.Equals("品种") && (a.ClientId == t.ClientId || a.ClientId == 0) && a.VarietyId == variety.id).OrderByDescending(a=>a.ClientId).ThenByDescending(a => a.ValueDate).FirstOrDefault(); t.waringLine = marginRate.WarningLine; t.closepPositionLine = marginRate.ClosePositionLine; } } } if (t.PositionMarginRate <= t.closepPositionLine) { t.WaringStatus = "达到平仓线"; } else if (t.PositionMarginRate <= t.waringLine) { t.WaringStatus = "达到预警线"; } else { t.Margin = 0.0;//不到预警线不追保 t.WaringStatus = "无预警"; } }); List underlyingCodes = null; if (req.VarietyIds != null && req.VarietyIds.Count() > 0) { underlyingCodes = (from underlying in yldb.underlying_manager where req.VarietyIds.Contains(underlying.UnderlyingTypeId) select underlying.UnderlyingCode).ToList(); } if (req.UnderlyingIds != null && req.UnderlyingIds.Count() > 0) { underlyingCodes = (from underlying in yldb.underlying_manager where req.UnderlyingIds.Contains(underlying.id) select underlying.UnderlyingCode).ToList(); } if (underlyingCodes != null && underlyingCodes.Count() > 0) { tradeSwapList = tradeSwapList.Where(t => underlyingCodes.Contains(t.Trade.UnderlyingCode) || t.TradeSwapDetails.Any(a => underlyingCodes.Contains(a.UnderlyingCode))).ToList(); } if (req.WarnningTypes != null && req.WarnningTypes.Count() > 0 && tradeSwapList.Count() > 0) { tradeSwapList = tradeSwapList.Where(t => req.WarnningTypes.Contains(t.WaringStatus)).ToList(); } return tradeSwapList; } public ActionResult execlExport(MarginRateSwapMonitorReq req) { var sourceFileName = Path.Combine(OtcAppContext.MapPath("~/App_Docs/导出模板/"), "收益互换预付金监控.xlsx"); var list = monitorQuery(req); var modleDict = new Dictionary { ["Sheet1"] = new { InfoList = list.Select(t => new { t.TradeNumber, t.ClientName, t.AssetBookName, t.SwapType, t.LongShort, TradeDate = t.TradeDate == null ? "" : (t.TradeDate.Value.ToString("yyyy-MM-dd")), t.StockEqvNotional, t.tradeAmount, t.PositionNotional, t.PositionAmount, t.UnderlyingCode, t.SpotPrice, t.Price, t.InitMarginRate, t.PostionProfitLoss, t.PositionValue, t.InitMargin, t.PositionMargin, t.PositionMarginRate, t.Margin }).ToList() } }; var result = OtcAppContext.GetExportFileOutputPath($"收益互换预付金监控_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); new ExcelTemplateGenerator().SetTemplateFile(sourceFileName).SetTemplateData(modleDict).OutputToFile(result.PhysicalPath); return JsonSuccess("收益互换预付金监控成功", result.WebPath); } #region 新版互换预付金监控预警 /// /// 新版互换预付金监控预警 /// /// public ActionResult MarginRateSwapMonitorV2() { ViewBag.valueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd"); var swapMonitorConfgValue = AppManager.GetSwapMonitorValue(); SwapMonitorConfig monitorConfig=new SwapMonitorConfig(); if (!string.IsNullOrEmpty(swapMonitorConfgValue)) { monitorConfig = JsonHelper.Deserialize(swapMonitorConfgValue); } ViewBag.swapMonitorConfg = monitorConfig; return View(); } /// /// 设置预警线 /// /// /// [HttpPost] public JsonResult SetSwapMonitor(SwapMonitorConfig swapMonitorConfig) { AppManager.SetSwapMonitorValue(JsonHelper.Serialize(swapMonitorConfig)); return JsonSuccess(); } /// /// 互换预付金监控查询 /// /// /// public JsonResult MarginRateSwapMonitorQueryV2(SwapMarginMonitorRequest req) { var valueDate = valuedateBLL.ValueDate; var clientPredicate = PredicateBuilder.Create(x=>x.ProcessStatus=="已开户"); if (req.ClientIds.Any()) { clientPredicate = clientPredicate.And(d => req.ClientIds.Contains(d.id)); } if (req.SwapTypes.Any()) { clientPredicate = clientPredicate.And(d => req.SwapTypes.Contains(d.SwapTradeType??0)); } var swapMonitorConfgValue = AppManager.GetSwapMonitorValue(); SwapMonitorConfig monitorConfig = new SwapMonitorConfig(); if (!string.IsNullOrEmpty(swapMonitorConfgValue)) { monitorConfig = JsonHelper.Deserialize(swapMonitorConfgValue); } var clientquery = DataCacheProvider.GetClientDataSource().AsQueryable(clientPredicate); var clientIds= clientquery.Select(s => s.id).ToList(); var reqSort = req.sidx; var reqSord = req.sord; var balanceList= ClientBalanceUtility.GetClientBanlances(clientIds, DateTime.MinValue, valueDate); SearchListResult searchList = new SearchListResult(); if (req.WarnningTypes.Any()) { if (req.WarnningTypes.Contains("达到平仓线")) { balanceList = balanceList.Where(x => x.MaintenanceLine <= monitorConfig.UnwindLine * 0.01); } else if (req.WarnningTypes.Contains("达到预警线")) { balanceList = balanceList.Where(x => x.MaintenanceLine <= monitorConfig.WarningLine * 0.01&& x.MaintenanceLine > monitorConfig.UnwindLine * 0.01); } else if (req.WarnningTypes.Contains("无预警")) { balanceList = balanceList.Where(x => x.MaintenanceLine > monitorConfig.WarningLine * 0.01); } } req.sord = reqSord; req.sidx=string.IsNullOrEmpty(reqSort)? "ClientNumber" : reqSort; searchList = balanceList.AsQueryable().ToSearchList(req); return Json(searchList); } /// /// 互换预付金监控导出 /// /// /// public object ExportMarginRateSwapMonitor(SwapMarginMonitorRequest req) { req.page = 1; req.rows = 10000; var list = MarginRateSwapMonitorQueryV2(req).Value as SearchListResult; var tplFilePath = OtcAppContext.MapPath("/App_Docs"); var sourceFileName = Path.Combine(tplFilePath, "导出模板", "互换预付金监控导出模板.xlsx"); var modelDict = new Dictionary(); var model = new { list = list.rows }; modelDict.Add("Sheet1", model); ExcelPackage.LicenseContext = LicenseContext.NonCommercial; var bytes= new ExcelTemplateGenerator().SetTemplateFile(sourceFileName).SetTemplateData(modelDict).Output(); return File(bytes, xlsxMimeType, $"互换预付金监控导出{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } #endregion } }