feat(web): EQD-6953 前端值域闸门补疑似到期债券判定——ytm=0且净/全价均为面值100三者同时成立(现实在市券几乎不可能,UAT 060203.IB实证jquantlib空现金流退化形态)时按既有'不回写+toast真实原因'处理,提示核对到期日或手工填写;录入页/平仓页共用此闸门同步生效;判定条件与后端BondCalcHepler.IsMaturedDegenerate同口径(注释已互指);新增4个jest用例(命中/正常券/ytm=0但价格非面值/价格面值但ytm非0)61/61通过

This commit is contained in:
hjhan
2026-08-21 15:26:46 +08:00
parent 38e0a7795f
commit cd981527ab
2 changed files with 25 additions and 0 deletions
+18
View File
@@ -120,6 +120,24 @@ describe('边界:计算器未返回的值不覆盖、无变化不写', () => {
});
});
describe('疑似到期债券值域闸门:ytm=0 且 净/全价均为面值100UAT 060203.IB 实证的退化形态)', () => {
test('三条件同时成立 → 命中闸门返回真实原因(不回写)', () => {
const resp = { cleanPrice: 100, dirtyPrice: 100, ytm: 0 };
const msg = SwapCalc.getBondCalcErrorMessage(resp);
expect(msg).toContain('疑似已到期');
expect(msg).toContain('手工填写');
});
test('正常券不命中 → 返回 null 放行回写', () => {
expect(SwapCalc.getBondCalcErrorMessage({ cleanPrice: 97.43, dirtyPrice: 100.00001369863016, ytm: 6.738278242318886 })).toBeNull();
});
test('ytm=0 但价格非面值(真实零息平价券)→ 不命中', () => {
expect(SwapCalc.getBondCalcErrorMessage({ cleanPrice: 99.5, dirtyPrice: 100, ytm: 0 })).toBeNull();
});
test('价格=面值 但 ytm 非 0(正常息票平价券)→ 不命中', () => {
expect(SwapCalc.getBondCalcErrorMessage({ cleanPrice: 100, dirtyPrice: 100.5, ytm: 3.2 })).toBeNull();
});
});
describe('错误反馈:getBondCalcErrorMessage(对齐 C# BondCalcHepler 的 errCode 守卫)', () => {
test('空响应 → 提示"无响应",且绝不回写', () => {
expect(SwapCalc.getBondCalcErrorMessage(null)).toBe("债券计算器无响应,已保留手工输入");
@@ -352,6 +352,13 @@
return "债券计算收益率量级异常(" + yd + "),已保留手工输入;" +
"请检查估值日/价格输入或联系管理员核对债券计算服务";
}
// 疑似到期/无剩余现金流:估值日过到期日后 jquantlib 对空现金流求解得 ytm=0、净/全价均为面值100
// (三者同时成立在现实在市券中几乎不可能,UAT 060203.IB 实证)。宁可不回写并提示真实原因,
// 也不用退化值覆盖手工输入。与后端 BondCalcHepler.IsMaturedDegenerate 同口径,勿单边改动判定条件。
if (yd === 0 && cp === 100 && dp === 100) {
return "该债券疑似已到期或无剩余现金流(收益率=0、净价/全价均为面值100),无法反算," +
"请核对债券到期日或手工填写净价/全价/收益率";
}
return null;
}