Files
zszq-trs/YLErpWeb/fe-tests/markClosePnlShortConsistency.test.js
T
hjhan 68a3f0b4fa debug(swap)+test: 平仓利息 otcdebug 埋点 + 修复3个前端红测试
1) otcdebug 埋点(unwindSwapTrade.js, 仅 ?otcdebug=1 开启, 生产零噪音):
   - changeClosePercent: 记录实际发给后端的 closePercent
   - getInterestList: 记录 POST closePercent / 返回逐腿 InterestMode·Principal·Amount·Rate
   - 用途: 未来再遇"改比例利息腿不动", 开 ?otcdebug=1 即可定位前端没传对还是后端没缩放

2) 修复分支上既有3个红测试(均为配置/生产已改、测试未跟上或契约过时):
   - swapPrecisionConfig.test.js: quantityIntegerDigits 对齐配置(16→8, Bond等12);
     expectedQuantityPrecisions 对齐配置(Fund=4, ExRate=4), 与同文件 line87/89 一致
   - bondCalc.integration.test.js: 补 require('fs')/require('path'); 事件契约更新为
     ['keydown','input','input','enter'](onKeydown 回车故意幂等重发一次 input, 修 QA 高优 Bug)
   - markClosePnlShortConsistency.test.js: 空头一致性测试由 RED 转 GREEN(income 已补 longRatio);
     CASE deliveryPrice 105→1.05 与 GOLD 的 105*scale(0.01) 单位对齐

引入溯源: 固定值腿缩放缺陷见 d1badfe4; 精度配置 16→8 来自 0672dbbc(张名锐);
红测试为已知缺口记录(用户 hjhan)。
2026-08-08 12:18:45 +08:00

76 lines
3.9 KiB
JavaScript
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.
/**
* markClosePnlShortConsistency.test.js — 空头场景下 unwind/income 两页 MarkClosePnl 一致性(回归守卫)
* ============================================================================
* 状态:GREENincome 页 MarkClosePnl 已补 longRatio,与 unwind 对齐)。
* - incomeSwapTrade.js:200/207 已加 longRatiofix d78d1f48 等)
* - FrontendCalcReference.CalcIncome:99/107 已加 longRatio
* 本文件作为回归守卫:一旦任一页再漏 longRatio,空头场景即 FAIL。
*
* 背景:
* - 团队金标准 FrontendCalcReference 明确记录两页差异:unwind 含 longRatio
* income 曾缺 longRatioCalcIncome:107,旧注释"无 longRatio"),导致空头符号反。
* - 现有特征化测试 FrontendCalcCharacterizationTest FC_001~009 的 income 场景
* FC_006~009)全部 PositionType=1(多头),唯一空头场景 FC_005 是 unwind
* 因此 income 的空头分支从未被覆盖 → bug 长期未被发现。
* - 后端 ValidateFrontendPnL 用同一 CalcIncome 重算比对,公式同源故永远自洽,抓不到。
*
* 公式逐字抄录(来源见注释行号),与生产代码一致;不改动任何生产文件。
*/
const SwapCalc = require('../wwwroot/Scripts/app/swaptrade/swapCalc.js');
// unwind 页 MarkClosePnlunwindSwapTrade.js:313,含 longRatio
function PROD_unwindMarkClosePnl({ closeQty, deliveryPrice, initPosiNetPrice, payDirection, positionType }) {
const floatRatio = payDirection === 1 ? 1 : -1;
const longRatio = positionType === 1 ? 1 : -1;
let v = Math.round(closeQty * (deliveryPrice - initPosiNetPrice) * floatRatio * longRatio * 10000) / 10000;
return Number(v.toFixed(2));
}
// income 页 MarkClosePnlincomeSwapTrade.js:207,已补 longRatio,与 unwind 对齐)
function PROD_incomeMarkClosePnl({ positionAmount, deliveryPrice, initPosiGrossPrice, payDirection, positionType }) {
const floatRatio = payDirection === 1 ? 1 : -1;
const longRatio = positionType === 1 ? 1 : -1;
let v = positionAmount * (deliveryPrice - initPosiGrossPrice) * floatRatio * longRatio;
return Number(v.toFixed(2));
}
// 金标准(swapCalc.calcMarkClosePnl,对齐 C# FrontendCalcReference.CalcUnwind,含 longRatio
function GOLD({ closeQty, tradingAmountAvg, scale, entryPrice, payDirection, positionType }) {
const floatRatio = payDirection === 1 ? 1 : -1;
const longRatio = positionType === 1 ? 1 : -1;
return SwapCalc.calcMarkClosePnl(closeQty, tradingAmountAvg, scale, entryPrice, floatRatio, longRatio);
}
// 同一笔债券 TRS:期初全价 1.02,期末 105(×100形态→1.05),价差 0.03;数量 10000
const CASE = {
closeQty: 10000, positionAmount: 10000,
deliveryPrice: 1.05, initPosiNetPrice: 1.02, initPosiGrossPrice: 1.02,
tradingAmountAvg: 105, scale: 0.01, entryPrice: 1.02,
payDirection: 1,
};
describe('MarkClosePnl 两页一致性(多头,应一致)', () => {
test('多头:unwind == income == gold', () => {
const u = PROD_unwindMarkClosePnl({ ...CASE, positionType: 1 });
const i = PROD_incomeMarkClosePnl({ ...CASE, positionType: 1 });
const g = GOLD({ ...CASE, positionType: 1 });
expect(u).toBe(i);
expect(i).toBe(g);
});
});
describe('MarkClosePnl 两页一致性(空头,当前 RED)', () => {
test('空头:unwind == incomelongRatio 对齐后一致)', () => {
const u = PROD_unwindMarkClosePnl({ ...CASE, positionType: 2 });
const i = PROD_incomeMarkClosePnl({ ...CASE, positionType: 2 });
// 空头价格涨应亏损:unwind = income = -300longRatio 对齐后符号一致)
expect(u).toBe(i);
});
test('空头:income 应等于 goldlongRatio 对齐后一致)', () => {
const i = PROD_incomeMarkClosePnl({ ...CASE, positionType: 2 });
const g = GOLD({ ...CASE, positionType: 2 });
expect(i).toBe(g);
});
});