117 lines
5.1 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|