fix 部分平仓 选择切换 会导致不一致,浮动端会错误

This commit is contained in:
hjhan
2026-07-16 20:57:18 +08:00
parent cd9fed9913
commit 62c26bd7f5
3 changed files with 104 additions and 7 deletions
+60
View File
@@ -101,6 +101,66 @@ describe('多次部分平仓:比例↔名义本金换算以 PosiNotionalValue
});
});
// ============================================================================
// 多次部分平仓:全部↔部分切换时 CloseQty 不应随 ClosePercent 口径变化而跳变
// 守卫 unwindSwapTrade.js changeCloseMethod/changeClosePercent/changeCloseQty/changeCloseNotionalValue
// 旧 bugClosePercent 是占期初口径(A),但 CloseQty=PositionQty*ClosePercent 错当占剩余(B)用
// 全部(ClosePercent=0.7,CloseQty=720000) → 部分(ClosePercent没变, CloseQty=504000) ❌ 跳变
// 修复:CloseQty = PositionQty × (ClosePercent / oriClosePercent)
// ============================================================================
describe('多次部分平仓:全部↔部分切换 CloseQty 不跳变(占期初口径自洽)', () => {
// 场景基于 GLMS-20260701-0013
// 期初 NotionalValue=980000,已平两次剩 PosiNotionalValue=686000, PositionQty=720000
// oriClosePercent = 686000/980000 = 0.7
const NotionalValue = 980000;
const PosiNotionalValue = 686000;
const PositionQty = 720000;
const oriClosePercent = PosiNotionalValue / NotionalValue; // 0.7
test('全部平仓 ClosePercent=0.7 → CloseQty=720000(剩余全部)', () => {
const closePercent = oriClosePercent; // 全部平仓 = oriClosePercent
const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
expectClose(closeQty, 720000, '全部平仓应平剩余全部数量');
});
test('全部→部分切换(ClosePercent 没变=0.7):CloseQty 应保持 720000 不跳变', () => {
// 旧 bugCloseQty = 720000 * 0.7 = 504000(错误跳变)
// 修复:CloseQty = 720000 * (0.7/0.7) = 720000(不变)
const closePercent = oriClosePercent;
const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
const buggyCloseQty = Math.round(PositionQty * closePercent * 100) / 100; // 旧 bug 公式
expectClose(closeQty, 720000, '修复后应不变');
expect(Math.abs(buggyCloseQty - 504000)).toBeLessThanOrEqual(TOL, '旧 bug 会跳变到 504000');
expect(Math.abs(closeQty - buggyCloseQty)).toBeGreaterThan(TOL, '修复与旧 bug 必须有差异');
});
test('改比例 0.5(占期初)→ CloseQty=720000×(0.5/0.7)=514285.71', () => {
const closePercent = 0.5;
const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
expectClose(closeQty, 514285.71, '占期初 50% 对应占剩余 71.43%,×720000=514285.71');
});
test('逆运算:CloseQty=514285.71 → ClosePercent=0.5(占期初)', () => {
const closeQty = 514285.71;
const closePercent = SwapCalc.calcOriginalClosePercentByQty(closeQty, PositionQty, oriClosePercent);
expectClose(closePercent, 0.5, '逆运算应还原为占期初 0.5');
});
test('逆运算自洽:CloseQty=720000=PositionQty)→ ClosePercent=0.7=oriClosePercent', () => {
const closeQty = PositionQty; // 720000
const closePercent = SwapCalc.calcOriginalClosePercentByQty(closeQty, PositionQty, oriClosePercent);
expectClose(closePercent, oriClosePercent, '平全部剩余 → ClosePercent=oriClosePercent');
});
test('除零保护:oriClosePercent=0(已全平完)→ CloseQty=0', () => {
expect(SwapCalc.calcCloseQtyByOriginalPercent(0.5, 0, 720000)).toBe(0);
});
test('除零保护:PositionQty=0 → ClosePercent=0', () => {
expect(SwapCalc.calcOriginalClosePercentByQty(100, 0, oriClosePercent)).toBe(0);
});
});
describe('交叉校验:对齐 C# FrontendCalcCharacterizationTest 金标准', () => {
// FC_001 平仓-债券多头-默认
test('FC_001 平仓 债券多头 默认', () => {