此前 AIcoding 第 1~3 步的产出仅存在于本地磁盘、未纳入版本库,本次一次性入库, 补齐「设计可追溯」。本提交为纯文档 + 一个实算脚本,**代码零改动**,接口契约与表结构不变。 入库 6 个文件: - docs/PRD/PRD-基金转换交易.md(v0.9 · 需求权威:FR-C1~C16 / §4 表结构 / §5 接口 / §9 验收) - docs/项目框架设计/架构设计-基金转换交易.md(v1.0 · 实现依据:D1~D20 / §5 事务补偿 / §11.1 DB 账号分离 / §15 任务映射 T-0~T-13 与 §15.1 依赖拓扑) - docs/项目框架设计/基金转换-审查意见处置表.md(33 条外审处置 + §九 用户拍板记录) - docs/项目框架设计/评审待办-风控主架构与基金转换.md(评审逐条判定 + 核实证据) - docs/交接文档-基金转换.md(本线交接入口,读完即可开工) - scripts/dev/calc_convert_demo.py(PRD §5.3 主示例实算回填脚本——派生值禁手算) 门控:PRD 已定稿并经独立评审闭环(M-7 已满足);架构 v1.0 独立评审 13 条建议 0 悬空。 下一步:AIcoding 第 4 步「产出开发计划」,输入为架构 §15 / §15.1。
99 lines
4.5 KiB
Python
99 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""基金转换主示例实算(PRD §5.3 数值来源)。
|
||
|
||
用途:PRD §5.3 响应示例中的**所有派生金额/份额**,必须由本脚本算出后回填,
|
||
**禁止手算**——v0.7 曾两次因手算与口径不符被外部审查质疑(见处置表 T-2b / 自检第 9 问)。
|
||
|
||
公式与 PRD §2.1 / §2.1.1 / §2.1.3 / §2.5 完全一致:
|
||
转出金额 = Σ(各批次份额 × 转出净值)
|
||
赎回费 = Σ(各批次金额 × 该批适用赎回费率) # 逐批次先舍入、后求和
|
||
转换金额 = 转出金额 − 赎回费
|
||
补差费(B) = Max[ 转换金额×转入费率/(1+转入费率)
|
||
− 转换金额×转出费率/(1+转出费率), 0 ] # 价外法两端差(本期默认)
|
||
补差费(A) = 转换金额 × max(转入费率−转出费率,0) / (1+补差费率) # 费率差法(配置保留)
|
||
转入金额 = 转换金额 − 补差费
|
||
转入份额 = 转入金额 ÷ 转入净值 # 2 位,ROUND_HALF_UP
|
||
|
||
运行:<托管 Python> scripts/dev/calc_convert_demo.py
|
||
"""
|
||
from decimal import Decimal, ROUND_HALF_UP
|
||
|
||
TWO = Decimal("0.01")
|
||
FOUR = Decimal("0.0001")
|
||
|
||
|
||
def q2(x: Decimal) -> Decimal:
|
||
"""金额/份额统一保留 2 位、四舍五入(显式 ROUND_HALF_UP,禁用默认 HALF_EVEN)。"""
|
||
return x.quantize(TWO, rounding=ROUND_HALF_UP)
|
||
|
||
|
||
def main() -> None:
|
||
# —— 主示例输入(与 §5.3 / §4.3 种子一致)——
|
||
lots = [
|
||
# (份额, 持有天数, 该批赎回费率) —— 费率来自 §2.1.3 分档表
|
||
(Decimal("30000"), 100, Decimal("0.0050")), # [30,180) 日 → 0.5%
|
||
(Decimal("20000"), 3, Decimal("0.0150")), # [0,7) 日 → 1.5%
|
||
]
|
||
nav_out = Decimal("1.03") # PROD-110022 债基 转出净值
|
||
nav_in = Decimal("0.95") # PROD-005827 主动偏股 转入净值
|
||
fee_out = Decimal("0.0030") # 转出端申购费率(债基,22 号文 §8 上限 0.3%)
|
||
fee_in = Decimal("0.0080") # 转入端申购费率(主动偏股,上限 0.8%)
|
||
|
||
out_amount = Decimal("0")
|
||
redeem_fee = Decimal("0")
|
||
detail = []
|
||
for qty, days, rate in lots:
|
||
amt = q2(qty * nav_out)
|
||
fee = q2(amt * rate)
|
||
out_amount += amt
|
||
redeem_fee += fee
|
||
detail.append((qty, days, rate, amt, fee))
|
||
|
||
convert_amount = q2(out_amount - redeem_fee)
|
||
|
||
# —— 口径 B:价外法两端差(本期默认)——
|
||
sub_in = convert_amount * fee_in / (Decimal("1") + fee_in)
|
||
sub_out = convert_amount * fee_out / (Decimal("1") + fee_out)
|
||
diff_b = q2(max(sub_in - sub_out, Decimal("0")))
|
||
in_amount = q2(convert_amount - diff_b)
|
||
theoretical = in_amount / nav_in
|
||
in_qty = q2(theoretical)
|
||
rounding_diff = theoretical - in_qty
|
||
|
||
# —— 口径 A:费率差法(配置 convert_diff_fee_mode='rate_diff' 保留)——
|
||
rate_diff = max(fee_in - fee_out, Decimal("0"))
|
||
diff_a = q2(convert_amount * rate_diff / (Decimal("1") + rate_diff))
|
||
in_qty_a = q2(q2(convert_amount - diff_a) / nav_in)
|
||
|
||
# —— 同费率对照(补差 = 0),用于 §9 第 19 条 ——
|
||
same_rate = Decimal("0.0030")
|
||
diff_same = q2(max(convert_amount * same_rate / (Decimal("1") + same_rate)
|
||
- convert_amount * same_rate / (Decimal("1") + same_rate),
|
||
Decimal("0")))
|
||
in_amount_same = q2(convert_amount - diff_same)
|
||
in_qty_same = q2(in_amount_same / nav_in)
|
||
|
||
print("=== 主示例(口径 B)===")
|
||
for qty, days, rate, amt, fee in detail:
|
||
print(f"批次 {qty} 份 / {days} 天 / 费率 {rate} -> amount={amt} fee={fee}")
|
||
print(f"out_amount = {out_amount}")
|
||
print(f"redeem_fee = {redeem_fee}")
|
||
print(f"convert_amount = {convert_amount}")
|
||
print(f" (转入端申购费) = {sub_in.quantize(FOUR)} -> q2 {q2(sub_in)}")
|
||
print(f" (转出端申购费) = {sub_out.quantize(FOUR)} -> q2 {q2(sub_out)}")
|
||
print(f"diff_fee(B) = {diff_b}")
|
||
print(f"in_amount = {in_amount}")
|
||
print(f"in_qty = {in_qty}")
|
||
print(f"rounding_diff = {rounding_diff.quantize(FOUR)} (理论 {theoretical.quantize(FOUR)} - 实际 {in_qty})")
|
||
print()
|
||
print("=== 对照:口径 A(费率差法)===")
|
||
print(f"diff_fee(A) = {diff_a}")
|
||
print(f"in_qty(A) = {in_qty_a}")
|
||
print()
|
||
print("=== 同费率对照(两端 0.0030,补差 = 0)===")
|
||
print(f"diff_fee={diff_same} in_amount={in_amount_same} in_qty={in_qty_same}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|