fix(live): 守恒/废单跨日过滤属性错位根治——订单时间字段误读不存在的datetime(bullet_trade Order实为add_time,全字段扫描实锤)恒None→跨日过滤从不生效,引擎跨交易日存活时历史终态订单全进当日守恒对比(台账只记当日行)→每日假缺口告警+重试刷到23:00;09-01进程将首次跨日存活必首发作;两处同修(守恒+废单清单),测试替身datetime_=改回add_time_=(08-29周末提交曾喂不存在的datetime=把bug锁进断言)+新增昨日终态订单零缺口回归;531绿 [vps]
This commit is contained in:
@@ -284,11 +284,15 @@ def eod_reconcile(engine: Any, ledger: Any, db: str, account_id: int,
|
||||
ledger_vol[vkey] = ledger_vol.get(vkey, 0) + int(r.get("amount") or 0)
|
||||
|
||||
# 守恒校验:订单成交合计 vs 台账记录合计(前缀 6 位码归一,跨日订单不计)
|
||||
# ⚠️ 订单时间字段=bullet_trade Order.add_time(08-31 修:原误读不存在的
|
||||
# ``datetime`` 属性恒 None → 跨日过滤从不生效,引擎跨交易日存活时历史
|
||||
# 订单全进对比 → 每日假缺口告警;测试替身当时被喂了 datetime= 字段,
|
||||
# 把 bug 行为锁进了断言——替身必须贴真实字段名)
|
||||
order_vol: Dict[tuple, int] = {}
|
||||
for o in own_by_broker.values():
|
||||
if _status_str(getattr(o, "status", None)) not in _TERMINAL:
|
||||
continue
|
||||
o_dt = getattr(o, "datetime", None)
|
||||
o_dt = getattr(o, "add_time", None)
|
||||
if o_dt is not None and not str(o_dt).startswith(today):
|
||||
continue
|
||||
filled = int(getattr(o, "filled", 0) or 0)
|
||||
@@ -313,7 +317,7 @@ def eod_reconcile(engine: Any, ledger: Any, db: str, account_id: int,
|
||||
for o in own_by_broker.values():
|
||||
if _status_str(getattr(o, "status", None)) not in ("rejected", "failed", "error"):
|
||||
continue
|
||||
o_dt = getattr(o, "datetime", None)
|
||||
o_dt = getattr(o, "add_time", None)
|
||||
if o_dt is not None and not str(o_dt).startswith(today):
|
||||
continue
|
||||
if int(getattr(o, "filled", 0) or 0) > 0:
|
||||
|
||||
@@ -26,11 +26,13 @@ from sanguo_portfolio.live_reconcile import (
|
||||
|
||||
# ------------------ 公共替身 ------------------
|
||||
def _order(oid="o1", broker_oid="1001", security="000049.XSHE", is_buy=True,
|
||||
amount=500, filled=0, status="open", datetime_=None):
|
||||
amount=500, filled=0, status="open", add_time_=None):
|
||||
"""替身字段名必须贴真实 bullet_trade Order(08-31 教训:曾被喂不存在的
|
||||
``datetime``=,把守恒跨日过滤的属性错位 bug 锁进了断言)。"""
|
||||
return SimpleNamespace(
|
||||
order_id=oid, _broker_order_id=broker_oid, security=security,
|
||||
is_buy=is_buy, amount=amount, filled=filled, status=status,
|
||||
datetime=datetime_,
|
||||
add_time=add_time_,
|
||||
)
|
||||
|
||||
|
||||
@@ -361,13 +363,30 @@ class TestEodReconcile:
|
||||
eng = _engine(
|
||||
[_order(status="rejected", filled=300, amount=500, broker_oid="a"),
|
||||
_order(status="rejected", filled=0, amount=200, broker_oid="b",
|
||||
datetime_="2020-01-01 10:00:00")],
|
||||
add_time_="2020-01-01 10:00:00")],
|
||||
[])
|
||||
with caplog.at_level("WARNING"):
|
||||
summary = eod_reconcile(eng, led, db, 19, "s")
|
||||
assert summary["rejected_orders"] == []
|
||||
assert not any("废单" in r.message for r in caplog.records)
|
||||
|
||||
def test_yesterday_order_no_conservation_gap(self, db, caplog):
|
||||
"""08-31 守恒误报回归:引擎跨交易日存活(进程不死)时,**昨日**的
|
||||
终态足额订单不得进当日守恒对比——台账只记当日行,历史订单计入
|
||||
必然产生假缺口(原 ``datetime`` 属性误读恒 None,过滤从不生效)。"""
|
||||
led = LiveInstanceLedger(initial_cash=1_000_000)
|
||||
from datetime import timedelta as _td
|
||||
yday = (datetime.now() - _td(days=1)).strftime("%Y-%m-%d 09:30:00")
|
||||
eng = _engine(
|
||||
[_order(status="filled", filled=500, broker_oid="old",
|
||||
add_time_=yday),
|
||||
_order(status="filled", filled=500, broker_oid="new")],
|
||||
[_qmt_trade(order_id="new", trade_id="t-new")])
|
||||
with caplog.at_level("WARNING"):
|
||||
summary = eod_reconcile(eng, led, db, 19, "s")
|
||||
assert summary["conservation_gaps"] == []
|
||||
assert summary["rejected_orders"] == []
|
||||
|
||||
def test_gap_warning_dedup_on_identical_retry(self, db, caplog):
|
||||
"""缺口重试轮:内容不变只首轮回 WARNING,重复轮降级 INFO 防刷屏。"""
|
||||
from sanguo_live.persistence import save_trade
|
||||
|
||||
Reference in New Issue
Block a user