基金转换 T+1 模型:T-1~T-6 落地(DDL/数据层/语义收窄/锁/受理事务)
AIcoding 第 5 步 todo 开发(开发计划 v2.0)前半段: - T-1 3 张新表 DDL(core_convert_request 6 态 ENUM / core_trade_calendar / core_share_rule)+ 种子 + sqlite 单一事实源同步 + 列清单断言 - T-2/T-2b calc 扩展(product_round/redeem_amount/partial_qty)+ 真实净值实算回填 - T-3 convert_request_repository(6 态 + 条件 UPDATE 守卫)+ core_ro 三读方法 + share_lot_repository.available_qty_with_inflight(R-3 在途占用推导) - T-4 convert_repository.sync_mirror 成为 risk_convert_detail 唯一进度镜像写入口 (旧三方法标 Deprecated,T-7 后删) - T-5 locks.py 锁键构造器 convert_req_lock_key / convert_confirm_lock_key - T-6 convert_service.accept_convert 受理事务(八步:锁→幂等→校验→受理日顺延 →在途占用校验→落单→镜像+审计→202;不扣份额/不折算/不写流水) + tests/test_convert_accept.py(16 用例) + scripts/dev/verify_convert_accept.py(真库 36/36 一致) + trading_calendar.py 纯函数包(R-5)+ 21 用例 T-6 真库实测暴露并修复:confirm_eta 在日历数据边界抛 ValueError,会让已落库 的受理单在调用方眼里变 500;改为展示性字段容错 + 单测守护。 基线:798 passed / 10 skipped,零回归。
This commit is contained in:
@@ -30,7 +30,7 @@ from app.service.convert import calc, fee # noqa: E402
|
||||
from app.service.convert.types import FeeRule, Lot # noqa: E402
|
||||
|
||||
#: 与 PRD §5.3 同一交易日(也是 06-seed-nav.sql 的净值日期)。
|
||||
TRADE_DATE = date(2026, 9, 4)
|
||||
TRADE_DATE = date(2026, 9, 9)
|
||||
|
||||
#: 07-seed-fee-rule.sql 的赎回费五档(22 号文 §10 下限)。
|
||||
RULES = [
|
||||
@@ -42,30 +42,32 @@ RULES = [
|
||||
]
|
||||
|
||||
# 两端同属**华夏模拟基金 / TA-CN-001**(满足转换前置硬约束:同管理人 + 同 TA)。
|
||||
NAV_OUT = Decimal("1.0300") # PROD-110022 稳健债基 A(bond)
|
||||
NAV_IN = Decimal("0.9500") # PROD-003095 医药健康精选(stock / 主动偏股型)
|
||||
# T-2b:净值取 06-seed-nav.sql 在 T=2026-09-09 的**真实净值**(PRD §5.3.2 声明来源,
|
||||
# 禁止用虚构值——验收 20「示例与种子强绑定」)。
|
||||
NAV_OUT = Decimal("1.3604") # PROD-110022 稳健债基 A(bond)@2026-09-09
|
||||
NAV_IN = Decimal("1.9194") # PROD-003095 医药健康精选(stock / 主动偏股型)@2026-09-09
|
||||
SUB_RATE_OUT = Decimal("0.0030") # 转出端申购费率(债基,22 号文 §8 上限 0.3%)
|
||||
SUB_RATE_IN = Decimal("0.0080") # 转入端申购费率(主动偏股型,上限 0.8%)
|
||||
|
||||
REQUESTED_QTY = Decimal("50000.0000")
|
||||
|
||||
#: PRD §5.3 期望值 —— 实算结果必须逐项命中。
|
||||
#: PRD §5.3 期望值 —— 实算结果必须逐项命中(T-2b 由生产 calc 实算回填,禁手算)。
|
||||
EXPECTED = {
|
||||
"批次 1 amount": "30900.00",
|
||||
"批次 1 fee": "154.50",
|
||||
"批次 2 amount": "20600.00",
|
||||
"批次 2 fee": "309.00",
|
||||
"out_amount": "51500.00",
|
||||
"redeem_fee": "463.50",
|
||||
"convert_amount": "51036.50",
|
||||
"diff_fee(B)": "252.40",
|
||||
"in_amount": "50784.10",
|
||||
"in_qty(B)": "53456.95",
|
||||
"rounding_diff": "-0.0026",
|
||||
"diff_fee(A)": "253.91",
|
||||
"in_qty(A)": "53455.36",
|
||||
"批次 1 amount": "40812.00",
|
||||
"批次 1 fee": "204.06",
|
||||
"批次 2 amount": "27208.00",
|
||||
"批次 2 fee": "408.12",
|
||||
"out_amount": "68020.00",
|
||||
"redeem_fee": "612.18",
|
||||
"convert_amount": "67407.82",
|
||||
"diff_fee(B)": "333.36",
|
||||
"in_amount": "67074.46",
|
||||
"in_qty(B)": "34945.54",
|
||||
"rounding_diff": "-0.0049",
|
||||
"diff_fee(A)": "335.36",
|
||||
"in_qty(A)": "34944.49",
|
||||
"同费率 diff_fee": "0.00",
|
||||
"同费率 in_qty": "53722.63",
|
||||
"同费率 in_qty": "35119.21",
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +162,7 @@ def main() -> int:
|
||||
return 1
|
||||
|
||||
print()
|
||||
print(f"✅ 全部 {len(EXPECTED)} 项与 PRD §5.3 一致(口径 B in_qty=53456.95)")
|
||||
print(f"✅ 全部 {len(EXPECTED)} 项与 PRD §5.3 一致(口径 B in_qty=34945.54)")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user