Files
zszq-trs/YLErpDAL/Modules/MarginModule/MarginTemplateV2RateHelper.cs
T

153 lines
6.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.Enums;
using YLErp.Modules.UnderlyingModule;
namespace YLErp.Modules.MarginModule
{
/// <summary>
/// 预付金模板V2 取数帮助类:按交易绑定的模板(trade_margin_template → margin_template_v2 → margin_template_detail
/// 取 初始预付金率x / 维持预付金率y,供交易确认书、预付金计算等消费点统一使用。
/// 匹配维度:生效日期(ValueDate 最新)→ 利率债期限档(SpanConfig.BondTerm,四档,空=全部兜底)→ 标的资产类型(UnderlyingType 标志位)。
/// </summary>
public static class MarginTemplateV2RateHelper
{
/// <summary>
/// 取数结果。率已统一换算为小数(如 0.1 表示 10%),调用方直接用。
/// </summary>
public class MarginRateResult
{
/// <summary>
/// 命中的模板
/// </summary>
public margin_template_v2 Template { get; set; }
/// <summary>
/// 命中的明细参数行(无预付金规则时为 null)
/// </summary>
public margin_template_detail Detail { get; set; }
/// <summary>
/// 初始预付金率 x(小数)
/// </summary>
public decimal? InitRate { get; set; }
/// <summary>
/// 维持预付金率 y(小数)
/// </summary>
public decimal? MaintainRate { get; set; }
}
/// <summary>
/// 按交易绑定的模板取 初始/维持预付金率。
/// </summary>
/// <param name="tradeId">交易ID</param>
/// <param name="underlyingCode">标的代码(用于计算利率债期限档)</param>
/// <param name="underlyingInstrumentType">标的资产类型(trade/swap_position 的 UnderlyingInstrumentType,如 TBonds</param>
/// <param name="valueDate">业务日期</param>
/// <returns>命中返回结果;交易未绑定模板、模板无效、规则非 无预付金/区间追保结构、或明细无匹配行时返回 null(由调用方决定兜底)</returns>
public static MarginRateResult GetTradeMarginRate(int tradeId, string underlyingCode, string underlyingInstrumentType, DateTime valueDate)
{
using (var db = new YLContext())
{
return GetTradeMarginRate(tradeId, underlyingCode, underlyingInstrumentType, valueDate, db);
}
}
/// <summary>
/// 按交易绑定的模板取 初始/维持预付金率(调用方传入 DbContext,供批量场景复用连接)。
/// </summary>
public static MarginRateResult GetTradeMarginRate(int tradeId, string underlyingCode, string underlyingInstrumentType, DateTime valueDate, YLContext db)
{
//1.交易绑定(ValueDate 最新)
var binding = db.trade_margin_template.AsNoTracking()
.Where(x => x.TradeId == tradeId && x.ValueDate <= valueDate)
.OrderByDescending(x => x.ValueDate)
.FirstOrDefault();
if (binding == null)
{
return null;
}
var template = db.margin_template_v2.AsNoTracking().FirstOrDefault(x => x.id == binding.MarginTemplateId);
if (template == null || !template.IsValid)
{
return null;
}
//2.无预付金规则:率直接为 0
if (template.RuleType == (int)MarginRuleTypeEnum.无预付金)
{
return new MarginRateResult { Template = template, InitRate = 0m, MaintainRate = 0m };
}
if (template.RuleType != (int)MarginRuleTypeEnum.区间追保结构)
{
//其他规则不在本帮助类支持范围,显式返回 null
return null;
}
//3.区间追保结构:取 ValueDate 最新生效的一组明细(同一 ValueDate 下有多行参数组)
var detailQuery = db.margin_template_detail.AsNoTracking()
.Where(x => x.MarginTemplateId == template.id && x.ValueDate <= valueDate);
if (!detailQuery.Any())
{
return null;
}
var latestValueDate = detailQuery.Max(x => x.ValueDate);
var details = detailQuery.Where(x => x.ValueDate == latestValueDate).ToList();
//4.利率债期限档匹配:精确档 → "全部"BondTerm 为空)兜底
var term = UnderlyingHelper.GetApplicableMarginTerm(underlyingCode, valueDate);
var matched = details.Where(x => x.SpanConfig != null && x.SpanConfig.BondTerm == term).ToList();
if (!matched.Any())
{
matched = details.Where(x => x.SpanConfig == null || string.IsNullOrEmpty(x.SpanConfig.BondTerm)).ToList();
}
if (!matched.Any())
{
return null;
}
//5.标的资产类型匹配(仅当模板选了"按资产类型分类"):精确标志位 → 通配行(None/All)兜底
if (template.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType
&& Enum.TryParse<UnderlyingTypeEnum>(underlyingInstrumentType, out var instrumentFlag))
{
var byInstrument = matched.Where(x => (x.UnderlyingType & instrumentFlag) > 0).ToList();
if (byInstrument.Any())
{
matched = byInstrument;
}
else
{
var wildcard = matched.Where(x => x.UnderlyingType == UnderlyingTypeEnum.None || x.UnderlyingType == UnderlyingTypeEnum.All).ToList();
if (wildcard.Any())
{
matched = wildcard;
}
}
}
var detail = matched.First();
return new MarginRateResult
{
Template = template,
Detail = detail,
InitRate = ToDecimalRate(detail.MarginRatio1),
MaintainRate = ToDecimalRate(detail.MarginRatio2)
};
}
/// <summary>
/// 模板页录入的百分数(如 10 表示 10%)换算为小数(0.1)
/// </summary>
private static decimal? ToDecimalRate(double? ratio)
{
return ratio.HasValue ? (decimal)(ratio.Value / 100d) : (decimal?)null;
}
}
}