|
@@ -256,24 +256,23 @@ def _detail_values(
|
|
|
|
|
|
|
|
def _match_master(ctx: TrsContext, user: UserView, row: Mapping[str, Any]) -> tuple[str | None, Mapping[str, Any] | None]:
|
|
def _match_master(ctx: TrsContext, user: UserView, row: Mapping[str, Any]) -> tuple[str | None, Mapping[str, Any] | None]:
|
|
|
token = _text(row.get("master_order_no"))
|
|
token = _text(row.get("master_order_no"))
|
|
|
|
|
+ # 报表 master_order_no 是算法号时,只对算法母单。子单/清算委托上盖的 algo_no
|
|
|
|
|
+ # 只是累加成交金额用,不能当成主单命中,否则多条子单会把无对冲的 CRM 算法单判成「没有对上」。
|
|
|
|
|
+ algo_hits = [src for src in user.rows("trade_algo_master") if token and _text(src.get("algo_no")) == token]
|
|
|
|
|
+ if len(algo_hits) == 1:
|
|
|
|
|
+ return "trade_algo_master", algo_hits[0]
|
|
|
|
|
+ if len(algo_hits) > 1:
|
|
|
|
|
+ return "trade_algo_master", None
|
|
|
|
|
+
|
|
|
hedges = [hedge for hedge in ctx.hedges if hedge.entrust_no == token or hedge.algo_no == token]
|
|
hedges = [hedge for hedge in ctx.hedges if hedge.entrust_no == token or hedge.algo_no == token]
|
|
|
order_name = _order_name(user)
|
|
order_name = _order_name(user)
|
|
|
- prefer = "trade_algo_master" if any(hedge.algo_no == token for hedge in hedges) else None
|
|
|
|
|
- if prefer is None and any(hedge.entrust_no == token for hedge in hedges):
|
|
|
|
|
- prefer = order_name
|
|
|
|
|
refs = {hedge.ext_ref for hedge in hedges}
|
|
refs = {hedge.ext_ref for hedge in hedges}
|
|
|
- if prefer:
|
|
|
|
|
- matched = _hits(user, prefer, token, refs)
|
|
|
|
|
- if len(matched) == 1:
|
|
|
|
|
- return prefer, matched[0]
|
|
|
|
|
- if len(matched) > 1:
|
|
|
|
|
- return prefer, None
|
|
|
|
|
- found: list[tuple[str, Mapping[str, Any]]] = []
|
|
|
|
|
- for key in (order_name, "trade_algo_master"):
|
|
|
|
|
- for src in _hits(user, key, token, refs):
|
|
|
|
|
- found.append((key, src))
|
|
|
|
|
- if len(found) == 1:
|
|
|
|
|
- return found[0]
|
|
|
|
|
|
|
+ # 普通委托主单只按委托号 / 对冲 ext_ref;禁止再用 algo_no 去扫子单。
|
|
|
|
|
+ matched = _order_hits(user, order_name, token, refs)
|
|
|
|
|
+ if len(matched) == 1:
|
|
|
|
|
+ return order_name, matched[0]
|
|
|
|
|
+ if len(matched) > 1:
|
|
|
|
|
+ return order_name, None
|
|
|
return None, None
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
|
|
@@ -316,6 +315,30 @@ def _hits(user: UserView, key: str, token: str | None, refs: set[str]) -> list[M
|
|
|
return found
|
|
return found
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def _order_hits(
|
|
|
|
|
+ user: UserView, key: str, token: str | None, refs: set[str]
|
|
|
|
|
+) -> list[Mapping[str, Any]]:
|
|
|
|
|
+ """主单级普通委托匹配:委托号或对冲 ext_ref,不用子单上的 algo_no。"""
|
|
|
|
|
+
|
|
|
|
|
+ found: list[Mapping[str, Any]] = []
|
|
|
|
|
+ seen: set[str] = set()
|
|
|
|
|
+ for src in user.rows(key):
|
|
|
|
|
+ linked = False
|
|
|
|
|
+ if token and _text(src.get("entrust_no")) == token:
|
|
|
|
|
+ linked = True
|
|
|
|
|
+ elif _text(src.get("ext_ref")) in refs:
|
|
|
|
|
+ linked = True
|
|
|
|
|
+ if not linked:
|
|
|
|
|
+ continue
|
|
|
|
|
+ ident = src.get("id")
|
|
|
|
|
+ mark = f"obj:{id(src)}" if ident is None else biz_text(ident)
|
|
|
|
|
+ if mark in seen:
|
|
|
|
|
+ continue
|
|
|
|
|
+ seen.add(mark)
|
|
|
|
|
+ found.append(src)
|
|
|
|
|
+ return found
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def _fill_source(ctx: TrsContext, user: UserView) -> tuple[str | None, list[Mapping[str, Any]]]:
|
|
def _fill_source(ctx: TrsContext, user: UserView) -> tuple[str | None, list[Mapping[str, Any]]]:
|
|
|
if user.has("clr_trade_fill") and not source_is_live(ctx, "clr_trade_fill"):
|
|
if user.has("clr_trade_fill") and not source_is_live(ctx, "clr_trade_fill"):
|
|
|
return "clr_trade_fill", user.rows("clr_trade_fill")
|
|
return "clr_trade_fill", user.rows("clr_trade_fill")
|