|
@@ -48,10 +48,12 @@ _ORDER_STATUSES = frozenset({"completed", "settled"})
|
|
|
_ISSUE_PRICE = "票据发行价(结算币种) = 当前票据面值(结算币种) + 发行费用(结算币种)"
|
|
_ISSUE_PRICE = "票据发行价(结算币种) = 当前票据面值(结算币种) + 发行费用(结算币种)"
|
|
|
_FLOAT = "浮动盈亏(结算币种) = 票据估值(结算币种) − 当前票据面值(结算币种) − 增额金额(结算币种)"
|
|
_FLOAT = "浮动盈亏(结算币种) = 票据估值(结算币种) − 当前票据面值(结算币种) − 增额金额(结算币种)"
|
|
|
_NAV = "票据价格/净值 = 票据估值(结算币种) / (当前票据面值(结算币种) + 增额金额(结算币种)) × 100"
|
|
_NAV = "票据价格/净值 = 票据估值(结算币种) / (当前票据面值(结算币种) + 增额金额(结算币种)) × 100"
|
|
|
|
|
+_SOLD_NAV = "票据价格/净值 = 合计卖出金额 / (合计卖出金额 − 合计卖出A类盈亏) × 100"
|
|
|
_VALUATION = (
|
|
_VALUATION = (
|
|
|
"票据估值(结算币种) = 底层资产浮动盈亏 > 0 时当前票据面值 + 增额金额 + "
|
|
"票据估值(结算币种) = 底层资产浮动盈亏 > 0 时当前票据面值 + 增额金额 + "
|
|
|
"底层资产浮动盈亏 × 收益比例,否则 MAX(0, 当前票据面值 + 增额金额 + 底层资产浮动盈亏)"
|
|
"底层资产浮动盈亏 × 收益比例,否则 MAX(0, 当前票据面值 + 增额金额 + 底层资产浮动盈亏)"
|
|
|
)
|
|
)
|
|
|
|
|
+_SOLD_VALUATION = "票据估值(结算币种) = 合计卖出金额"
|
|
|
_DIFF = "OTC005 共赢票据实时详情报表与当日 OTC004 共赢票据每日切片详情报表同列"
|
|
_DIFF = "OTC005 共赢票据实时详情报表与当日 OTC004 共赢票据每日切片详情报表同列"
|
|
|
|
|
|
|
|
# 副本列与报表列同名。标度按金额、股数、汇率、价格分开。
|
|
# 副本列与报表列同名。标度按金额、股数、汇率、价格分开。
|
|
@@ -175,7 +177,7 @@ def _append_detail(
|
|
|
sources: Mapping[str, str],
|
|
sources: Mapping[str, str],
|
|
|
) -> None:
|
|
) -> None:
|
|
|
_float_pnl(lines, report_name, row)
|
|
_float_pnl(lines, report_name, row)
|
|
|
- _nav(lines, report_name, row)
|
|
|
|
|
|
|
+ _nav(lines, report_name, row, note)
|
|
|
_issue_price(lines, report_name, row, note_no, ctx)
|
|
_issue_price(lines, report_name, row, note_no, ctx)
|
|
|
_copy_columns(lines, report_name, row, note, ambiguous, sources, ctx)
|
|
_copy_columns(lines, report_name, row, note, ambiguous, sources, ctx)
|
|
|
_valuation(lines, report_name, row, note, ambiguous, sources, ctx)
|
|
_valuation(lines, report_name, row, note, ambiguous, sources, ctx)
|
|
@@ -224,7 +226,16 @@ def _float_pnl(lines: list[CheckLine], report_name: str, row: Mapping[str, Any])
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
-def _nav(lines: list[CheckLine], report_name: str, row: Mapping[str, Any]) -> None:
|
|
|
|
|
|
|
+def _nav(
|
|
|
|
|
+ lines: list[CheckLine],
|
|
|
|
|
+ report_name: str,
|
|
|
|
|
+ row: Mapping[str, Any],
|
|
|
|
|
+ note: Mapping[str, Any] | None = None,
|
|
|
|
|
+) -> None:
|
|
|
|
|
+ # 已卖出:净值 = 合计卖出金额 / (合计卖出金额 − 合计卖出 A 类盈亏) × 100。
|
|
|
|
|
+ if row.get("note_status") == "sold":
|
|
|
|
|
+ _sold_nav(lines, report_name, row, note)
|
|
|
|
|
+ return
|
|
|
value_ok, valuation = present_number(row, "valuation")
|
|
value_ok, valuation = present_number(row, "valuation")
|
|
|
face_ok, face = present_number(row, "cur_face_value")
|
|
face_ok, face = present_number(row, "cur_face_value")
|
|
|
add_ok, added = present_number(row, "add_amt")
|
|
add_ok, added = present_number(row, "add_amt")
|
|
@@ -393,6 +404,118 @@ def _copy_columns(
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def _sold_valuation(
|
|
|
|
|
+ lines: list[CheckLine],
|
|
|
|
|
+ report_name: str,
|
|
|
|
|
+ row: Mapping[str, Any],
|
|
|
|
|
+ note: Mapping[str, Any] | None,
|
|
|
|
|
+ sources: Mapping[str, str],
|
|
|
|
|
+ ctx: IssueContext,
|
|
|
|
|
+) -> None:
|
|
|
|
|
+ """已卖出票据估值等于合计卖出金额,与日切报表 calculate_final_summary 一致。"""
|
|
|
|
|
+
|
|
|
|
|
+ total = read_note_cell(note, "sold_total_amt", ctx.logs, sources)
|
|
|
|
|
+ if total.absent or total.number is None:
|
|
|
|
|
+ # 报表行上的合计卖出金额是写出结果,副本缺失时退回同行。
|
|
|
|
|
+ ok, number = present_number(row, "sold_total_amt")
|
|
|
|
|
+ calc = number if ok else None
|
|
|
|
|
+ text = (
|
|
|
|
|
+ "合计卖出金额缺失"
|
|
|
|
|
+ if calc is None
|
|
|
|
|
+ else f"合计卖出金额 = {format_decimal(calc, SCALE_AMT)}"
|
|
|
|
|
+ )
|
|
|
|
|
+ live = False
|
|
|
|
|
+ else:
|
|
|
|
|
+ calc = quantize(total.number, SCALE_AMT)
|
|
|
|
|
+ text = f"合计卖出金额 = {format_decimal(calc, SCALE_AMT)}"
|
|
|
|
|
+ live = total.live
|
|
|
|
|
+ emit_amount(
|
|
|
|
|
+ lines,
|
|
|
|
|
+ formula=_SOLD_VALUATION,
|
|
|
|
|
+ basis="已卖出票据估值等于合计卖出金额",
|
|
|
|
|
+ calc_text=text,
|
|
|
|
|
+ calc_value=calc,
|
|
|
|
|
+ report_name=report_name,
|
|
|
|
|
+ column="票据估值(结算币种)",
|
|
|
|
|
+ row=row,
|
|
|
|
|
+ field="valuation",
|
|
|
|
|
+ order_no=None,
|
|
|
|
|
+ scale=SCALE_AMT,
|
|
|
|
|
+ live=live,
|
|
|
|
|
+ force=VERDICT_SUSPECT if calc is None else None,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _sold_nav(
|
|
|
|
|
+ lines: list[CheckLine],
|
|
|
|
|
+ report_name: str,
|
|
|
|
|
+ row: Mapping[str, Any],
|
|
|
|
|
+ note: Mapping[str, Any] | None,
|
|
|
|
|
+) -> None:
|
|
|
|
|
+ """已卖出净值 = 合计卖出金额 / (合计卖出金额 − 合计卖出 A 类盈亏) × 100。"""
|
|
|
|
|
+
|
|
|
|
|
+ total_ok, total = present_number(row, "sold_total_amt")
|
|
|
|
|
+ pnl = None
|
|
|
|
|
+ if note is not None:
|
|
|
|
|
+ pnl = as_decimal(note.get("sold_a_pnl"))
|
|
|
|
|
+ if pnl is None:
|
|
|
|
|
+ # 日切把 sold_a_pnl 写进浮动盈亏列,副本没有时用同行。
|
|
|
|
|
+ _pnl_ok, pnl = present_number(row, "float_pnl")
|
|
|
|
|
+ if not total_ok or total is None or pnl is None:
|
|
|
|
|
+ emit_amount(
|
|
|
|
|
+ lines,
|
|
|
|
|
+ formula=_SOLD_NAV,
|
|
|
|
|
+ basis="已卖出票据净值按合计卖出金额与合计卖出A类盈亏",
|
|
|
|
|
+ calc_text="合计卖出金额或合计卖出A类盈亏缺失",
|
|
|
|
|
+ calc_value=None,
|
|
|
|
|
+ report_name=report_name,
|
|
|
|
|
+ column="票据价格/净值",
|
|
|
|
|
+ row=row,
|
|
|
|
|
+ field="nav",
|
|
|
|
|
+ order_no=None,
|
|
|
|
|
+ scale=SCALE_PCT,
|
|
|
|
|
+ force=VERDICT_SUSPECT,
|
|
|
|
|
+ )
|
|
|
|
|
+ return
|
|
|
|
|
+ base = quantize(total - pnl, SCALE_AMT)
|
|
|
|
|
+ if base <= 0:
|
|
|
|
|
+ emit_amount(
|
|
|
|
|
+ lines,
|
|
|
|
|
+ formula=_SOLD_NAV,
|
|
|
|
|
+ basis="已卖出净值分母必须大于 0",
|
|
|
|
|
+ calc_text=(
|
|
|
|
|
+ f"合计卖出金额 − 合计卖出A类盈亏 = {format_decimal(base, SCALE_AMT)};分母不可用"
|
|
|
|
|
+ ),
|
|
|
|
|
+ calc_value=None,
|
|
|
|
|
+ report_name=report_name,
|
|
|
|
|
+ column="票据价格/净值",
|
|
|
|
|
+ row=row,
|
|
|
|
|
+ field="nav",
|
|
|
|
|
+ order_no=None,
|
|
|
|
|
+ scale=SCALE_PCT,
|
|
|
|
|
+ force=VERDICT_SUSPECT,
|
|
|
|
|
+ )
|
|
|
|
|
+ return
|
|
|
|
|
+ calc = quantize(total, SCALE_AMT) / base * Decimal(100)
|
|
|
|
|
+ text = (
|
|
|
|
|
+ f"{format_decimal(quantize(total, SCALE_AMT), SCALE_AMT)} / "
|
|
|
|
|
+ f"{format_decimal(base, SCALE_AMT)} × 100 = {format_decimal(calc, SCALE_PCT)}"
|
|
|
|
|
+ )
|
|
|
|
|
+ emit_amount(
|
|
|
|
|
+ lines,
|
|
|
|
|
+ formula=_SOLD_NAV,
|
|
|
|
|
+ basis="已卖出票据净值按合计卖出金额与合计卖出A类盈亏",
|
|
|
|
|
+ calc_text=text,
|
|
|
|
|
+ calc_value=calc,
|
|
|
|
|
+ report_name=report_name,
|
|
|
|
|
+ column="票据价格/净值",
|
|
|
|
|
+ row=row,
|
|
|
|
|
+ field="nav",
|
|
|
|
|
+ order_no=None,
|
|
|
|
|
+ scale=SCALE_PCT,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def _valuation(
|
|
def _valuation(
|
|
|
lines: list[CheckLine],
|
|
lines: list[CheckLine],
|
|
|
report_name: str,
|
|
report_name: str,
|
|
@@ -402,6 +525,10 @@ def _valuation(
|
|
|
sources: Mapping[str, str],
|
|
sources: Mapping[str, str],
|
|
|
ctx: IssueContext,
|
|
ctx: IssueContext,
|
|
|
) -> None:
|
|
) -> None:
|
|
|
|
|
+ # 已卖出后当前股数和面值被置 0,估值改为合计卖出金额,不再走存续浮动盈亏。
|
|
|
|
|
+ if row.get("note_status") == "sold":
|
|
|
|
|
+ _sold_valuation(lines, report_name, row, note, sources, ctx)
|
|
|
|
|
+ return
|
|
|
calc, text, live = _underlying_pnl(ctx, row, note, ambiguous, sources)
|
|
calc, text, live = _underlying_pnl(ctx, row, note, ambiguous, sources)
|
|
|
if calc is None:
|
|
if calc is None:
|
|
|
emit_amount(
|
|
emit_amount(
|