From 89df4443bd7a21801cbfe620949c27a09e29c557 Mon Sep 17 00:00:00 2001 From: gongpei Date: Tue, 21 Oct 2025 13:43:32 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=E5=80=BA=E5=88=B8=E4=BB=98?= =?UTF-8?q?=E6=81=AF=E6=94=B6=E7=9B=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Framework/YLErp.Core/DBModels/BondPayment.cs | 108 ++++++++++++ .../YLErp.Core/DBModels/underlying_manager.cs | 5 + YLErpDAL/DataBase/YLContext.cs | 2 + .../Modules/EodModule/BondPaymentService.cs | 159 ++++++++++++++++++ .../Modules/SwapModule/SwapDealService.cs | 12 +- .../SwapModule/SwapEodPositionService.cs | 11 +- YLErpWeb/App_Data/FunctionRight.xml | 2 + YLErpWeb/Common/UserInfoRight.cs | 2 + YLErpWeb/Controllers/BondPaymentController.cs | 94 +++++++++++ .../Views/BondPayment/BondPaymentEdit.cshtml | 57 +++++++ .../Views/BondPayment/BondPaymentList.cshtml | 43 +++++ .../Views/BondPayment/BondPaymentView.cshtml | 46 +++++ .../Views/eod_trade_value/eodExecV2.cshtml | 5 + YLErpWeb/YLErpWeb.csproj | 8 +- .../app/bondPayment/bondpaymentList.js | 89 ++++++++++ .../Scripts/app/swaptrade/unwindSwapTrade.js | 14 ++ 16 files changed, 651 insertions(+), 6 deletions(-) create mode 100644 Framework/YLErp.Core/DBModels/BondPayment.cs create mode 100644 YLErpDAL/Modules/EodModule/BondPaymentService.cs create mode 100644 YLErpWeb/Controllers/BondPaymentController.cs create mode 100644 YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml create mode 100644 YLErpWeb/Views/BondPayment/BondPaymentList.cshtml create mode 100644 YLErpWeb/Views/BondPayment/BondPaymentView.cshtml create mode 100644 YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js diff --git a/Framework/YLErp.Core/DBModels/BondPayment.cs b/Framework/YLErp.Core/DBModels/BondPayment.cs new file mode 100644 index 00000000..bcf23d60 --- /dev/null +++ b/Framework/YLErp.Core/DBModels/BondPayment.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using YieldChain.Security; +using YLErp.DBModels.Base; + +namespace YLErp.DBModels +{ + /// + /// 债券期间付息表 + /// + [Table("bond_payment_info")] + public class BondPayment + { + public long id { get; set; } + + /// + /// 加密主键 + /// + [NotMapped] + public string EncryptId + { + get { return DataProtect.Encrypt(id.ToString()); } + } + /// + /// 债券代码 + /// + [Column("inner_code")] + public int inner_code { get; set; } + + [Column("underlying_code")] + public string underlyingCode { get; set; } + /// + /// 债券代码 + /// + [DisplayName("债券代码")] + [NotMapped] + public string security_id { get; set; } + + /// + /// 债券名称 + /// + [DisplayName("债券名称")] + [NotMapped] + public string symbol { get; set; } + /// + /// 利息税率(%) + /// + [DisplayName("利息税率(%)")] + [Column("interest_tax_rate")] + public decimal? coupon_rate { get; set; } + + /// + /// 现金流发放日 + /// + [DisplayName("理论付息(兑付)日")] + [Column("pay_date_PL")] + public DateTime? payment_date_pl { get; set; } + /// + /// 现金流发放日 + /// + [DisplayName("实际付息(兑付)日")] + [Column("pay_date_act")] + public DateTime? payment_date { get; set; } + /// + /// 每张兑付利息额 + /// + [DisplayName("每张兑付利息额")] + [Column("paying_interest")] + public decimal? payment_interest { get; set; } + /// + /// 每张兑付本金额 + /// + [DisplayName("每张兑付本金额")] + [Column("paying_principal")] + public decimal? payment_parvalue { get; set; } + + /// + /// 每张兑付本息额 + /// + [DisplayName("每张兑付本息额")] + [Column("paying_price")] + public decimal? paying_price { get; set; } + + /// + /// 渠道来源 + /// + [Column("info_source")] + public string channel_source { get; set; } + /// + /// 聚源JSID + /// + public long jsid { get; set; } + /// + /// 发布时间 + /// + [Column("insert_time")] + public DateTime create_time { get; set; } + /// + /// 更新时间 + /// + [Column("update_time")] + public DateTime update_time { get; set; } + } +} diff --git a/Framework/YLErp.Core/DBModels/underlying_manager.cs b/Framework/YLErp.Core/DBModels/underlying_manager.cs index 7c200bcf..89fea84e 100644 --- a/Framework/YLErp.Core/DBModels/underlying_manager.cs +++ b/Framework/YLErp.Core/DBModels/underlying_manager.cs @@ -317,6 +317,11 @@ namespace YLErp.DBModels public string UnderlyingPinYin { get; set; } + /// + /// 聚源内部id + /// + public long? InnerCode { get; set; } + public override string ToString() { return $"{UnderlyingCode}--{UnderlyingName}--{id}--{UnderlyingInstrumentType}"; diff --git a/YLErpDAL/DataBase/YLContext.cs b/YLErpDAL/DataBase/YLContext.cs index 73d418c8..b6ed6e6d 100644 --- a/YLErpDAL/DataBase/YLContext.cs +++ b/YLErpDAL/DataBase/YLContext.cs @@ -406,5 +406,7 @@ namespace YLErp.BLL public DbSet clientMarginConfig { get; set; } public DbSet clientMarginDetail { get; set; } public DbSet tradeContractOaResult { get; set; } + public DbSet bondPayment { get; set; } + } } \ No newline at end of file diff --git a/YLErpDAL/Modules/EodModule/BondPaymentService.cs b/YLErpDAL/Modules/EodModule/BondPaymentService.cs new file mode 100644 index 00000000..05f5a1cf --- /dev/null +++ b/YLErpDAL/Modules/EodModule/BondPaymentService.cs @@ -0,0 +1,159 @@ +using BaseOUDAL; +using DocumentFormat.OpenXml.Bibliography; +using ExcelDataReader.Log; +using YLErp.DBModels; +using YLErp.Helpers; + +namespace YLErp.Modules.EodModule +{ + /// + /// 债券期间付息服务 + /// + public class BondPaymentService : YLBaseService + { + private static IYcLogger Log = LogFactory.GetLogger(nameof(BondPaymentService)); + public BondPaymentService(OptUserInfo userInfo) : base(userInfo) + { + + } + + public SearchListResult SearchList(BondPaymentReq req) + { + var valueDtStart = req.ValueDateStart.Year > 2000 ? req.ValueDateStart : DateTime.Today.AddYears(-1); + var valueDtEnd = req.ValueDateEnd.Year > 2000 ? req.ValueDateEnd.AddDays(1) : DateTime.Today.AddYears(1); + + var predicatUn = PredicateBuilder.Create(d => d.LaunchState == "1"); + var predicatEoc = PredicateBuilder.Create(source => source.payment_date >= valueDtStart && source.payment_date < valueDtEnd); + + if (!string.IsNullOrEmpty(req.DataSource)) + { + predicatEoc = predicatEoc.And(d => d.channel_source.Contains(req.DataSource)); + } + if (!string.IsNullOrEmpty(req.MarketName)) + { + predicatUn = predicatUn.And(d => d.MarketName == req.MarketName); + } + if (!string.IsNullOrEmpty(req.UnderlyingCode)) + { + predicatEoc = predicatEoc.And(d => d.underlyingCode.Contains(req.UnderlyingCode)); + } + if (string.IsNullOrEmpty(req.sidx)) + { + req.sidx = "payment_date"; + req.sord = "desc"; + } + var queryUn = DbContext.underlying_manager.Where(predicatUn).Select(n => new { n.id, n.MarketName, n.UnderlyingCode, n.UnderlyingName, n.UnderlyingInstrumentType, n.InnerCode }); + var query = from un in queryUn + join source in DbContext.bondPayment.Where(predicatEoc) on un.UnderlyingCode equals source.underlyingCode + select new BondPaymentDto + { + id = source.id, + channel_source = source.channel_source, + MarketName = un.MarketName, + security_id = un.UnderlyingCode, + symbol = un.UnderlyingName, + coupon_rate = source.coupon_rate, + payment_date = source.payment_date, + payment_interest = source.payment_interest, + payment_parvalue = source.payment_parvalue, + create_time = source.create_time, + update_time = source.update_time + }; + var result = query.ToSearchList(req); + return result; + } + + public BondPayment SaveBondPayment(BondPayment req) + { + if (req is null) + { + throw new ArgumentNullException(nameof(req)); + } + BondPayment dbmodel; + + if (req.id == 0) + { + DbContext.bondPayment.Add(dbmodel = req); + } + else + { + dbmodel = DbContext.bondPayment.Find(req.id); + if (dbmodel == null) + { + throw new ServiceException("数据不存在"); + } + UpdateChanges(dbmodel, req); + } + dbmodel.update_time = DateTime.Now; + DbContext.SaveChanges(); + + return dbmodel; + } + /// + /// 获取某债券的期间付息情况集合 + /// + /// + /// + /// + /// + public List GetBondPayments(string underylingCode, DateTime startDate, DateTime endDate) + { + var result = DbContext.bondPayment.Where(x => x.underlyingCode == underylingCode && x.payment_date > startDate && x.payment_date <= endDate).AsNoTracking().ToList(); + return result; + } + /// + /// 计算某债券某段时间的期间付息 + /// + /// 债券代码 + /// 计息开始日 + /// 计息结束日 + /// 持仓数量 + /// 多空方向 + /// 收支方向 + /// + public decimal CalcPayment(string underylingCode, DateTime startDate, DateTime endDate, decimal qty, decimal longRatio, decimal payDirection) + { + var payments = GetBondPayments(underylingCode, startDate, endDate); + return CalcPayment(payments, qty, longRatio, payDirection); + } + /// + /// 计算某债券期间付息 + /// + /// 期间付息集合 + /// 持仓数量 + /// 多空方向 + /// 收支方向 + /// + public decimal CalcPayment(List payments, decimal qty, decimal longRatio, decimal payDirection) + { + var interest = payments.Sum(s => s.payment_interest ?? 0); + return interest * qty * 0.01m * longRatio * payDirection; + } + } + + /// + /// + /// + public class BondPaymentReq : BaseSearchReq + { + /// + /// 数据来源 + /// + public string DataSource { get; set; } + + /// + /// 标的代码 + /// + public string UnderlyingCode { get; set; } + + public DateTime ValueDateStart { get; set; } + + public DateTime ValueDateEnd { get; set; } + // 市场 + public string MarketName { get; set; } + } + public class BondPaymentDto : BondPayment + { + public string MarketName { get; set; } + } +} diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 33023148..ef693f9c 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -319,7 +319,7 @@ namespace YLErp.Modules.SwapModule var posiNotionalValue = stockEqvNotional * closePercent;//剩余名义本金 var grossPrice = realPostitions.Where(x => x.PosiDirection > 0).FirstOrDefault()?.PosiGrossPrice; bool tdClose = DbContext.swap_flow_event.Any(x => x.SwapTradeId == tradeId && x.UnwindDate == unwindDate && eventTypes.Contains(x.EventType) && x.DataState == (int)SwapFlowDateStateEnum.完成); - interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false, false); + interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false, false); return interests; } /// @@ -880,11 +880,17 @@ namespace YLErp.Modules.SwapModule floatEvent.TradingFeePending = position.PosiTradingFeePending * unwindData.ClosePercent; floatEvent.TradingFeePending = Math.Round(floatEvent.TradingFeePending, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingFee = closeFee; + BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); + var payments = bondPaymentService.GetBondPayments(floatEvent.UnderlyingCode, td.StartDate.Value, floatEvent.UnwindDate.Value); + floatEvent.DividendIn = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio); + floatEvent.DividendIn = Math.Round(floatEvent.DividendIn, 2, MidpointRounding.AwayFromZero); + floatEvent.DividendPending = bondPaymentService.CalcPayment(payments, floatEvent.PositionQty ?? 0, longRatio, floatRatio); + floatEvent.MarkClosePnl = (unwindPrice - position.PosiGrossPrice) * unwindQty * floatRatio * longRatio; - floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + ((floatEvent.TradingFeePending+ closeFee) * floatRatio * -1), ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + ((floatEvent.TradingFeePending+ closeFee) * floatRatio * -1) + floatEvent.DividendIn, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingAmount = unwindPrice * floatEvent.Quantity * floatEvent.ContractSize; floatEvent.TradingAmount = Math.Round(floatEvent.TradingAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - floatEvent.OptLog = "流水自动"; + floatEvent.OptLog = "流水自动"; floatEvent.ClientId = td.ClientId; floatEvent.SetOpt(UserInfo); } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index e18db806..b97a1562 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1142,6 +1142,13 @@ namespace YLErp.Modules.SwapModule int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp); + BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); + if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0 || valueDate == td.UnWindDate)) + { + curretEod.TdPosiDividend = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); + } + curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; + curretEod.PosiQuantity = eod.PosiQuantity; if (curretEod.PosiStatus == 1) { curretEod.PosiNotionalValue = 0; @@ -1149,8 +1156,8 @@ namespace YLErp.Modules.SwapModule curretEod.UnderlyingPrice = price; curretEod.UnderlyingMarketValue = curretEod.UnderlyingPrice * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio; curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio; - curretEod.TdPosiDividend = 0; - curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; + //curretEod.TdPosiDividend = 0; + //curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum+ curretEod.PosiFeePending; curretEod.TdCloseFee = 0; curretEod.TdCloseQty = 0; diff --git a/YLErpWeb/App_Data/FunctionRight.xml b/YLErpWeb/App_Data/FunctionRight.xml index 33f79ba4..348b101d 100644 --- a/YLErpWeb/App_Data/FunctionRight.xml +++ b/YLErpWeb/App_Data/FunctionRight.xml @@ -53,6 +53,8 @@ + + diff --git a/YLErpWeb/Common/UserInfoRight.cs b/YLErpWeb/Common/UserInfoRight.cs index eca83cde..ead15534 100644 --- a/YLErpWeb/Common/UserInfoRight.cs +++ b/YLErpWeb/Common/UserInfoRight.cs @@ -605,6 +605,8 @@ namespace YLErp.Web public bool 结算管理_日终价格查看 => HasRight("结算管理-日终价格查看"); + public bool 结算管理_债券付息数据查看 => HasRight("结算管理-债券付息数据查看"); + public bool 结算管理_日终价格修改 => HasRight("结算管理-日终价格修改"); public bool 结算管理_结算汇率查看 => HasRight("结算管理-结算汇率查看"); diff --git a/YLErpWeb/Controllers/BondPaymentController.cs b/YLErpWeb/Controllers/BondPaymentController.cs new file mode 100644 index 00000000..d0b08dbe --- /dev/null +++ b/YLErpWeb/Controllers/BondPaymentController.cs @@ -0,0 +1,94 @@ +using Org.BouncyCastle.Ocsp; +using YLErp.DBModels; +using YLErp.Modules.EodModule; + +namespace YLErp.Web.Controllers +{ + public class BondPaymentController : BaseController + { + readonly IViewRenderService _viewRenderer; + + public BondPaymentController(IViewRenderService viewRenderer) + { + _viewRenderer = viewRenderer; + } + + [MyAuthorize("结算管理-债券付息数据查看")] + public ActionResult BondPaymentList() + { + return View(); + } + + [HttpPost] + public JsonResult BondPaymentQuery(BondPaymentReq req) + { + var sList = new BondPaymentService(CurUser).SearchList(req); + return Json(sList); + } + + public ActionResult BondPaymentView(string enid) + { + var intid = DecryptLong(enid); + var r = yldb.bondPayment.Find(intid); + var um = yldb.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == r.underlyingCode); + r.symbol = um?.UnderlyingName; + r.security_id = um?.UnderlyingCode; + return View(r); + } + + public ActionResult BondPaymentEdit(string enid) + { + if (string.IsNullOrEmpty(enid) || enid == "0") + { + return View(new BondPayment()); + } + var intid = DecryptLong(enid); + var dbmodel = yldb.bondPayment.Find(intid); + if (dbmodel == null) + { + return ShowError("找不到数据"); + } + var um = yldb.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == dbmodel.security_id); + dbmodel.symbol = um?.UnderlyingName; + return View(dbmodel); + } + + public JsonResult BondPaymentEditJson(BondPayment req) + { + if (!string.IsNullOrEmpty(req.EncryptId)) + { + req.id = DecryptLong(req.EncryptId); + } + var r = new BondPaymentService(CurUser).SaveBondPayment(req); + + return JsonSuccess("更新成功", r); + } + + [HttpPost] + public JsonResult DeletBondPayment(string id) + { + var intid = DecryptLong(id); + var r = yldb.bondPayment.Find(intid); + if (r == null) + { + return JsonError("找不到债券期间付息信息"); + } + yldb.bondPayment.Remove(r); + yldb.SaveChanges(); + return JsonSuccess("删除成功"); + } + /// + /// 获取某债券期间付息 + /// + /// + /// + /// + /// + public JsonResult GetBondPayMentInterest(DateTime startDate, DateTime endDate, string underlyingCode) + { + var payments = new BondPaymentService(CurUser).GetBondPayments(underlyingCode, startDate, endDate); + decimal interest = payments.Sum(s => s.payment_interest ?? 0) * 0.01m; + return JsonSuccess("", interest); + } + } +} diff --git a/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml b/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml new file mode 100644 index 00000000..ce6e7b93 --- /dev/null +++ b/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml @@ -0,0 +1,57 @@ +@model BondPayment +@{ + ViewBag.Title = "ծȯڼ丶Ϣ | ༭"; + Layout = "~/Views/Shared/_InfoLayout.cshtml"; +} +@section JS +{ + +} +
+ + @Html.HiddenFor(model => model.id) + @Html.HiddenFor(model => model.jsid) + @Html.HiddenFor(model => model.coupon_rate) + @Html.HiddenFor(model => model.payment_parvalue) + @Html.HiddenFor(model => model.paying_price) + @Html.HiddenFor(model => model.channel_source) +

ծȯڼ丶Ϣ޸

+ +
+
+ + +
+
+ + +
+ @Html.MyDateFor(model => model.payment_date) + @Html.MyTextFor(model => model.payment_interest) +
+
+ + + +
+
\ No newline at end of file diff --git a/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml b/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml new file mode 100644 index 00000000..53d3737b --- /dev/null +++ b/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml @@ -0,0 +1,43 @@ +@{ + var DataSources = new List { "Դ", "˹" }; + ViewBag.Title = "ծȯڼ丶Ϣ"; + Layout = "~/Views/Shared/_InfoLayout.cshtml"; +} +@section CSS { + +} + +@section JS { + + +} + + + +
+ @Html.SearchDateRange("ValueDate", "֧") + @Html.MyAceDropdownInput2("DataSource", "Դ", GlobalData.GetSelectItems(DataSources)) + @Html.MyAceDropdownInput2("MarketName", "г", MarketController.GetAllmarketName()) + @Html.ShortInput("UnderlyingCode", "Ĵ") + @MyControls.SearchBtn() + @MyControls.Btn("", "downloadExcel()") +
+ +@Html.Raw(JqGridSimple.OutTable()) + diff --git a/YLErpWeb/Views/BondPayment/BondPaymentView.cshtml b/YLErpWeb/Views/BondPayment/BondPaymentView.cshtml new file mode 100644 index 00000000..0cbccab8 --- /dev/null +++ b/YLErpWeb/Views/BondPayment/BondPaymentView.cshtml @@ -0,0 +1,46 @@ +@model BondPayment +@{ + ViewBag.Title = "债券期间付息|查看"; + Layout = "~/Views/Shared/_InfoLayout.cshtml"; +} +@section JS { + +} + +
+ @if (CurUser.结算管理_日终价格修改) + { + @MyControls.Btn("修改", "window.location.href=('/BondPayment/BondPaymentEdit/?enid=" + Model.EncryptId + "');") + } + @MyControls.Btn("关闭", "layer.closeMe();") +
+ +
+ + @Html.MyDisplayFor(m => m.payment_date, Utilities.ShowValidDatetime(Model.payment_date)) + @Html.MyDisplayFor(m => m.security_id) + @Html.MyDisplayFor(m => m.symbol) + @Html.MyDisplayFor(m => m.payment_interest) + @Html.MyDisplayFor(m => m.update_time, Utilities.ShowValidDatetime(Model.update_time)) +
+
\ No newline at end of file diff --git a/YLErpWeb/Views/eod_trade_value/eodExecV2.cshtml b/YLErpWeb/Views/eod_trade_value/eodExecV2.cshtml index 5a827c72..9423c6cf 100644 --- a/YLErpWeb/Views/eod_trade_value/eodExecV2.cshtml +++ b/YLErpWeb/Views/eod_trade_value/eodExecV2.cshtml @@ -122,6 +122,11 @@ { 日终价格管理 } + @if (CurUser.结算管理_债券付息数据查看) + { + 债券付息数据 + } + @if (CurUser.结算管理_结算汇率查看) { 结算汇率设置 diff --git a/YLErpWeb/YLErpWeb.csproj b/YLErpWeb/YLErpWeb.csproj index b637f139..228d2de2 100644 --- a/YLErpWeb/YLErpWeb.csproj +++ b/YLErpWeb/YLErpWeb.csproj @@ -208,9 +208,15 @@ - + + + + + + + diff --git a/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js b/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js new file mode 100644 index 00000000..2b53d3c4 --- /dev/null +++ b/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js @@ -0,0 +1,89 @@ +$(function () { + $("#DateToValueDate").val(curdate) + $("#DateFromValueDate").val(curdate) + var PostData = { ValueDateEnd: curdate, ValueDateStart: curdate }; + $(".datepicker").datepicker({ changeMonth: true, changeYear: true, showButtonPanel: true, showOtherMonths: true, selectOtherMonths: true }); + var grid = jQuery('#listGrid').jqGrid({ + url: '/BondPayment/BondPaymentQuery', + datatype: 'json', + height: 'auto', + width: '100%', + autowidth: false, + shrinkToFit: false, + viewrecords: true, + jsonReader: { repeatitems: false }, + cmTemplate: { align: 'center', width: 120 }, + mtype: 'POST', + postData: PostData, + colModel: colModelGrid, + pager: jQuery('#pagerGrid'), + pagerpos: 'left', + rowNum: 20, + rowList: [20, 30, 50, 200, 10000], + footerrow: false + }); + function keyEnter(event) { + try { + var e = event ? event : (window.event ? window.event : null); + (e.keyCode == 13) && SearchClick(true); + } catch (e) { } + } + document.onkeydown = keyEnter; +}); + +var colModelGrid = [{ + name: '', label: '操作', index: '', width: 120, formatter: showToolName +}, { + name: 'payment_date', label: '支付日期', index: 'ValueDate', width: 120, formatter: 'date' +}, { + name: 'MarketName', label: '市场', index: 'MarketName', width: 200 +}, { + name: 'security_id', label: '债券代码', index: 'security_id', width: 150 +}, { + name: 'symbol', label: '债券名称', index: 'symbol', width: 200 +}, { + name: 'payment_interest', label: '支付利息', index: 'payment_interest', width: 100 +}, +{ + name: 'update_time', label: '更新时间', index: 'update_time', width: 160, formatter: 'datetime' +}, { + name: 'channel_source', label: '数据来源', index: 'channel_source', sortable: false, width: 120 +}]; + +function showToolName(cellValue, options, rowObject) { + return "".template(rowObject.EncryptId, "查看"); +} + +function startView(id) { + var srcurl = "/BondPayment/BondPaymentView/?enid=" + id; + main.open("查看债券期间付息", srcurl, { area: ['800px', '600px'] }); +} + +function SearchClick(isSearchclick) { + var listGrid = $('#listGrid'); + listGrid.appendPostData({ UnderlyingCode: $("#UnderlyingCode").val() }); + listGrid.appendPostData({ MarketName: $("#MarketName").val() }); + listGrid.appendPostData({ ValueDateStart: $("#DateFromValueDate").val() }); + listGrid.appendPostData({ ValueDateEnd: $("#DateToValueDate").val() }); + listGrid.appendPostData({ DataSource: $("#DataSource").val() }); + if (isSearchclick) { + //点击搜索时默认第一页 + listGrid.jqGrid('setGridParam', { page: 1 }); + } + listGrid.trigger('reloadGrid'); +} + + +function reloadData() { + SearchClick(false); +} + +function downloadExcel() { + var dateTemp = new Date().Format("yyyyMMdd"); + var fileName = "债券期间付息" + dateTemp; + var formatters = _.map(['市场', '债券代码', '债券名称', '支付利息'] + , x => new Object({ colName: x, formatter: "text" })); + formatters.push(_.map(['支付日期', '更新时间'] + , x => new Object({ colName: x, formatter: "datetime" }))); + main.toExcel("listGrid", fileName, "xls", null, "操作", formatters) +} \ No newline at end of file diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js index 50afd3f3..1eff09c5 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js @@ -262,6 +262,20 @@ const vue = new Vue({ }); thisObj.calcCloseAmount(); thisObj.dataFormat(); + thisObj.getDivindIn(); + }); + }, + getDivindIn() { + var thisObj = this; + let ratio = this.floatPosition.PositionType == 1 ? 1 : -1; + let floatRatio = this.floatPosition.PayDirection == 1 ? 1 : -1; + var postData = { startDate: thisObj.floatPosition.PosiStartDate, endDate: thisObj.deal.UnwindDate, underlyingCode: thisObj.floatPosition.UnderlyingCode } + main.post("/BondPayment/GetBondPayMentInterest", postData, { async: false }).done(function (resp) { + thisObj.floatPosition.DividendIn = parseFloat(thisObj.deal.CloseQty) * resp.obj * ratio * floatRatio; + var posiQty = parseFloat(thisObj.floatPosition.Quantity) - parseFloat(thisObj.deal.CloseQty); + thisObj.floatPosition.DividendPending = posiQty * resp.obj * ratio * floatRatio; + thisObj.calcFloatClosePnl(); + thisObj.dataFormat(); }); }, closeTrade() {//平仓 From 652334925d1482b72b9ce419fab258e88f48ae56 Mon Sep 17 00:00:00 2001 From: gongpei Date: Tue, 21 Oct 2025 16:44:21 +0800 Subject: [PATCH 02/13] =?UTF-8?q?fix:=20=E4=BC=B0=E5=80=BC=E8=A1=A8?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6=E5=90=8D=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SettlementReportFotShanXiService.cs | 2 +- .../Views/BondPayment/BondPaymentEdit.cshtml | 14 +++++++------- .../Views/BondPayment/BondPaymentList.cshtml | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs b/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs index 5517fc74..6a129faf 100644 --- a/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs +++ b/YLErpDAL/Modules/ReportModule/SettlementReportModule/SettlementReportFotShanXiService.cs @@ -205,7 +205,7 @@ namespace YLErp.Modules.ReportModule.SettlementReportModule Directory.CreateDirectory(targetPath); } var clientName = report.client.Name; - var fileName = report.ReportFrom == DateTime.MinValue ? $"估值表_{report.ReportEnd:yyyyMMdd}_{clientName}" : $"估值表_{report.ReportFrom:yyyyMMdd}_{report.ReportEnd:yyyyMMdd}_{clientName}"; + var fileName = report.ReportFrom == DateTime.MinValue ? $"浙商证券_估值表_{report.ReportEnd:yyyyMMdd}_{clientName}" : $"浙商证券_估值表_{report.ReportFrom:yyyyMMdd}_{report.ReportEnd:yyyyMMdd}_{clientName}"; var targetFileName = Path.Combine(targetPath, $"{fileName}.xlsx"); var excelDeclareModel = new ExcelDeclareModel() diff --git a/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml b/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml index ce6e7b93..d631980d 100644 --- a/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml +++ b/YLErpWeb/Views/BondPayment/BondPaymentEdit.cshtml @@ -1,6 +1,6 @@ -@model BondPayment +@model BondPayment @{ - ViewBag.Title = "ծȯڼ丶Ϣ | ༭"; + ViewBag.Title = "债券期间付息 | 编辑"; Layout = "~/Views/Shared/_InfoLayout.cshtml"; } @section JS @@ -35,23 +35,23 @@ @Html.HiddenFor(model => model.payment_parvalue) @Html.HiddenFor(model => model.paying_price) @Html.HiddenFor(model => model.channel_source) -

ծȯڼ丶Ϣ޸

+

债券期间付息修改

- +
- +
@Html.MyDateFor(model => model.payment_date) @Html.MyTextFor(model => model.payment_interest)
- - + +
\ No newline at end of file diff --git a/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml b/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml index 53d3737b..9d642daf 100644 --- a/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml +++ b/YLErpWeb/Views/BondPayment/BondPaymentList.cshtml @@ -1,6 +1,6 @@ -@{ - var DataSources = new List { "Դ", "˹" }; - ViewBag.Title = "ծȯڼ丶Ϣ"; +@{ + var DataSources = new List { "聚源", "人工" }; + ViewBag.Title = "债券期间付息管理"; Layout = "~/Views/Shared/_InfoLayout.cshtml"; } @section CSS { @@ -31,12 +31,12 @@
- @Html.SearchDateRange("ValueDate", "֧") - @Html.MyAceDropdownInput2("DataSource", "Դ", GlobalData.GetSelectItems(DataSources)) - @Html.MyAceDropdownInput2("MarketName", "г", MarketController.GetAllmarketName()) - @Html.ShortInput("UnderlyingCode", "Ĵ") + @Html.SearchDateRange("ValueDate", "支付日期") + @Html.MyAceDropdownInput2("DataSource", "数据来源", GlobalData.GetSelectItems(DataSources)) + @Html.MyAceDropdownInput2("MarketName", "市场", MarketController.GetAllmarketName()) + @Html.ShortInput("UnderlyingCode", "标的代码") @MyControls.SearchBtn() - @MyControls.Btn("", "downloadExcel()") + @MyControls.Btn("导出", "downloadExcel()")
@Html.Raw(JqGridSimple.OutTable()) From 80a2b4057d11dd73976fb50ead9935b0f975d2c0 Mon Sep 17 00:00:00 2001 From: gongpei Date: Wed, 22 Oct 2025 16:14:32 +0800 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20=E8=AE=A1=E7=AE=97=E6=B5=AE?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E5=B9=B3=E4=BB=93=E7=9B=88=E4=BA=8F=E5=88=86?= =?UTF-8?q?=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YLErp.Core/DBModels/underlying_manager.cs | 6 ++++++ YLErpDAL/Modules/SwapModule/SwapDealService.cs | 15 ++++++++++++++- .../Modules/SwapModule/SwapEodPositionService.cs | 13 +++++++++++-- .../Scripts/app/bondPayment/bondpaymentList.js | 2 +- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Framework/YLErp.Core/DBModels/underlying_manager.cs b/Framework/YLErp.Core/DBModels/underlying_manager.cs index 89fea84e..5edecdac 100644 --- a/Framework/YLErp.Core/DBModels/underlying_manager.cs +++ b/Framework/YLErp.Core/DBModels/underlying_manager.cs @@ -322,6 +322,12 @@ namespace YLErp.DBModels ///
public long? InnerCode { get; set; } + /// + /// 债券增值税 + /// + [Column("value_added_tax")] + public decimal? ValueAddedTax { get; set; } + public override string ToString() { return $"{UnderlyingCode}--{UnderlyingName}--{id}--{UnderlyingInstrumentType}"; diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index ef693f9c..28689a31 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -881,8 +881,10 @@ namespace YLErp.Modules.SwapModule floatEvent.TradingFeePending = Math.Round(floatEvent.TradingFeePending, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingFee = closeFee; BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); + var tax = GetUnderlyingTax(floatEvent.UnderlyingCode); var payments = bondPaymentService.GetBondPayments(floatEvent.UnderlyingCode, td.StartDate.Value, floatEvent.UnwindDate.Value); - floatEvent.DividendIn = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio); + var payment = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio); + floatEvent.DividendIn = payment / (1 + tax) * (1 - tax); floatEvent.DividendIn = Math.Round(floatEvent.DividendIn, 2, MidpointRounding.AwayFromZero); floatEvent.DividendPending = bondPaymentService.CalcPayment(payments, floatEvent.PositionQty ?? 0, longRatio, floatRatio); @@ -910,6 +912,17 @@ namespace YLErp.Modules.SwapModule CalcCloseAmount(unwindData); DealUnwind(unwindData, td); } + + public decimal GetUnderlyingTax(string code) + { + var data = DataCacheProvider.GetUnderlyingDataSource().GetData(code); + if (data == null) + { + return 0; + } + return data.ValueAddedTax ?? 0; + } + /// /// 衡泰新增平仓事件 /// diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index b97a1562..6e94cba2 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1142,10 +1142,13 @@ namespace YLErp.Modules.SwapModule int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp); + decimal tax = um.ValueAddedTax ?? 0; BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0 || valueDate == td.UnWindDate)) { - curretEod.TdPosiDividend = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); + decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); + // 考虑增值税 + curretEod.TdPosiDividend = payment / (1 - tax) * (1 + tax); } curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; curretEod.PosiQuantity = eod.PosiQuantity; @@ -1162,6 +1165,7 @@ namespace YLErp.Modules.SwapModule curretEod.TdCloseFee = 0; curretEod.TdCloseQty = 0; curretEod.TdCloseMtmPnl = 0; + // 需要计算平仓盈亏分红 curretEod.TdCloseDividend = 0; curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; @@ -1204,6 +1208,7 @@ namespace YLErp.Modules.SwapModule if (curretEod == null) { curretEod = eod.Clone(); + curretEod.TdPosiDividend = 0; curretEod.id = 0; curretEod.ValueDate = valueDate; } @@ -1224,10 +1229,14 @@ namespace YLErp.Modules.SwapModule curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; - curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; + //curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee; curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; + var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity); + // 等于 平仓数量/昨天剩余平仓数量 * 昨日浮动端分红 + curretEod.TdCloseDividend = closeQty / eod.PosiQuantity * eod.TdPosiDividend; + curretEod.RealizedDividend = curretEod.RealizedDividend + curretEod.TdCloseDividend; if (curretEod.PosiStatus == 1) { curretEod.PosiNotionalValue = 0; diff --git a/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js b/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js index 2b53d3c4..e51e522b 100644 --- a/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js +++ b/YLErpWeb/wwwroot/Scripts/app/bondPayment/bondpaymentList.js @@ -34,7 +34,7 @@ var colModelGrid = [{ name: '', label: '操作', index: '', width: 120, formatter: showToolName }, { - name: 'payment_date', label: '支付日期', index: 'ValueDate', width: 120, formatter: 'date' + name: 'payment_date', label: '支付日期', index: 'payment_date', width: 120, formatter: 'date' }, { name: 'MarketName', label: '市场', index: 'MarketName', width: 200 }, { From f228d9be1b5c8e78199126ae864c782ccc6ee64d Mon Sep 17 00:00:00 2001 From: gongpei Date: Wed, 22 Oct 2025 16:14:32 +0800 Subject: [PATCH 04/13] =?UTF-8?q?fix:=20=E8=AE=A1=E7=AE=97=E6=B5=AE?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E5=B9=B3=E4=BB=93=E7=9B=88=E4=BA=8F=E5=88=86?= =?UTF-8?q?=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 6e94cba2..3fb1e355 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1226,6 +1226,13 @@ namespace YLErp.Modules.SwapModule curretEod.UnderlyingPrice = price; curretEod.UnderlyingMarketValue = curretEod.UnderlyingPrice * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio; curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio; + + decimal tax = um.ValueAddedTax ?? 0; + BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); + decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); + // 考虑增值税 + curretEod.TdPosiDividend = payment / (1 - tax) * (1 + tax); + curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; From 936bed21f8b189df0d399090717206fd8c3d4814 Mon Sep 17 00:00:00 2001 From: gongpei Date: Wed, 22 Oct 2025 16:14:32 +0800 Subject: [PATCH 05/13] =?UTF-8?q?fix:=20=E8=AE=A1=E7=AE=97=E6=B5=AE?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E5=B9=B3=E4=BB=93=E7=9B=88=E4=BA=8F=E5=88=86?= =?UTF-8?q?=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/SwapModule/SwapEodPositionService.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 3fb1e355..b7428b63 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1232,18 +1232,20 @@ namespace YLErp.Modules.SwapModule decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); // 考虑增值税 curretEod.TdPosiDividend = payment / (1 - tax) * (1 + tax); - - curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; - curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; - //curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; + curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee; curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; - var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity); - // 等于 平仓数量/昨天剩余平仓数量 * 昨日浮动端分红 - curretEod.TdCloseDividend = closeQty / eod.PosiQuantity * eod.TdPosiDividend; + var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity); + // 当日浮动端平仓盈亏·分红 = 平仓数量/昨天剩余平仓数量 * 昨日浮动端待实现收益·分红 + curretEod.TdCloseDividend = closeQty / eod.PosiQuantity * eod.PosiDividendSum; curretEod.RealizedDividend = curretEod.RealizedDividend + curretEod.TdCloseDividend; + + // 浮动端待实现收益·分红 = 昨日 + 当日浮动端分红 - 当日浮动端平仓盈亏·分红 + curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend - curretEod.TdCloseDividend; + curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; + curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; if (curretEod.PosiStatus == 1) { curretEod.PosiNotionalValue = 0; From 866f13d85e721376570a2df2dbfa1ce4a7f0aea5 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 15:25:47 +0800 Subject: [PATCH 06/13] =?UTF-8?q?fix:=20=E6=89=8B=E5=8A=A8=E5=B9=B3?= =?UTF-8?q?=E4=BB=93=E5=88=86=E7=BA=A2=E6=94=B6=E7=9B=8A=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Framework/YLErp.Core/DBModels/SwapEvent.cs | 3 +++ .../YLErp.Core/DBModels/underlying_manager.cs | 1 + YLErpDAL/Modules/EodModule/BondPaymentService.cs | 16 ++++++++++++---- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 11 +++++++---- .../underlying_managerEdit.cshtml | 4 ++++ .../underlying_managerView.cshtml | 5 +++++ .../Scripts/app/swaptrade/unwindSwapTrade.js | 3 ++- 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Framework/YLErp.Core/DBModels/SwapEvent.cs b/Framework/YLErp.Core/DBModels/SwapEvent.cs index 4b0af775..311c25d1 100644 --- a/Framework/YLErp.Core/DBModels/SwapEvent.cs +++ b/Framework/YLErp.Core/DBModels/SwapEvent.cs @@ -183,5 +183,8 @@ namespace YLErp.DBModels /// 支付日 /// public DateTime? PayDate { get; set; } + + [NotMapped] + public DateTime? TradeStartDate { get; set; } } } diff --git a/Framework/YLErp.Core/DBModels/underlying_manager.cs b/Framework/YLErp.Core/DBModels/underlying_manager.cs index 5edecdac..38138af3 100644 --- a/Framework/YLErp.Core/DBModels/underlying_manager.cs +++ b/Framework/YLErp.Core/DBModels/underlying_manager.cs @@ -326,6 +326,7 @@ namespace YLErp.DBModels /// 债券增值税 /// [Column("value_added_tax")] + [DisplayName("增值税率")] public decimal? ValueAddedTax { get; set; } public override string ToString() diff --git a/YLErpDAL/Modules/EodModule/BondPaymentService.cs b/YLErpDAL/Modules/EodModule/BondPaymentService.cs index 05f5a1cf..eda780f8 100644 --- a/YLErpDAL/Modules/EodModule/BondPaymentService.cs +++ b/YLErpDAL/Modules/EodModule/BondPaymentService.cs @@ -96,11 +96,19 @@ namespace YLErp.Modules.EodModule /// /// /// - public List GetBondPayments(string underylingCode, DateTime startDate, DateTime endDate) + public List GetBondPayments(string underlyingCode, DateTime startDate, DateTime endDate) { - var result = DbContext.bondPayment.Where(x => x.underlyingCode == underylingCode && x.payment_date > startDate && x.payment_date <= endDate).AsNoTracking().ToList(); + var result = DbContext.bondPayment.Where(x => x.underlyingCode == underlyingCode && x.payment_date > startDate && x.payment_date <= endDate).AsNoTracking().ToList(); return result; } + + + public List GetTargetDatePayments(string underlyingCode, DateTime targetDate) + { + var startDate = targetDate.Date; + var endDate = startDate.AddDays(1); + return DbContext.bondPayment.AsNoTracking().Where(x => x.underlyingCode == underlyingCode && x.payment_date >= startDate && x.payment_date < endDate).ToList(); + } /// /// 计算某债券某段时间的期间付息 /// @@ -111,9 +119,9 @@ namespace YLErp.Modules.EodModule /// 多空方向 /// 收支方向 /// - public decimal CalcPayment(string underylingCode, DateTime startDate, DateTime endDate, decimal qty, decimal longRatio, decimal payDirection) + public decimal CalcPayment(string underlyingCode, DateTime startDate, DateTime endDate, decimal qty, decimal longRatio, decimal payDirection) { - var payments = GetBondPayments(underylingCode, startDate, endDate); + var payments = GetBondPayments(underlyingCode, startDate, endDate); return CalcPayment(payments, qty, longRatio, payDirection); } /// diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 28689a31..19775965 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -71,6 +71,7 @@ namespace YLErp.Modules.SwapModule } else { + unwindData.TradeStartDate = td.StartDate; unwindData.CloseType = commodity ? 1 : 2; unwindData.StartDate = td.TradeDate.Value; if (preDealDate.HasValue) @@ -880,13 +881,15 @@ namespace YLErp.Modules.SwapModule floatEvent.TradingFeePending = position.PosiTradingFeePending * unwindData.ClosePercent; floatEvent.TradingFeePending = Math.Round(floatEvent.TradingFeePending, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingFee = closeFee; + BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); var tax = GetUnderlyingTax(floatEvent.UnderlyingCode); - var payments = bondPaymentService.GetBondPayments(floatEvent.UnderlyingCode, td.StartDate.Value, floatEvent.UnwindDate.Value); - var payment = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio); - floatEvent.DividendIn = payment / (1 + tax) * (1 - tax); + // 只计算事件日期当天的分红收益 + var payments = bondPaymentService.GetTargetDatePayments(floatEvent.UnderlyingCode, floatEvent.EventDate); + floatEvent.DividendIn = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio) / (1 + tax) * (1 - tax); floatEvent.DividendIn = Math.Round(floatEvent.DividendIn, 2, MidpointRounding.AwayFromZero); - floatEvent.DividendPending = bondPaymentService.CalcPayment(payments, floatEvent.PositionQty ?? 0, longRatio, floatRatio); + floatEvent.DividendPending = bondPaymentService.CalcPayment(payments, floatEvent.PositionQty ?? 0, longRatio, floatRatio) / (1 + tax) * (1 - tax); + floatEvent.MarkClosePnl = (unwindPrice - position.PosiGrossPrice) * unwindQty * floatRatio * longRatio; floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + ((floatEvent.TradingFeePending+ closeFee) * floatRatio * -1) + floatEvent.DividendIn, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); diff --git a/YLErpWeb/Views/underlying_manager/underlying_managerEdit.cshtml b/YLErpWeb/Views/underlying_manager/underlying_managerEdit.cshtml index e1280475..db4e13a7 100644 --- a/YLErpWeb/Views/underlying_manager/underlying_managerEdit.cshtml +++ b/YLErpWeb/Views/underlying_manager/underlying_managerEdit.cshtml @@ -308,6 +308,10 @@ +
+ + +
diff --git a/YLErpWeb/Views/underlying_manager/underlying_managerView.cshtml b/YLErpWeb/Views/underlying_manager/underlying_managerView.cshtml index 07953c86..f22e7837 100644 --- a/YLErpWeb/Views/underlying_manager/underlying_managerView.cshtml +++ b/YLErpWeb/Views/underlying_manager/underlying_managerView.cshtml @@ -170,6 +170,11 @@ @Html.MyDisplayFor(m => m.Price) } + + + 增值税率 + @(Model.ValueAddedTax.OtcFormatPercent()) +
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js index 1eff09c5..fe235911 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js @@ -51,6 +51,7 @@ const vue = new Vue({ }); this.ratio = this.floatPosition.PayDirection == 1 ? -1 : 1; this.shortRatio = this.floatPosition.PositionType == 1 ? 1 : -1; + this.TradeStartDate = model.TradeStartDate; }, IsBond(instType) { return tradeHelper.IsBond(instType); @@ -269,7 +270,7 @@ const vue = new Vue({ var thisObj = this; let ratio = this.floatPosition.PositionType == 1 ? 1 : -1; let floatRatio = this.floatPosition.PayDirection == 1 ? 1 : -1; - var postData = { startDate: thisObj.floatPosition.PosiStartDate, endDate: thisObj.deal.UnwindDate, underlyingCode: thisObj.floatPosition.UnderlyingCode } + var postData = { startDate: thisObj.TradeStartDate, endDate: thisObj.deal.UnwindDate, underlyingCode: thisObj.floatPosition.UnderlyingCode } main.post("/BondPayment/GetBondPayMentInterest", postData, { async: false }).done(function (resp) { thisObj.floatPosition.DividendIn = parseFloat(thisObj.deal.CloseQty) * resp.obj * ratio * floatRatio; var posiQty = parseFloat(thisObj.floatPosition.Quantity) - parseFloat(thisObj.deal.CloseQty); From f5463e4a5742ae5cc473027b5bb4e1263927b549 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 17:10:05 +0800 Subject: [PATCH 07/13] =?UTF-8?q?fix:=20=E6=B5=81=E6=B0=B4=E7=9A=84?= =?UTF-8?q?=E5=88=86=E7=BA=A2=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Framework/YLErp.Core/DBModels/BondPayment.cs | 1 + .../Modules/SwapModule/SwapDealService.cs | 47 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Framework/YLErp.Core/DBModels/BondPayment.cs b/Framework/YLErp.Core/DBModels/BondPayment.cs index bcf23d60..94056c19 100644 --- a/Framework/YLErp.Core/DBModels/BondPayment.cs +++ b/Framework/YLErp.Core/DBModels/BondPayment.cs @@ -102,6 +102,7 @@ namespace YLErp.DBModels /// /// 更新时间 /// + [DisplayName("更新时间")] [Column("update_time")] public DateTime update_time { get; set; } } diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 19775965..3d3d0e9b 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -9,6 +9,7 @@ using OfficeOpenXml.Drawing.Controls; using Org.BouncyCastle.Asn1.Ocsp; using Qdp.Pricing.Base.Implementations; using Qdp.Pricing.Core.Modules; +using Qdp.Pricing.Library.Base.Utilities; using System.Linq.Expressions; using YLErp.BLL; using YLErp.BLL.Eod; @@ -320,7 +321,7 @@ namespace YLErp.Modules.SwapModule var posiNotionalValue = stockEqvNotional * closePercent;//剩余名义本金 var grossPrice = realPostitions.Where(x => x.PosiDirection > 0).FirstOrDefault()?.PosiGrossPrice; bool tdClose = DbContext.swap_flow_event.Any(x => x.SwapTradeId == tradeId && x.UnwindDate == unwindDate && eventTypes.Contains(x.EventType) && x.DataState == (int)SwapFlowDateStateEnum.完成); - interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false, false); + interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false, false); return interests; } /// @@ -401,7 +402,7 @@ namespace YLErp.Modules.SwapModule } else if (position.InterestMode == (int)InterestModeEnum.标的期初全价) { - _closePosiNotionalValue = _posiNotionalValue * closePrecent; + _closePosiNotionalValue = _posiNotionalValue * closePrecent; _posiNotionalValue = _posiNotionalValue; } else if (position.InterestMode == (int)InterestModeEnum.追加预付金 || position.InterestMode == (int)InterestModeEnum.初始预付金) @@ -434,7 +435,7 @@ namespace YLErp.Modules.SwapModule position.FloatRate = Convert.ToDecimal(floatRate); positionClone.FloatRate = position.FloatRate; } - else if(!swap) + else if (!swap) { throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{rateDate:yyyy年MM月dd日}的价格"); } @@ -770,7 +771,7 @@ namespace YLErp.Modules.SwapModule DealFloatPosition(unwindData); var flowList = new List(unwindData.FlowEvents); var eventId = SaveSwapDeal(unwindData, (int)SwapEventTypeEnum.平仓, clientCashId, "系统操作_平仓"); - if (unwindData.CloseMethod == (int)CloseMethodEnum.全部平仓|| unwindData.ClosePercent==1) + if (unwindData.CloseMethod == (int)CloseMethodEnum.全部平仓 || unwindData.ClosePercent == 1) { td.TradeStatus = "已平仓"; td.trade_extend = DbContext.trade_extend.FirstOrDefault(x => x.TradeId == td.id); @@ -813,7 +814,7 @@ namespace YLErp.Modules.SwapModule /// /// /// - public void AuotoSwapUnwind(int tradeid, decimal unwindPrice, decimal unwindPriceFee, decimal unwindNetFee, decimal unwindNet, DateTime valueDate, decimal unwindQty,decimal closeFee) + public void AuotoSwapUnwind(int tradeid, decimal unwindPrice, decimal unwindPriceFee, decimal unwindNetFee, decimal unwindNet, DateTime valueDate, decimal unwindQty, decimal closeFee) { unwindPriceFee = decimal.Parse(unwindPriceFee.ToString("F10")); var td = DbContext.trade.Find(tradeid); @@ -851,7 +852,7 @@ namespace YLErp.Modules.SwapModule unwindData.CloseMethod = unwindQty == unwindData.PositionQty ? (int)CloseMethodEnum.全部平仓 : (int)CloseMethodEnum.部分平仓; unwindData.ClosePercent = unwindData.PositionQty == 0 ? 0 : unwindPercent; unwindData.CloseNotionalValue = position == null ? 0 : unwindQty * position.PosiGrossPrice * position.ContractSize; - unwindData.CloseNotionalValue = unwindPercent >= 1? unwindData.PosiNotionalValue: Math.Round(unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + unwindData.CloseNotionalValue = unwindPercent >= 1 ? unwindData.PosiNotionalValue : Math.Round(unwindData.CloseNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); unwindData.CloseQty = unwindQty; if (position != null) { @@ -881,23 +882,14 @@ namespace YLErp.Modules.SwapModule floatEvent.TradingFeePending = position.PosiTradingFeePending * unwindData.ClosePercent; floatEvent.TradingFeePending = Math.Round(floatEvent.TradingFeePending, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingFee = closeFee; - - BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); - var tax = GetUnderlyingTax(floatEvent.UnderlyingCode); - // 只计算事件日期当天的分红收益 - var payments = bondPaymentService.GetTargetDatePayments(floatEvent.UnderlyingCode, floatEvent.EventDate); - floatEvent.DividendIn = bondPaymentService.CalcPayment(payments, unwindQty, longRatio, floatRatio) / (1 + tax) * (1 - tax); - floatEvent.DividendIn = Math.Round(floatEvent.DividendIn, 2, MidpointRounding.AwayFromZero); - floatEvent.DividendPending = bondPaymentService.CalcPayment(payments, floatEvent.PositionQty ?? 0, longRatio, floatRatio) / (1 + tax) * (1 - tax); - - floatEvent.MarkClosePnl = (unwindPrice - position.PosiGrossPrice) * unwindQty * floatRatio * longRatio; - floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + ((floatEvent.TradingFeePending+ closeFee) * floatRatio * -1) + floatEvent.DividendIn, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + floatEvent.MarkClosePnl = Math.Round(floatEvent.MarkClosePnl + ((floatEvent.TradingFeePending + closeFee) * floatRatio * -1) + floatEvent.DividendIn, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.TradingAmount = unwindPrice * floatEvent.Quantity * floatEvent.ContractSize; floatEvent.TradingAmount = Math.Round(floatEvent.TradingAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); floatEvent.OptLog = "流水自动"; floatEvent.ClientId = td.ClientId; floatEvent.SetOpt(UserInfo); + EnrichDividendIn(floatEvent, unwindQty); } unwindData.FlowEvents.Add(floatEvent); var interestPositions = GetUnwindInterests(unwindData.ValueDate, unwindData.UnwindDate.Value, td.id, unwindPercent, (int)SwapEventTypeEnum.平仓); @@ -907,8 +899,8 @@ namespace YLErp.Modules.SwapModule }); foreach (var item in interestPositions) { - item.TdInterestAmount=Math.Round(item.TdInterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); - item.InterestAmount=Math.Round(item.InterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + item.TdInterestAmount = Math.Round(item.TdInterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + item.InterestAmount = Math.Round(item.InterestAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); item.InterestClosePnL = Math.Round(item.InterestClosePnL, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); } unwindData.FlowEvents.AddRange(interestPositions); @@ -916,6 +908,15 @@ namespace YLErp.Modules.SwapModule DealUnwind(unwindData, td); } + private void EnrichDividendIn(swap_flow_event flowEvent, decimal unwindQty) + { + // 平仓数量/平仓前的数量*平仓对象的待实现分红收益,保留2位小数 + var yest = QdpCalendarHelper.GetNonHolidayDefore(flowEvent.EventDate.AddDays(-1)); + var eod = DbContext.eod_swap_position.Where(e => e.SwapTradeId == flowEvent.SwapTradeId && !e.Invalid && e.PosiQuantity > 0 && e.ValueDate == yest).FirstOrDefault(); + var dividendIn = eod.PosiProfitSum * unwindQty / eod.PosiQuantity; + flowEvent.DividendIn = Math.Round(dividendIn, 2, MidpointRounding.AwayFromZero); + } + public decimal GetUnderlyingTax(string code) { var data = DataCacheProvider.GetUnderlyingDataSource().GetData(code); @@ -1073,7 +1074,7 @@ namespace YLErp.Modules.SwapModule return interests; } - private void DealUnwind(UnwindData unwindData, trade td, string actionMsg = "系统操作_自动平仓") + private void DealUnwind(UnwindData unwindData, trade td, string actionMsg = "系统操作_自动平仓") { int clientCashId = AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapRealizedPnL), ClientCashInCashOut.系统操作_平仓费, unwindData.ValueDate); if (unwindData.SwapMarginAmount != 0) @@ -1104,7 +1105,7 @@ namespace YLErp.Modules.SwapModule td.TradeAmount -= Convert.ToDouble(unwindData.CloseQty); td.Notional = td.TradeAmount; td.OptDate = DateTime.Now; - td.OptId= UserId; + td.OptId = UserId; td.OptName = UserName; DbContext.SaveChanges(); } @@ -1384,7 +1385,7 @@ namespace YLErp.Modules.SwapModule decimal shortRatio = item.PositionType == (int)PositionTypeFlag.Long ? -1m : 1m; item.TradingAmountFeeAvg = item.TradingAmountAvg + item.TradingFeePending / unwindData.CloseQty * shortRatio; item.TradingAmountNetFeeAvg = item.TradingAmountNetAvg + item.TradingFeePending / unwindData.CloseQty * shortRatio; - item.TradingAmount= item.TradingAmountAvg * unwindData.CloseQty; + item.TradingAmount = item.TradingAmountAvg * unwindData.CloseQty; } } } @@ -1400,7 +1401,7 @@ namespace YLErp.Modules.SwapModule if (!string.IsNullOrEmpty(position.UnderlyingCode)) { position.PosiQuantity -= unwindData.CloseQty; - position.PosiNotionalValue = unwindData.PosiNotionalValue- unwindData.CloseNotionalValue; + position.PosiNotionalValue = unwindData.PosiNotionalValue - unwindData.CloseNotionalValue; position.PosiTradingFee -= position.PosiTradingFee * unwindData.ClosePercent; position.PosiTradingFeePending -= position.PosiTradingFeePending * unwindData.ClosePercent; } From 8b8eb19ddca45964b81f8e7a7dbbf7e622c464c7 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 17:30:50 +0800 Subject: [PATCH 08/13] =?UTF-8?q?fix:=20=E6=B5=AE=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E5=BE=85=E5=AE=9E=E7=8E=B0=E6=94=B6=E7=9B=8A=E5=88=86=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 3d3d0e9b..23490925 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -913,7 +913,7 @@ namespace YLErp.Modules.SwapModule // 平仓数量/平仓前的数量*平仓对象的待实现分红收益,保留2位小数 var yest = QdpCalendarHelper.GetNonHolidayDefore(flowEvent.EventDate.AddDays(-1)); var eod = DbContext.eod_swap_position.Where(e => e.SwapTradeId == flowEvent.SwapTradeId && !e.Invalid && e.PosiQuantity > 0 && e.ValueDate == yest).FirstOrDefault(); - var dividendIn = eod.PosiProfitSum * unwindQty / eod.PosiQuantity; + var dividendIn = eod.PosiDividendSum * unwindQty / eod.PosiQuantity; flowEvent.DividendIn = Math.Round(dividendIn, 2, MidpointRounding.AwayFromZero); } From 5ee62775b73db30c4467e90f3ac7e17afb5bc6c1 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 18:58:26 +0800 Subject: [PATCH 09/13] =?UTF-8?q?fix:=20=E8=AE=A1=E7=AE=97=E5=B9=B3?= =?UTF-8?q?=E4=BB=93=E5=88=86=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 23490925..09862168 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -910,10 +910,21 @@ namespace YLErp.Modules.SwapModule private void EnrichDividendIn(swap_flow_event flowEvent, decimal unwindQty) { - // 平仓数量/平仓前的数量*平仓对象的待实现分红收益,保留2位小数 - var yest = QdpCalendarHelper.GetNonHolidayDefore(flowEvent.EventDate.AddDays(-1)); - var eod = DbContext.eod_swap_position.Where(e => e.SwapTradeId == flowEvent.SwapTradeId && !e.Invalid && e.PosiQuantity > 0 && e.ValueDate == yest).FirstOrDefault(); + if (flowEvent.UnwindDate == null) { + throw new ArgumentNullException("平仓日期缺失"); + } + var date = flowEvent.UnwindDate.GetValueOrDefault(); + var preDate = date.AddDays(-1); + // 平仓数量/平仓前的数量 * 上一自然日待实现分红收益,保留2位小数 + var eod = DbContext.eod_swap_position.Where(e => e.SwapTradeId == flowEvent.SwapTradeId && !e.Invalid && e.PosiQuantity > 0 && e.ValueDate == preDate).FirstOrDefault(); var dividendIn = eod.PosiDividendSum * unwindQty / eod.PosiQuantity; + // + 付息日>上日日终且小于等于平仓日期的分红数据 + BondPaymentService servie = new BondPaymentService(UserInfo); + var payments = servie.GetBondPayments(flowEvent.UnderlyingCode, preDate, date); + + int shortRatio = flowEvent.PositionType == (int)PositionTypeFlag.Long ? 1 : -1; + int directionRatio = flowEvent.PayDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; + dividendIn = dividendIn + servie.CalcPayment(payments, unwindQty, shortRatio, directionRatio); flowEvent.DividendIn = Math.Round(dividendIn, 2, MidpointRounding.AwayFromZero); } From de184dfdd6a84bb35744a0bc77e6041ed83902b8 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 21:14:39 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E8=BF=98=E5=8E=9F=E5=B9=B3=E4=BB=93?= =?UTF-8?q?=E6=97=B6=E4=BB=98=E6=81=AF=E8=AE=B0=E5=BD=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 09862168..a791eca8 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -889,7 +889,7 @@ namespace YLErp.Modules.SwapModule floatEvent.OptLog = "流水自动"; floatEvent.ClientId = td.ClientId; floatEvent.SetOpt(UserInfo); - EnrichDividendIn(floatEvent, unwindQty); + EnrichDividendIn(floatEvent, unwindQty, td); } unwindData.FlowEvents.Add(floatEvent); var interestPositions = GetUnwindInterests(unwindData.ValueDate, unwindData.UnwindDate.Value, td.id, unwindPercent, (int)SwapEventTypeEnum.平仓); @@ -908,23 +908,20 @@ namespace YLErp.Modules.SwapModule DealUnwind(unwindData, td); } - private void EnrichDividendIn(swap_flow_event flowEvent, decimal unwindQty) + private void EnrichDividendIn(swap_flow_event flowEvent, decimal unwindQty, trade td) { - if (flowEvent.UnwindDate == null) { + if (flowEvent.UnwindDate == null) + { throw new ArgumentNullException("平仓日期缺失"); } var date = flowEvent.UnwindDate.GetValueOrDefault(); - var preDate = date.AddDays(-1); - // 平仓数量/平仓前的数量 * 上一自然日待实现分红收益,保留2位小数 - var eod = DbContext.eod_swap_position.Where(e => e.SwapTradeId == flowEvent.SwapTradeId && !e.Invalid && e.PosiQuantity > 0 && e.ValueDate == preDate).FirstOrDefault(); - var dividendIn = eod.PosiDividendSum * unwindQty / eod.PosiQuantity; - // + 付息日>上日日终且小于等于平仓日期的分红数据 BondPaymentService servie = new BondPaymentService(UserInfo); - var payments = servie.GetBondPayments(flowEvent.UnderlyingCode, preDate, date); + var payments = servie.GetBondPayments(flowEvent.UnderlyingCode, td.StartDate.Value, date); int shortRatio = flowEvent.PositionType == (int)PositionTypeFlag.Long ? 1 : -1; int directionRatio = flowEvent.PayDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; - dividendIn = dividendIn + servie.CalcPayment(payments, unwindQty, shortRatio, directionRatio); + // + 付息日>上日日终且小于等于平仓日期的分红数据 + var dividendIn = servie.CalcPayment(payments, unwindQty, shortRatio, directionRatio); flowEvent.DividendIn = Math.Round(dividendIn, 2, MidpointRounding.AwayFromZero); } From 1bbdd474977bbed75d2c2ffb270bb7a2c0de1bb0 Mon Sep 17 00:00:00 2001 From: gongpei Date: Thu, 23 Oct 2025 22:42:27 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B9=B3=E4=BB=93?= =?UTF-8?q?=E6=97=B6=E8=AE=A1=E6=81=AF=E4=BD=BF=E7=94=A8=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E6=97=A5=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/SwapModule/SwapDealService.cs | 2 +- .../SwapModule/SwapEodPositionService.cs | 63 +++++++++---------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index a791eca8..5e799b66 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -914,7 +914,7 @@ namespace YLErp.Modules.SwapModule { throw new ArgumentNullException("平仓日期缺失"); } - var date = flowEvent.UnwindDate.GetValueOrDefault(); + var date = flowEvent.EventDate; BondPaymentService servie = new BondPaymentService(UserInfo); var payments = servie.GetBondPayments(flowEvent.UnderlyingCode, td.StartDate.Value, date); diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index b7428b63..09ba627a 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -137,7 +137,7 @@ namespace YLErp.Modules.SwapModule } var flowEvents = new List(); Expression> eventExpression = x => x.SwapTradeId == td.id && x.DataState == (int)SwapFlowDateStateEnum.完成; - eventExpression = eventExpression.And(x => x.EventDate == settleDate ); + eventExpression = eventExpression.And(x => x.EventDate == settleDate); //if (settleDate == td.TradeDate) //{ // eventExpression = eventExpression.And(x => x.EventDate == settleDate); @@ -443,7 +443,7 @@ namespace YLErp.Modules.SwapModule decimal allPosiNotionalValue = 0; decimal longNotionalValue = realPositions.Where(s => s.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue);//剩余多头名义本金规模 decimal shortNotionalValue = realPositions.Where(s => s.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue);//剩余空头名义本金规模 - + foreach (var eventGroup in eventQuery.GroupBy(g => g.PositionId))//持仓标的腿合成持仓 { var eventList = eventGroup.ToList(); @@ -562,7 +562,7 @@ namespace YLErp.Modules.SwapModule unwindData.CloseNotionalValue = tdCloseNotionalValue; swapEvent.EventData = JsonHelper.Serialize(unwindData); DbContext.SaveChanges(); - SaveEodSwap(td, tradeDate,preSettleDate); + SaveEodSwap(td, tradeDate, preSettleDate); DbContext.SaveChanges(); trans?.Commit(); } @@ -717,7 +717,7 @@ namespace YLErp.Modules.SwapModule var interests = new SwapDealService(this).GetInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, posiNotionalValue, closePercent, (int)SwapEventTypeEnum.自动互换, false, true, grossPrice, orginPv, true); decimal InterestAmount = interests.Sum(x => x.InterestAmount); decimal TdInterestAmount = interests.Sum(x => x.TdInterestAmount); - + newEodPayPosition.ValueDate = valueDate; newEodPayPosition.PositionId = position.id; UpdateDbOption(newEodPayPosition); @@ -750,7 +750,7 @@ namespace YLErp.Modules.SwapModule newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee; newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum; //持仓价值 - newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum + newEodPayPosition.PosiProfitSum; + newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum + newEodPayPosition.PosiProfitSum; //累计已实现 newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio; @@ -824,7 +824,7 @@ namespace YLErp.Modules.SwapModule preEodPositions.Add(eodPayPosition); var interests = new SwapDealService(this).GetInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, closeNational, 1, eventType, false, true, grossPrice, orginPv, true); decimal TdInterestAmount = interests.Sum(x => x.TdInterestAmount); - + newEodPayPosition.ValueDate = valueDate; newEodPayPosition.PositionId = position.id; UpdateDbOption(newEodPayPosition); @@ -970,7 +970,7 @@ namespace YLErp.Modules.SwapModule } var interests = new SwapDealService(this).GetInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNational, posiShortNational, posiNotionalValue, closePercent, 0, false, needPrice, grossPrice, orginPv); UpdateDbOption(newEodPayPosition); - + newEodPayPosition.PosiStatus = 0; newEodPayPosition.Invalid = false; newEodPayPosition.ValueDate = valueDate; @@ -1137,7 +1137,7 @@ namespace YLErp.Modules.SwapModule { return curretEod; } - var dealDate = curretEod.ValueDate; + var dealDate = curretEod.ValueDate; int shortRatio = eod.PositionType == (int)PositionTypeFlag.Long ? 1 : -1; int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; @@ -1148,9 +1148,9 @@ namespace YLErp.Modules.SwapModule { decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); // 考虑增值税 - curretEod.TdPosiDividend = payment / (1 - tax) * (1 + tax); + curretEod.TdPosiDividend = payment / (1 + tax) * (1 - tax); } - curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; + curretEod.PosiDividendSum = eod.PosiQuantity > 0 ? (eod.PosiDividendSum + curretEod.TdPosiDividend) : 0; curretEod.PosiQuantity = eod.PosiQuantity; if (curretEod.PosiStatus == 1) { @@ -1161,7 +1161,7 @@ namespace YLErp.Modules.SwapModule curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio; //curretEod.TdPosiDividend = 0; //curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend; - curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum+ curretEod.PosiFeePending; + curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; curretEod.TdCloseFee = 0; curretEod.TdCloseQty = 0; curretEod.TdCloseMtmPnl = 0; @@ -1218,7 +1218,7 @@ namespace YLErp.Modules.SwapModule { return curretEod; } - var dealDate = curretEod.ValueDate; + var dealDate = curretEod.ValueDate; int shortRatio = eod.PositionType == (int)PositionTypeFlag.Long ? 1 : -1; int directionRatio = eod.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp); @@ -1231,20 +1231,19 @@ namespace YLErp.Modules.SwapModule BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); // 考虑增值税 - curretEod.TdPosiDividend = payment / (1 - tax) * (1 + tax); + curretEod.TdPosiDividend = payment / (1 + tax) * (1 - tax); curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; - + curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee; curretEod.RealizedPnl = eod.RealizedPnl + curretEod.TdCloseMtmPnl; curretEod.PosiStatus = curretEod.PosiQuantity == 0 ? 1 : 0; var closeQty = unwindEvents.Where(x => x.EventType == (int)SwapFlowEventTypeEnum.平仓).ToList().Sum(s => s.Quantity); // 当日浮动端平仓盈亏·分红 = 平仓数量/昨天剩余平仓数量 * 昨日浮动端待实现收益·分红 - curretEod.TdCloseDividend = closeQty / eod.PosiQuantity * eod.PosiDividendSum; + curretEod.TdCloseDividend = unwindEvents.Sum(e => e.DividendIn); curretEod.RealizedDividend = curretEod.RealizedDividend + curretEod.TdCloseDividend; // 浮动端待实现收益·分红 = 昨日 + 当日浮动端分红 - 当日浮动端平仓盈亏·分红 curretEod.PosiDividendSum = eod.PosiDividendSum + curretEod.TdPosiDividend - curretEod.TdCloseDividend; - curretEod.RealizedDividend = eod.RealizedDividend + curretEod.TdCloseDividend; curretEod.PosiProfitSum = curretEod.PosiMtmPnL + curretEod.PosiDividendSum + curretEod.PosiFeePending; if (curretEod.PosiStatus == 1) { @@ -1320,13 +1319,13 @@ namespace YLErp.Modules.SwapModule curretEod.PosiNetFeePrice = Math.Round(curretEod.PosiNetFeePrice ?? 0, 10, MidpointRounding.AwayFromZero); } curretEod.PosiNotionalValue = curretEod.PosiGrossPrice * curretEod.PosiQuantity * curretEod.ContractSize; - curretEod.PosiNotionalValue= Math.Round(curretEod.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); + curretEod.PosiNotionalValue = Math.Round(curretEod.PosiNotionalValue, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); curretEod.TdPosiDividend = unwindEvents.Sum(x => x.DividendIn) * directionRatio; - curretEod.TdCloseFee = unwindFlowEvents.Sum(x => x.TradingFee+x.TradingFeePending); + curretEod.TdCloseFee = unwindFlowEvents.Sum(x => x.TradingFee + x.TradingFeePending); curretEod.TdCloseQty = unwindQty; curretEod.TdCloseMtmPnl = unwindEvents.Sum(x => x.MarkClosePnl); } - if (curretEod.PosiQuantity==0) + if (curretEod.PosiQuantity == 0) { curretEod.PosiFeePending = 0; } @@ -1347,7 +1346,7 @@ namespace YLErp.Modules.SwapModule { return curretEod; } - var dealDate = settleDate; + var dealDate = settleDate; curretEod.ValueDate = settleDate; curretEod.PosiStartDate = position.PosiStartDate; curretEod.PosiMatuirityDate = td.ExerciseDate.Value; @@ -1457,11 +1456,11 @@ namespace YLErp.Modules.SwapModule /// /// 互换交易 /// 收盘日 - private void SaveEodSwap(trade td, DateTime settleDate,DateTime preSettleDate) + private void SaveEodSwap(trade td, DateTime settleDate, DateTime preSettleDate) { - var eod_Swaps = DbContext.eod_swap.Where(x => x.SwapTradeId == td.id && x.ValueDate >= preSettleDate && x.ValueDate<= settleDate).ToList(); - var eod_Swap = eod_Swaps.FirstOrDefault(x => x.ValueDate == settleDate); - var preEodSwap= eod_Swaps.FirstOrDefault(x => x.ValueDate == preSettleDate); + var eod_Swaps = DbContext.eod_swap.Where(x => x.SwapTradeId == td.id && x.ValueDate >= preSettleDate && x.ValueDate <= settleDate).ToList(); + var eod_Swap = eod_Swaps.FirstOrDefault(x => x.ValueDate == settleDate); + var preEodSwap = eod_Swaps.FirstOrDefault(x => x.ValueDate == preSettleDate); if (eod_Swap == null) { eod_Swap = new eod_swap(); @@ -1918,14 +1917,14 @@ namespace YLErp.Modules.SwapModule { eventDate = QdpCalendarHelper.GetNonHoliday(eventDate.AddDays(tradeExtend.ExtendObj.SettlementRules)); } - item.DayCount = (eventDate - item.position.PosiStartDate).Days+1; + item.DayCount = (eventDate - item.position.PosiStartDate).Days + 1; //item.position.PosiProfitSum += item.position.VTradingFee-item.position.PosiFeePending; SetClientEodPosition(item.position); //item.position.PosiProfitSum += item.TradingFee; - var posiProfitSum= item.position.PosiProfitSum; + var posiProfitSum = item.position.PosiProfitSum; //item.position.PosiProfitSum 不需要加交易费用 - item.position.PosiProfitSum = item.position.PosiProfitSum - item.position.PosiFeePending-item.position.PosiDividendSum; - item.NetSettmentAmount = item.position.PosiProfitSum+ item.position.PosiDividendSum+ item.position.PosiFeePending; + item.position.PosiProfitSum = item.position.PosiProfitSum - item.position.PosiFeePending - item.position.PosiDividendSum; + item.NetSettmentAmount = item.position.PosiProfitSum + item.position.PosiDividendSum + item.position.PosiFeePending; item.PeriodAmount = item.position.PosiDividendSum; var margins = positions.Where(x => x.SwapTradeId == item.position.SwapTradeId); var interests = eodPositions.Where(x => x.SwapTradeId == item.position.SwapTradeId && x.ValueDate == item.position.ValueDate); @@ -1933,14 +1932,14 @@ namespace YLErp.Modules.SwapModule var eodInterests = interests.Where(x => !marginTypes.Contains(x.InterestMode)); var floatRateInterest = eodInterests.Where(x => !string.IsNullOrEmpty(x.FloatRateUnderlyingCode)).FirstOrDefault(); item.position.FloatRateUnderlyingCode = floatRateInterest?.FloatRateUnderlyingCode; - item.position.FloatRate= floatRateInterest?.FloatRate??0; + item.position.FloatRate = floatRateInterest?.FloatRate ?? 0; item.OpenMarginAmount = margins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); item.OpenMarginRate = margins.Sum(s => s.InterestRateDefault * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); item.MarginInterestAmount = eodMargins.Sum(s => s.InterestIncomeSum * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); item.InterestAmount = eodInterests.Sum(s => s.InterestIncomeSum * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? -1 : 1)); item.InterestRate = eodInterests.Sum(s => s.InterestRateDefault); item.NetSettmentAmount += item.InterestAmount + item.MarginInterestAmount + eodMargins.Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1)); - item.NetSettmentAmount = Math.Round(item.NetSettmentAmount, ConsGlobal.MoneyRound,MidpointRounding.AwayFromZero); + item.NetSettmentAmount = Math.Round(item.NetSettmentAmount, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero); if (item.position.PosiNotionalValue != 0 && item.position.PosiNetPrice != 0) { item.FloatRateAbs = item.position.PosiNotionalValue == 0 ? 0 : item.InterestAmount / item.position.PosiNotionalValue; @@ -1986,7 +1985,7 @@ namespace YLErp.Modules.SwapModule return; } } - + /// /// 获取客户互换持仓信息 /// @@ -2011,7 +2010,7 @@ namespace YLErp.Modules.SwapModule foreach (var item in eodSwaps) { var tradeOrigin = trades.First(x => x.id == item.SwapTradeId); - var realizedPnL = item.RealizedMtmPnL + item.RealizedInterest; + var realizedPnL = item.RealizedMtmPnL + item.RealizedInterest; var tdExtend = tradeExtends.First(x => x.TradeId == item.SwapTradeId); eod_position model = new eod_position() { From d8d7dee5628901ee4986151aa55893035dda5997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AC=B4=E6=94=BF=20=E6=97=B6?= Date: Fri, 24 Oct 2025 14:53:13 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B9=B3=E4=BB=93?= =?UTF-8?q?=E4=B8=BA=E8=AE=A1=E7=AE=97=E7=A8=8E=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?,=20=E4=BF=AE=E5=A4=8D=E6=97=A5=E7=BB=88=E7=BB=93=E7=AE=97?= =?UTF-8?q?=E6=9C=AA=E8=80=83=E8=99=91=E8=B5=B7=E7=AE=97=E6=97=A5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/Modules/SwapModule/SwapDealService.cs | 4 ++++ .../SwapModule/SwapEodPositionService.cs | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 5e799b66..80d0f28f 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -922,6 +922,10 @@ namespace YLErp.Modules.SwapModule int directionRatio = flowEvent.PayDirection == (int)SwapDirectionEnum.收取 ? 1 : -1; // + 付息日>上日日终且小于等于平仓日期的分红数据 var dividendIn = servie.CalcPayment(payments, unwindQty, shortRatio, directionRatio); + var um = DataCacheProvider.GetUnderlyingDataSource().GetData(flowEvent.UnderlyingCode); + decimal tax = um.ValueAddedTax ?? 0; + dividendIn = dividendIn / (1 + tax) * (1 - tax); + flowEvent.DividendIn = Math.Round(dividendIn, 2, MidpointRounding.AwayFromZero); } diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 09ba627a..14f0af82 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -1144,7 +1144,7 @@ namespace YLErp.Modules.SwapModule var price = UnderlyingCodePrice(eod.UnderlyingCode, dealDate, out decimal vobp); decimal tax = um.ValueAddedTax ?? 0; BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); - if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0 || valueDate == td.UnWindDate)) + if (valueDate > td.StartDate.Value && curretEod.PosiQuantity > 0) { decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); // 考虑增值税 @@ -1226,12 +1226,15 @@ namespace YLErp.Modules.SwapModule curretEod.UnderlyingPrice = price; curretEod.UnderlyingMarketValue = curretEod.UnderlyingPrice * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio; curretEod.PosiMtmPnL = (curretEod.UnderlyingPrice - curretEod.PosiGrossPrice) * curretEod.PosiQuantity * curretEod.ContractSize * shortRatio * directionRatio; - - decimal tax = um.ValueAddedTax ?? 0; - BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); - decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); - // 考虑增值税 - curretEod.TdPosiDividend = payment / (1 + tax) * (1 - tax); + curretEod.TdPosiDividend = 0; + if (valueDate > td.StartDate.Value && (curretEod.PosiQuantity > 0)) + { + decimal tax = um.ValueAddedTax ?? 0; + BondPaymentService bondPaymentService = new BondPaymentService(UserInfo); + decimal payment = bondPaymentService.CalcPayment(curretEod.UnderlyingCode, eod.ValueDate, valueDate, curretEod.PosiQuantity, shortRatio, directionRatio); + // 考虑增值税 + curretEod.TdPosiDividend = payment / (1 + tax) * (1 - tax); + } curretEod.RealizedMtmPnL = eod.RealizedMtmPnL + curretEod.TdCloseMtmPnl; curretEod.RealizedFee = eod.RealizedFee + curretEod.TdCloseFee; From e891ce8faa4672e9f1e352300c8df4bc854cf09a Mon Sep 17 00:00:00 2001 From: gongpei Date: Wed, 29 Oct 2025 17:25:14 +0800 Subject: [PATCH 13/13] =?UTF-8?q?fix:=20=E5=AE=9E=E6=97=B6=E6=8C=81?= =?UTF-8?q?=E4=BB=93=E8=AE=A1=E7=AE=97=E6=8C=81=E4=BB=93=E7=9B=88=E4=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs index eea6f90c..f8b2e8d0 100644 --- a/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs +++ b/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs @@ -510,7 +510,7 @@ namespace YLErp.BLL.Eod && t.TradeType == "收益互换").ToList(); //OTC持仓交易 var tradeIdList = tradeList.Select(t => t.id).ToList(); - var positions = db.swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && !x.IsInitial && x.PosiQuantity > 0&&!x.Invalid).ToList(); + var positions = db.swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && !x.IsInitial && x.PosiQuantity > 0 && !x.Invalid).ToList(); var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成).ToList(); using var bondDb = new BondOmsDBContext(); var clientPositions = bondDb.client_position.AsEnumerable(); @@ -533,18 +533,18 @@ namespace YLErp.BLL.Eod td, p }; - var positionGroup = query.AsEnumerable().GroupBy(x => new { x.p.UnderlyingCode, x.td.ClientId,x.p.PosiDirection}); + var positionGroup = query.AsEnumerable().GroupBy(x => new { x.p.UnderlyingCode, x.td.ClientId, x.p.PosiDirection }); var dealSwapFlowIds = new List(); SwapTradeAutoService swapTradeAutoService = new SwapTradeAutoService(optUser); var datenow = DateTime.Now; foreach (var pair in positionGroup) { var client = DataCacheProvider.GetClientDataSource().GetData(pair.Key.ClientId); - if (client == null||string.IsNullOrEmpty(pair.Key.UnderlyingCode)) + if (client == null || string.IsNullOrEmpty(pair.Key.UnderlyingCode)) { continue; } - var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == pair.Key.ClientId && x.security_id == pair.Key.UnderlyingCode&&x.direction== pair.Key.PosiDirection); + var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == pair.Key.ClientId && x.security_id == pair.Key.UnderlyingCode && x.direction == pair.Key.PosiDirection); var trades = pair.Select(s => s.td).ToList(); var tradeIds = trades.Select(x => x.id); var positionGroupItems = positions.Where(x => tradeIds.Contains(x.SwapTradeId) && x.UnderlyingCode == pair.Key.UnderlyingCode && x.PosiDirection == pair.Key.PosiDirection); @@ -563,15 +563,17 @@ namespace YLErp.BLL.Eod var multiplier = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? ConsGlobal.bondShowPriceMultiple : 1; // 计算加权平均价格(区分债券和非债券) - var weightedPrice = posiQty==0?0: positionGroupItems - .Sum(s => { + var weightedPrice = posiQty == 0 ? 0 : positionGroupItems + .Sum(s => + { decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? s.PosiGrossPrice * ConsGlobal.bondShowPriceMultiple : s.PosiGrossPrice; return s.PosiQuantity * price; }) / posiQty; - var weightedNetPrice = posiQty==0?0: positionGroupItems - .Sum(s => { + var weightedNetPrice = posiQty == 0 ? 0 : positionGroupItems + .Sum(s => + { decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? s.PosiNetPrice * ConsGlobal.bondShowPriceMultiple : s.PosiNetPrice; @@ -584,7 +586,7 @@ namespace YLErp.BLL.Eod var um = DataCacheProvider.GetUnderlyingDataSource().GetData(pair.Key.UnderlyingCode); clientPosition = CreateClientPosition(clientPosition, pair.Key.ClientId, pair.Key.UnderlyingCode, netPrice, price, posiQty / 10000, comminsions, positionType == PositionTypeFlag.Long ? 0 : 1, lastPosi.ContractSize, pair.Key.PosiDirection); clientPosition.position_notional_principal = totalNotional; - if (pair.Key.PosiDirection==(int)SwapDirectionEnum.支付) + if (pair.Key.PosiDirection == (int)SwapDirectionEnum.支付) { var flowMerges = MergeSwapFlow(newSwapFlows, multiplier); dealSwapFlowIds.AddRange(newSwapFlows.Select(s => s.id)); @@ -596,7 +598,7 @@ namespace YLErp.BLL.Eod clientPosition.update_user = 0; SetClientPositionPrice(clientPosition); clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); - clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1) - clientPosition.commission; + clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * 0.01m * (clientPosition.position_qty * 10000) * (clientPosition.side == 0 ? 1 : -1) - clientPosition.commission; clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero); clientPosition.today_profit_loss = clientPosition.swap_market_value - lastPv; if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd)//发kafka 获取成交收益率 @@ -629,7 +631,7 @@ namespace YLErp.BLL.Eod continue; } var um = DataCacheProvider.GetUnderlyingDataSource().GetData(swapFlowGroup.Key.UnderlyingCode); - var multiplier = um!=null&& um.IsBond() ? ConsGlobal.bondShowPriceMultiple : 1; + var multiplier = um != null && um.IsBond() ? ConsGlobal.bondShowPriceMultiple : 1; var flowMerges = MergeSwapFlow(swapFlowGroup.ToList(), multiplier); var flowMergeMax = flowMerges.OrderByDescending(s => s.TradingQty).First(); var flowMergeMin = flowMerges.FirstOrDefault(x => x.BsType != flowMergeMax.BsType); @@ -665,7 +667,7 @@ namespace YLErp.BLL.Eod bondDb.SaveChanges(); } } - sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0"; + sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0"; bondDb.BulkDelete(sql); bondDb.SaveChanges(); #endregion @@ -741,10 +743,10 @@ namespace YLErp.BLL.Eod private static void BondCalcApi(ClientPosition clientPosition) { var resp = BondCalcHepler.BondCalc(clientPosition.security_id, clientPosition.deal_full_price_avg ?? 0, "DP"); - if (resp!=null) + if (resp != null) { - clientPosition.deal_yield_avg = resp.ytm* ConsGlobal.bondPriceMultiple; - _yLCache.StringSetWithNoPrefix("TRS-BondFullPrice:" + clientPosition.security_id, resp,TimeSpan.FromHours(1)); + clientPosition.deal_yield_avg = resp.ytm * ConsGlobal.bondPriceMultiple; + _yLCache.StringSetWithNoPrefix("TRS-BondFullPrice:" + clientPosition.security_id, resp, TimeSpan.FromHours(1)); } } /// @@ -759,7 +761,7 @@ namespace YLErp.BLL.Eod /// /// /// - private static ClientPosition CreateClientPosition(ClientPosition clientPosition, int clientId, string underlyingCode, decimal price, decimal fullPrice, decimal qty, decimal comminsion, int side,decimal contractsize,int direction) + private static ClientPosition CreateClientPosition(ClientPosition clientPosition, int clientId, string underlyingCode, decimal price, decimal fullPrice, decimal qty, decimal comminsion, int side, decimal contractsize, int direction) { var underlyingName = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode)?.UnderlyingName; var client = DataCacheProvider.GetClientDataSource().GetData(clientId); @@ -781,7 +783,7 @@ namespace YLErp.BLL.Eod clientPosition.side = side; clientPosition.create_time = DateTime.Now; clientPosition.client_user_id = 0; - clientPosition.position_notional_principal = fullPrice* qty * 10000 * contractsize * ConsGlobal.bondPriceMultiple; + clientPosition.position_notional_principal = fullPrice * qty * 10000 * contractsize * ConsGlobal.bondPriceMultiple; clientPosition.direction = direction; return clientPosition; } @@ -865,7 +867,7 @@ namespace YLErp.BLL.Eod clientPosition.deal_full_price_avg = priceResult.Item1; } clientPosition.commission = flowMerges.Sum(s => s.TradingFee); - clientPosition.position_qty = Math.Abs(allPosiQty/10000); + clientPosition.position_qty = Math.Abs(allPosiQty / 10000); clientPosition.position_notional_principal = Math.Abs(allPosiQty) * clientPosition.deal_full_price_avg * ConsGlobal.bondPriceMultiple; if (allPosiQty < 0) { @@ -881,7 +883,7 @@ namespace YLErp.BLL.Eod return (clientPosition.deal_full_price_avg ?? 0, clientPosition.deal_price_avg ?? 0); } var sameAmount = flowMergeSame.TradingAmountAvg * flowMergeSame.TradingQty; - var sameNetAmount = (flowMergeSame.TradingAmountNetAvg??0) * flowMergeSame.TradingQty; + var sameNetAmount = (flowMergeSame.TradingAmountNetAvg ?? 0) * flowMergeSame.TradingQty; var totalQty = (clientPosition.position_qty ?? 0) + flowMergeSame.TradingQty; if (totalQty == 0) { @@ -1052,7 +1054,7 @@ namespace YLErp.BLL.Eod //根据TradeId,VolType,ValueDate更新已经存在的数据 var tradeids = resultRisks.Select(t => t.TradeId).ToList(); var tradeRisks = db.realtime_trade_risk.Where(x => tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList(); - var delTradeRisks= db.realtime_trade_risk.Where(x => !tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList(); + var delTradeRisks = db.realtime_trade_risk.Where(x => !tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList(); db.realtime_trade_risk.RemoveRange(delTradeRisks); for (var i = 0; i < tradeRisks.Count; i++) { @@ -2388,7 +2390,7 @@ namespace YLErp.BLL.Eod public static ClientBalanceForTrsResponse GetClientBalance(int clientId) { - if (_yLCache!=null) + if (_yLCache != null) { return _yLCache.StringGet("ClientBalance:" + clientId); }