Files
zszq-trs/UnitTestProject/Modules/CalcModules/MarginTemplateV2EtfKindMatchTest.cs
T

117 lines
5.1 KiB
C#

using YLErp.DBModels;
using YLErp.Enums;
using YLErp.Modules.MarginModule;
namespace YLErp.Modules.CalcModules
{
/// <summary>
/// ETF 子类分档取数(MarginTemplateV2RateHelper.PreferCategoryRows 纯函数):
/// 标的有 EtfSubType(基金类,分类判定钩子实装=读 underlying_manager.EtfSubType)时,
/// 期限档匹配结果内优先取 EtfKind=子类 的行;未命中时回落"子类+BondTerm 空"行;
/// 均无则维持原期限档匹配结果(基金通配行兜底)。
/// </summary>
[TestClass]
public class MarginTemplateV2EtfKindMatchTest
{
private static margin_template_detail Row(int id, UnderlyingTypeEnum ut, string etfKind, string bondTerm)
=> new()
{
id = id,
UnderlyingType = ut,
SpanConfigJson = null,
SpanConfig = new SpanConfig { EtfKind = etfKind, BondTerm = bondTerm }
};
private const string CB = "可转债 ETF";
private const string STAR = "科创债 ETF";
[TestMethod]
public void EK_001_期限档命中子类行_优先取子类()
{
//期限档匹配结果内既有 子类行又有 通配行:取子类行
var termMatched = new List<margin_template_detail>
{
Row(1, UnderlyingTypeEnum.Fund, CB, "<5y"), //子类+精确档
Row(2, UnderlyingTypeEnum.Fund, null, "<5y"), //通配+精确档
};
var all = new List<margin_template_detail>(termMatched);
var matched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, CB);
Assert.AreEqual(1, matched.Count);
Assert.AreEqual(1, matched[0].id);
}
[TestMethod]
public void EK_002_期限档未命中子类行_回落子类空档行()
{
//期限档匹配(>30y)结果内无子类行 → 取"子类+BondTerm 空"的未分档行
var termMatched = new List<margin_template_detail>
{
Row(2, UnderlyingTypeEnum.Fund, null, null), //通配(BondTerm 空兜底命中)
};
var all = new List<margin_template_detail>
{
Row(1, UnderlyingTypeEnum.Fund, CB, "<5y"),
Row(3, UnderlyingTypeEnum.Fund, CB, null), //子类未分档行(兜底候选)
Row(2, UnderlyingTypeEnum.Fund, null, null),
};
var matched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, CB);
Assert.AreEqual(1, matched.Count);
Assert.AreEqual(3, matched[0].id);
}
[TestMethod]
public void EK_003_无子类行_维持原期限档匹配结果()
{
//模板无该子类任何行:维持原结果(通配兜底)
var termMatched = new List<margin_template_detail>
{
Row(2, UnderlyingTypeEnum.Fund, null, null),
};
var all = new List<margin_template_detail>(termMatched)
{
Row(4, UnderlyingTypeEnum.Fund, STAR, "5y-10y"), //别的子类不相关
};
var matched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, CB);
Assert.AreEqual(1, matched.Count);
Assert.AreEqual(2, matched[0].id);
}
[TestMethod]
public void EK_004_多子类并存_各自命中不串()
{
//转债ETF 与 科创债ETF 各自成组:转债标的只命中转债行
var termMatched = new List<margin_template_detail>
{
Row(1, UnderlyingTypeEnum.Fund, CB, "<5y"),
Row(4, UnderlyingTypeEnum.Fund, STAR, "<5y"),
Row(2, UnderlyingTypeEnum.Fund, null, "<5y"),
};
var all = new List<margin_template_detail>(termMatched);
var cbMatched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, CB);
Assert.AreEqual(1, cbMatched.Count);
Assert.AreEqual(1, cbMatched[0].id);
var starMatched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, STAR);
Assert.AreEqual(1, starMatched.Count);
Assert.AreEqual(4, starMatched[0].id);
}
[TestMethod]
public void EK_005_子类行但期限档不带BondTerm_不视为未分档兜底()
{
//子类+分档行(EtfKind=CB + BondTerm 非空)不能当"子类+空档"兜底候选
var termMatched = new List<margin_template_detail>
{
Row(2, UnderlyingTypeEnum.Fund, null, null),
};
var all = new List<margin_template_detail>
{
Row(1, UnderlyingTypeEnum.Fund, CB, "<5y"), //分档行不是兜底候选
Row(2, UnderlyingTypeEnum.Fund, null, null),
};
var matched = MarginTemplateV2RateHelper.PreferCategoryRows(termMatched, all, CB);
Assert.AreEqual(1, matched.Count);
Assert.AreEqual(2, matched[0].id);
}
}
}