|
@@ -432,23 +432,85 @@ def test_null_finance_rate_with_zero_cost_skips_interest_line() -> None:
|
|
|
assert F_MONTHLY_RATE not in formulas
|
|
assert F_MONTHLY_RATE not in formulas
|
|
|
|
|
|
|
|
|
|
|
|
|
-def test_interest_without_year_days_is_suspect() -> None:
|
|
|
|
|
|
|
+def test_empty_cleared_position_market_value_is_zero() -> None:
|
|
|
|
|
+ """无 clr_user_position 键时持仓市值合计为 0,与报表 0 对齐为正确。"""
|
|
|
|
|
+
|
|
|
|
|
+ data = _data(
|
|
|
|
|
+ profile=_profile(
|
|
|
|
|
+ available_amt=Decimal("10"),
|
|
|
|
|
+ frozen_amt=Decimal("0"),
|
|
|
|
|
+ position_mv=Decimal("0"),
|
|
|
|
|
+ total_asset=Decimal("10"),
|
|
|
|
|
+ total_float_pnl=Decimal("-20"),
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ data["trs_users"]["U1"]["clr_fund_account"] = [
|
|
|
|
|
+ {"user_id": 1, "ccy": "CNY", "available": Decimal("10"), "frozen": Decimal("0")}
|
|
|
|
|
+ ]
|
|
|
|
|
+ data["trs_users"]["U1"]["reports"][T_TRS014] = [
|
|
|
|
|
+ {
|
|
|
|
|
+ "id": 1,
|
|
|
|
|
+ "business_date": DAY,
|
|
|
|
|
+ "account": "U1",
|
|
|
|
|
+ "settle_ccy": "CNY",
|
|
|
|
|
+ "position_mv": Decimal("0"),
|
|
|
|
|
+ "total_asset": Decimal("10"),
|
|
|
|
|
+ "credit_principal": Decimal("0"),
|
|
|
|
|
+ "payable_interest": Decimal("0"),
|
|
|
|
|
+ "net_asset": Decimal("10"),
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ lines = check_trs_reports(data)
|
|
|
|
|
+ profile_mv = [line for line in lines if line.formula_text == "持仓市值 = 用户资金与持仓汇总"]
|
|
|
|
|
+ daily_mv = _exact(lines, "持仓市值 = 清算持仓市值合计")
|
|
|
|
|
+ assert len(profile_mv) == 1
|
|
|
|
|
+ assert profile_mv[0].verdict == "correct"
|
|
|
|
|
+ assert profile_mv[0].calc_value == Decimal("0.00")
|
|
|
|
|
+ assert daily_mv.verdict == "correct"
|
|
|
|
|
+ assert daily_mv.calc_value == Decimal("0.00")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_interest_cny_uses_360_and_percent_rate() -> None:
|
|
|
|
|
+ """CNY:成本 × 利率 / 100 / 360。"""
|
|
|
|
|
+
|
|
|
data = _data()
|
|
data = _data()
|
|
|
- data["trs_users"]["U1"]["reports"][T_TRS016] = [_interest_row()]
|
|
|
|
|
|
|
+ data["trs_users"]["U1"]["reports"][T_TRS016] = [
|
|
|
|
|
+ _interest_row(holding_cost=Decimal("36000"), finance_rate=Decimal("1"), interest=Decimal("1"))
|
|
|
|
|
+ ]
|
|
|
line = _exact(check_trs_reports(data), F_INTEREST)
|
|
line = _exact(check_trs_reports(data), F_INTEREST)
|
|
|
- assert line.verdict == "suspect"
|
|
|
|
|
- assert line.calc_value is None
|
|
|
|
|
- assert "年天数缺失" in line.calc_text
|
|
|
|
|
|
|
+ assert line.verdict == "correct"
|
|
|
|
|
+ assert line.calc_value == Decimal("1.00")
|
|
|
|
|
+ assert line.check_value == Decimal("1.00")
|
|
|
|
|
+ assert "/ 100 / 360" in line.calc_text
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
+def test_interest_hkd_uses_365_and_percent_rate() -> None:
|
|
|
|
|
+ """HKD:成本 × 利率 / 100 / 365。"""
|
|
|
|
|
|
|
|
-def test_interest_uses_given_year_days() -> None:
|
|
|
|
|
data = _data()
|
|
data = _data()
|
|
|
- data["year_days"] = Decimal("365")
|
|
|
|
|
- data["trs_users"]["U1"]["reports"][T_TRS016] = [_interest_row(interest=Decimal("1"))]
|
|
|
|
|
|
|
+ data["trs_users"]["U1"]["reports"][T_TRS016] = [
|
|
|
|
|
+ _interest_row(
|
|
|
|
|
+ settle_ccy="HKD",
|
|
|
|
|
+ holding_cost=Decimal("36500"),
|
|
|
|
|
+ finance_rate=Decimal("1"),
|
|
|
|
|
+ interest=Decimal("1"),
|
|
|
|
|
+ )
|
|
|
|
|
+ ]
|
|
|
line = _exact(check_trs_reports(data), F_INTEREST)
|
|
line = _exact(check_trs_reports(data), F_INTEREST)
|
|
|
assert line.verdict == "correct"
|
|
assert line.verdict == "correct"
|
|
|
assert line.calc_value == Decimal("1.00")
|
|
assert line.calc_value == Decimal("1.00")
|
|
|
- assert line.check_value == Decimal("1.00")
|
|
|
|
|
|
|
+ assert "/ 100 / 365" in line.calc_text
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_interest_unsupported_ccy_is_suspect() -> None:
|
|
|
|
|
+ data = _data()
|
|
|
|
|
+ data["trs_users"]["U1"]["reports"][T_TRS016] = [
|
|
|
|
|
+ _interest_row(settle_ccy="USD", interest=Decimal("1"))
|
|
|
|
|
+ ]
|
|
|
|
|
+ line = _exact(check_trs_reports(data), F_INTEREST)
|
|
|
|
|
+ assert line.verdict == "suspect"
|
|
|
|
|
+ assert line.calc_value is None
|
|
|
|
|
+ assert "不支持年天数" in line.calc_text
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_does_not_emit_trs015() -> None:
|
|
def test_does_not_emit_trs015() -> None:
|
|
@@ -995,13 +1057,19 @@ def _profile(**overrides: object) -> dict:
|
|
|
return row
|
|
return row
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _interest_row(interest: Decimal | None = Decimal("9")) -> dict:
|
|
|
|
|
|
|
+def _interest_row(
|
|
|
|
|
+ interest: Decimal | None = Decimal("1"),
|
|
|
|
|
+ *,
|
|
|
|
|
+ settle_ccy: str = "CNY",
|
|
|
|
|
+ holding_cost: Decimal = Decimal("36000"),
|
|
|
|
|
+ finance_rate: Decimal = Decimal("1"),
|
|
|
|
|
+) -> dict:
|
|
|
return {
|
|
return {
|
|
|
"id": 9,
|
|
"id": 9,
|
|
|
"nature_date": DAY,
|
|
"nature_date": DAY,
|
|
|
"account": "U1",
|
|
"account": "U1",
|
|
|
- "settle_ccy": "CNY",
|
|
|
|
|
- "holding_cost": Decimal("365"),
|
|
|
|
|
- "finance_rate": Decimal("1"),
|
|
|
|
|
|
|
+ "settle_ccy": settle_ccy,
|
|
|
|
|
+ "holding_cost": holding_cost,
|
|
|
|
|
+ "finance_rate": finance_rate,
|
|
|
"interest": interest,
|
|
"interest": interest,
|
|
|
}
|
|
}
|