客户保证金率设置需求变更:不需要根据发行年限,且增加30年以上一档,交易确认书保证金率获取也需要修改
This commit is contained in:
@@ -30,6 +30,11 @@ namespace YLErp.DBModels
|
||||
/// </summary>
|
||||
public const string ThirtyYear = "30Y";
|
||||
|
||||
/// <summary>
|
||||
/// 30年以上期
|
||||
/// </summary>
|
||||
public const string OverThirtyYear = "Over30Y";
|
||||
|
||||
/// <summary>
|
||||
/// 所有允许的期限值
|
||||
/// </summary>
|
||||
@@ -39,7 +44,8 @@ namespace YLErp.DBModels
|
||||
TwoYear,
|
||||
FiveYear,
|
||||
TenYear,
|
||||
ThirtyYear
|
||||
ThirtyYear,
|
||||
OverThirtyYear
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -66,6 +72,7 @@ namespace YLErp.DBModels
|
||||
FiveYear => "5年",
|
||||
TenYear => "10年",
|
||||
ThirtyYear => "30年",
|
||||
OverThirtyYear => "30年以上",
|
||||
_ => term?.Replace("Y", "年") ?? "默认"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.VisualBasic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Org.BouncyCastle.Ocsp;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -11,6 +12,7 @@ using YLErp.DBModels.Enums;
|
||||
using YLErp.Enums;
|
||||
using YLErp.Plugins.TradeDocGenerator;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
using static NPOI.HSSF.Util.HSSFColor;
|
||||
|
||||
namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
{
|
||||
@@ -100,7 +102,6 @@ namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
var clientduties = Context.GetClientDuties();
|
||||
var table1 = new JArray();
|
||||
var table2 = new JArray();
|
||||
var clientMarginRate = Context.GetClientMarginRate(client.id);
|
||||
dic["交易编号"] = GetContractNo(out string contractIndex);
|
||||
dic["交易对手方全称"] = client.ClientType != "产品" ? client.Name : $"{client.Manager}作为管理人代表{client.Name}";
|
||||
dic["主协议编号"] = client.MainProtocolCode;
|
||||
@@ -126,7 +127,7 @@ namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
var initialMarginQuery = swapPositions.Where(x => x.InterestMode == 5);
|
||||
var additionMarginQuery = swapPositions.Where(x => x.InterestMode == 6);
|
||||
var underlyingCode = swapPosition?.UnderlyingCode;
|
||||
|
||||
var clientMarginRate = YLErp.Modules.UnderlyingModule.UnderlyingHelper.GetApplicableMarginRate(client.id, underlyingCode, trade.TradeDate.Value);
|
||||
if (count == 0)
|
||||
{
|
||||
var interestMargin = allinterestMargins.FirstOrDefault(o => o.interest_rest_days != null);
|
||||
@@ -197,9 +198,9 @@ namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
//}
|
||||
|
||||
//dic["计算基准"] = calculationBasis;
|
||||
dic["初始保障金率"] = ((clientMarginRate?.InitMarginRate ?? 0) * 100).ToString("0.####") + "%";
|
||||
dic["维持保障金率"] = ((clientMarginRate?.MaintenanceRate ?? 0) * 100).ToString("0.####") + "%";
|
||||
|
||||
dic["初始保障金率"] = ((clientMarginRate?.init_rate ?? 0) * 100).ToString("0.####") + "%";
|
||||
dic["维持保障金率"] = ((clientMarginRate?.maintain_rate ?? 0) * 100).ToString("0.####") + "%";
|
||||
dic["期初预付金".Insert("期初预付金".Length, "2?")] = (StockEqvNotionalRealSum * Convert.ToDouble(clientMarginRate?.init_rate??0)).ToString("0.##");
|
||||
//var initialMarginSum = initialMarginQuery.Sum(x =>
|
||||
// x.InterestDirection == 2 ? x.InterestPrincipalFix * -1 : x.InterestPrincipalFix);
|
||||
//dic["期初预付金".Insert("期初预付金".Length, "2?")] = initialMarginSum.ToString("0.##");
|
||||
@@ -224,7 +225,7 @@ namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
FormatToDict("交易费用", (double)((swapPosition?.PosiTradingFeePending * 2) ?? 0), row);
|
||||
|
||||
row["期初预付金利率"] = ((initialMarginQuery.FirstOrDefault()?.InterestRateDefault) ?? 0) * 100;
|
||||
row["追加预付金返息率"] = ((clientMarginRate?.AddToMarginRebateRate) ?? 0) * 100;
|
||||
//row["追加预付金返息率"] = ((clientMarginRate?.AddToMarginRebateRate) ?? 0) * 100;
|
||||
if (!string.IsNullOrEmpty(underlyingCode))
|
||||
{
|
||||
var um = Context.GetTradeUnderlying(underlyingCode);
|
||||
@@ -258,7 +259,7 @@ namespace YLErp.Plugins.ShanXi.DocumentGenerator
|
||||
dic["交易费率"] = dic["基本费率"];
|
||||
dic["交易费用"] = PosiTradingFeePending;
|
||||
dic["名义本金".Insert("名义本金".Length, "2?")] = StockEqvNotionalRealSum.ToString("0.##");
|
||||
dic["期初预付金".Insert("期初预付金".Length, "2?")] = (StockEqvNotionalRealSum * clientMarginRate?.InitMarginRate)?.ToString("0.##");
|
||||
|
||||
|
||||
|
||||
clientduties = clientduties.Where(x => x.ContactTypeId.Contains("3")).OrderBy(o => o.id).ToList();//交易确认书邮件接收人
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Framework\YLErp.Core\YLErp.Core.csproj" />
|
||||
<ProjectReference Include="..\..\YLErpDAL\YLErpDAL.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,76 +9,54 @@ namespace YLErp.UnitTestProject.Modules.UnderlyingModule
|
||||
[TestMethod]
|
||||
public void GetApplicableMarginTerm_RuleTable_AllCases()
|
||||
{
|
||||
// 发行期限不限(OpenDate=null),测试(0.00,2.00],应返回2年
|
||||
// <=2年,应返回2年
|
||||
var code1 = "UNLIMITED_2Y";
|
||||
var maturity1 = new DateTime(2030, 1, 1);
|
||||
var underlying1 = CreateTestUnderlying ( code1, null,maturity1);
|
||||
var underlying1 = CreateTestUnderlying(code1, null, maturity1);
|
||||
var valueDate1 = maturity1.AddYears(-1); // 剩余1年
|
||||
var result1=UnderlyingHelper.GetApplicableMarginTerm(code1, valueDate1);
|
||||
Assert.AreEqual(ConsMarginTerm.TwoYear, result1, "(0,2]年 不限 应为2年");
|
||||
var result1 = UnderlyingHelper.GetApplicableMarginTerm(code1, valueDate1);
|
||||
Assert.AreEqual(ConsMarginTerm.TwoYear, result1, "<=2年 应为2年");
|
||||
|
||||
// (2.00,2.25] <5年,应返回2年
|
||||
var code2 = "LT5_2_25";
|
||||
var open2 = new DateTime(2020, 1, 1); var maturity2 = new DateTime(2024, 3, 1); // 4.17年
|
||||
var underlying2 = CreateTestUnderlying(code2, open2, maturity2);
|
||||
var valueDate2 = maturity2.AddYears(-2).AddMonths(-2); // 剩余约2.17年
|
||||
// (2,5]年,应返回5年
|
||||
var code2 = "UNLIMITED_5Y";
|
||||
var maturity2 = new DateTime(2030, 1, 1);
|
||||
var underlying2 = CreateTestUnderlying(code2, null, maturity2);
|
||||
var valueDate2 = maturity2.AddYears(-3); // 剩余3年
|
||||
var result2 = UnderlyingHelper.GetApplicableMarginTerm(code2, valueDate2);
|
||||
Assert.AreEqual(ConsMarginTerm.TwoYear, result2, "(2,2.25]年 <5 应为2年");
|
||||
Assert.AreEqual(ConsMarginTerm.FiveYear, result2, "(2,5]年 应为5年");
|
||||
|
||||
// (2.00,2.25] >=5年,应返回5年
|
||||
var code3 = "GE5_2_25";
|
||||
var open3 = new DateTime(2020, 1, 1); var maturity3 = new DateTime(2026, 1, 1); // 6年
|
||||
var underlying3 = CreateTestUnderlying(code3, open3, maturity3);
|
||||
var valueDate3_2 = maturity3.AddYears(-2).AddMonths(-1); // 剩余约2.08年
|
||||
// (5,10]年,应返回10年
|
||||
var code3 = "UNLIMITED_10Y";
|
||||
var maturity3 = new DateTime(2040, 1, 1);
|
||||
var underlying3 = CreateTestUnderlying(code3, null, maturity3);
|
||||
var valueDate3 = maturity3.AddYears(-7); // 剩余13年
|
||||
var valueDate3_2 = maturity3.AddYears(-10); // 剩余10年
|
||||
var result3 = UnderlyingHelper.GetApplicableMarginTerm(code3, valueDate3_2);
|
||||
Assert.AreEqual(ConsMarginTerm.FiveYear, result3, "(2,2.25]年 >=5 应为5年");
|
||||
Assert.AreEqual(ConsMarginTerm.TenYear, result3, "(5,10]年 应为10年");
|
||||
|
||||
// (2.25,5.00] 不限,应返回5年
|
||||
var code4 = "UNLIMITED_5Y";
|
||||
var maturity4 = new DateTime(2030, 1, 1);
|
||||
// (10,30]年,应返回30年
|
||||
var code4 = "UNLIMITED_30Y";
|
||||
var maturity4 = new DateTime(2050, 1, 1);
|
||||
var underlying4 = CreateTestUnderlying(code4, null, maturity4);
|
||||
var valueDate4 = maturity4.AddYears(-3); // 剩余3年
|
||||
var valueDate4 = maturity4.AddYears(-28); // 剩余28年
|
||||
var result4 = UnderlyingHelper.GetApplicableMarginTerm(code4, valueDate4);
|
||||
Assert.AreEqual(ConsMarginTerm.FiveYear, result4, "(2.25,5]年 不限 应为5年");
|
||||
Assert.AreEqual(ConsMarginTerm.ThirtyYear, result4, "(10,30]年 应为30年");
|
||||
|
||||
// (5.00,5.25] <7年,应返回5年
|
||||
var code5 = "LT7_5_25";
|
||||
var open5 = new DateTime(2020, 1, 1); var maturity5 = new DateTime(2026, 1, 1); // 6年
|
||||
var underlying5 = CreateTestUnderlying(code5, open5, maturity5);
|
||||
var valueDate5 = maturity5.AddYears(-5).AddMonths(-1); // 剩余约5.08年
|
||||
var result5 = UnderlyingHelper.GetApplicableMarginTerm(underlying5.UnderlyingCode, valueDate5);
|
||||
Assert.AreEqual(ConsMarginTerm.FiveYear, result5, "(5,5.25]年 <7 应为5年");
|
||||
// >30年,应返回30年以上
|
||||
var code5 = "OVER_30Y";
|
||||
var maturity5 = new DateTime(2060, 1, 1);
|
||||
var underlying5 = CreateTestUnderlying(code5, null, maturity5);
|
||||
var valueDate5 = maturity5.AddYears(-31); // 剩余31年
|
||||
var result5 = UnderlyingHelper.GetApplicableMarginTerm(code5, valueDate5);
|
||||
Assert.AreEqual(ConsMarginTerm.OverThirtyYear, result5, ">30年 应为30年以上");
|
||||
|
||||
// (5.00,5.25] >=7年,应返回10年
|
||||
var code6 = "GE7_5_25";
|
||||
var open6 = new DateTime(2015, 1, 1); var maturity6 = new DateTime(2023, 2, 1); // 8.08年
|
||||
var underlying6 = CreateTestUnderlying(code6, open6, maturity6);
|
||||
var valueDate6 = maturity6.AddYears(-5).AddMonths(-1); // 剩余约5.08年
|
||||
// 无效的到期日,应为默认
|
||||
var code6 = "INVALID_TERM";
|
||||
DateTime? maturity6 = null;
|
||||
var underlying6 = CreateTestUnderlying(code6, null, maturity6);
|
||||
var valueDate6 = DateTime.Now.Date;
|
||||
var result6 = UnderlyingHelper.GetApplicableMarginTerm(code6, valueDate6);
|
||||
Assert.AreEqual(ConsMarginTerm.TenYear, result6, "(5,5.25]年 >=7 应为10年");
|
||||
|
||||
// (5.25,25.00] 不限,应返回10年
|
||||
var code7 = "UNLIMITED_10Y";
|
||||
var maturity7 = new DateTime(2040, 1, 1);
|
||||
var underlying7 = CreateTestUnderlying(code7, null, maturity7);
|
||||
var valueDate7 = maturity7.AddYears(-10); // 剩余10年
|
||||
var result7 = UnderlyingHelper.GetApplicableMarginTerm(code7, valueDate7);
|
||||
Assert.AreEqual(ConsMarginTerm.TenYear, result7, "(5.25,25]年 不限 应为10年");
|
||||
|
||||
// (25.00,30.00] 不限,应返回30年
|
||||
var code8 = "UNLIMITED_30Y";
|
||||
var maturity8 = new DateTime(2050, 1, 1);
|
||||
var underlying8 = CreateTestUnderlying(code8, null, maturity8);
|
||||
var valueDate8 = maturity8.AddYears(-28); // 剩余28年
|
||||
var result8 = UnderlyingHelper.GetApplicableMarginTerm(code8, valueDate8);
|
||||
Assert.AreEqual(ConsMarginTerm.ThirtyYear, result8, "(25,30]年 不限 应为30年");
|
||||
|
||||
var code9 = "INVALID_TERM";
|
||||
DateTime? maturity9 = null;
|
||||
var underlying9 = CreateTestUnderlying(code9, null, maturity9);
|
||||
var valueDate9 = DateTime.Now.Date;
|
||||
var result9 = UnderlyingHelper.GetApplicableMarginTerm(code9, valueDate9);
|
||||
Assert.AreEqual(ConsMarginTerm.Default, result9, "无效的到期日 不限 应为默认");
|
||||
Assert.AreEqual(ConsMarginTerm.Default, result6, "无效的到期日 应为默认");
|
||||
}
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
@@ -8,10 +8,14 @@ namespace YLErp.Model
|
||||
public class ClientMarginDetailDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 利率债期限
|
||||
/// 债券期限
|
||||
/// </summary>
|
||||
public string bond_term { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 债券期限显示
|
||||
/// </summary>
|
||||
public string bond_term_desc => ConsMarginTerm.GetDisplayName(bond_term);
|
||||
|
||||
/// <summary>
|
||||
/// 初始保证金率(%) - 可空
|
||||
/// </summary>
|
||||
|
||||
@@ -298,15 +298,11 @@ namespace YLErp.Modules.UnderlyingModule
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
if (underlying == null || !underlying.MaturityDate.HasValue)
|
||||
return ConsMarginTerm.Default;
|
||||
|
||||
// 计算发行年限(从上市日期到到期日期)
|
||||
var issueTermYears = getYearTerm(underlying.OpenDate, underlying.MaturityDate);
|
||||
|
||||
// 计算剩余期限(从估值日期到到期日期)
|
||||
var remainingTermYears = getYearTerm(valueDate, underlying.MaturityDate);
|
||||
|
||||
// 根据业务规则确定适用的保证金率期限
|
||||
return DetermineMarginTerm(issueTermYears, remainingTermYears);
|
||||
return DetermineMarginTerm(remainingTermYears);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -317,55 +313,32 @@ namespace YLErp.Modules.UnderlyingModule
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据发行年限和剩余年限确定适用的保证金率期限
|
||||
/// 规则表格:
|
||||
/// | 剩余期限(年) | 发行期限(年) | 则适用于 |
|
||||
/// |------------------|---------------|----------|
|
||||
/// | (0.00,2.00] | 不限 | 2年 |
|
||||
/// | (2.00,2.25] | <5 | 2年 |
|
||||
/// | (2.00,2.25] | >=5 | 5年 |
|
||||
/// | (2.25,5.00] | 不限 | 5年 |
|
||||
/// | (5.00,5.25] | <7 | 5年 |
|
||||
/// | (5.00,5.25] | >=7 | 10年 |
|
||||
/// | (5.25,25.00] | 不限 | 10年 |
|
||||
/// | (25.00,30.00] | 不限 | 30年 |
|
||||
/// 说明:发行年限为null或0时视为“不限”
|
||||
/// 根据剩余年限确定适用的保证金率期限(新版规则,仅看剩余期限)
|
||||
/// | 剩余期限(年) | 则适用于 |
|
||||
/// |------------------|----------|
|
||||
/// | <=2 | 2年档位 |
|
||||
/// | (2,5] | 5年 |
|
||||
/// | (5,10] | 10年 |
|
||||
/// | (10,30] | 30年 |
|
||||
/// | >30 | 30年以上 |
|
||||
/// 未设置或无法计算剩余期限,使用“默认”
|
||||
/// </summary>
|
||||
private static string DetermineMarginTerm(double? issueYears, double? remainingYears)
|
||||
private static string DetermineMarginTerm( double? remainingYears)
|
||||
{
|
||||
// (0.00,2.00]年 不限 2年
|
||||
if (remainingYears > 0.00 && remainingYears <= 2.00)
|
||||
// 新版规则:只看剩余期限
|
||||
if (!remainingYears.HasValue)
|
||||
return ConsMarginTerm.Default;
|
||||
|
||||
if (remainingYears <= 2.0)
|
||||
return ConsMarginTerm.TwoYear;
|
||||
|
||||
// (2.00,2.25] <5 2年
|
||||
if (remainingYears > 2.00 && remainingYears <= 2.25 && issueYears.HasValue && issueYears < 5)
|
||||
return ConsMarginTerm.TwoYear;
|
||||
|
||||
// (2.00,2.25] >=5 5年
|
||||
if (remainingYears > 2.00 && remainingYears <= 2.25 && issueYears.HasValue && issueYears >= 5)
|
||||
if (remainingYears > 2.0 && remainingYears <= 5.0)
|
||||
return ConsMarginTerm.FiveYear;
|
||||
|
||||
// (2.25,5.00] 不限 5年
|
||||
if (remainingYears > 2.25 && remainingYears <= 5.00)
|
||||
return ConsMarginTerm.FiveYear;
|
||||
|
||||
// (5.00,5.25] <7 5年
|
||||
if (remainingYears > 5.00 && remainingYears <= 5.25 && issueYears.HasValue && issueYears < 7)
|
||||
return ConsMarginTerm.FiveYear;
|
||||
|
||||
// (5.00,5.25] >=7 10年
|
||||
if (remainingYears > 5.00 && remainingYears <= 5.25 && issueYears.HasValue && issueYears >= 7)
|
||||
if (remainingYears > 5.0 && remainingYears <= 10.0)
|
||||
return ConsMarginTerm.TenYear;
|
||||
|
||||
// (5.25,25.00] 不限 10年
|
||||
if (remainingYears > 5.25 && remainingYears <= 25.00)
|
||||
return ConsMarginTerm.TenYear;
|
||||
|
||||
// (25.00,30.00] 不限 30年
|
||||
if (remainingYears > 25.00 && remainingYears <= 30.00)
|
||||
if (remainingYears > 10.0 && remainingYears <= 30.0)
|
||||
return ConsMarginTerm.ThirtyYear;
|
||||
|
||||
// 其他情况返回默认
|
||||
if (remainingYears > 30.0)
|
||||
return ConsMarginTerm.OverThirtyYear;
|
||||
return ConsMarginTerm.Default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
@for (int i = 0; i < details.Count; i++)
|
||||
{
|
||||
var detail = details[i];
|
||||
var displayName = detail.bond_term == "" ? "默认" : detail.bond_term.Replace("Y", "年");
|
||||
var displayName = YLErp.DBModels.ConsMarginTerm.GetDisplayName(detail.bond_term);
|
||||
<tr data-index="@i">
|
||||
<td>
|
||||
<input type="hidden" name="details[@i].bond_term" value="@detail.bond_term" />
|
||||
|
||||
@@ -247,19 +247,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:格式化期限显示
|
||||
function formatBondTerm(bondTerm) {
|
||||
if (!bondTerm || bondTerm === '') return '默认';
|
||||
if (bondTerm === null || bondTerm === undefined) return '--';
|
||||
|
||||
// 将Y替换为年
|
||||
var formatted = bondTerm.toString().replace(/Y/g, '年');
|
||||
return escapeHtml(formatted);
|
||||
}
|
||||
|
||||
// 辅助函数:生成详情单元格HTML
|
||||
function generateDetailCells(detail) {
|
||||
return '<td>' + formatBondTerm(detail.bond_term) + '</td>' +
|
||||
return '<td>' + detail.bond_term_desc + '</td>' +
|
||||
'<td class="text-right">' + formatPercentage(detail.init_rate) + '</td>' +
|
||||
'<td class="text-right">' + formatPercentage(detail.maintain_rate) + '</td>' +
|
||||
'<td class="text-center">' + (detail.swap_days || '--') + '天</td>';
|
||||
|
||||
Reference in New Issue
Block a user