下单失败必须推 Telegram,并让心跳判读「做了却没建上」
实盘首日丢掉 4 个信号、白跑 5 小时,根因是 40774,但**没有任何推送**。 日志里一直在报,可外在表现和"没信号"一模一样——这正是整套通知设计要防的 那类静默经济损失,却恰好漏了下单失败这一条。 现在:入场被拒或止盈挂不上都推。按信号聚合成一条,不按腿推(避免一个信号 两条)。两腿全失败时说明"这个信号丢了"并带累计失败次数与常见原因;部分腿 失败时说明"收益结构已偏离设计"——那种情况仓位是半的,不是设计的两腿结构。 心跳原先只把数字并排列出来:"已做 4 · 在场 0/3" 那 5 小时一直在打,但没有 一处说这是异常。现在分开计 n_built 与 n_order_fail,做了却一次没建上直接 打 ⛔。只看 n_took 分不出"做了"和"建上了"。 status.sh 同样加判读:统计 entry_fail 次数并打出最后一条错误与码表。 tp_fail 现在也记进 live_trades.jsonl,原先只打日志不落盘。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -67,6 +67,19 @@ fi
|
||||
hr "最近成交"
|
||||
if [[ -s "$STATE/live_trades.jsonl" ]]; then
|
||||
tail -5 "$STATE/live_trades.jsonl" | sed 's/^/ /'
|
||||
# 「下过单但一次都没建上」是明确的故障,而它的外在表现和"没信号"一样,
|
||||
# 不主动判读就会白跑几小时。首日就是这么丢掉 4 个信号的
|
||||
nf="$(grep -c '"ev": "entry_fail"' "$STATE/live_trades.jsonl" || true)"
|
||||
nb="$(grep -c '"ev": "opened", "key": [^]]*\[{' "$STATE/live_trades.jsonl" || true)"
|
||||
ne="$(grep -c '"ev": "entry"' "$STATE/live_trades.jsonl" || true)"
|
||||
if [[ "${nf:-0}" -gt 0 ]]; then
|
||||
echo
|
||||
echo " ⛔ 有 $nf 次入场被拒(共尝试 $ne 个信号)"
|
||||
echo " 最后一条错误:"
|
||||
grep '"ev": "entry_fail"' "$STATE/live_trades.jsonl" | tail -1 \
|
||||
| sed 's/^/ /'
|
||||
echo " 40774 = 持仓模式不匹配 · 40762/40786 = 保证金不足"
|
||||
fi
|
||||
else
|
||||
echo " 还没有成交记录"
|
||||
fi
|
||||
|
||||
+35
-3
@@ -254,6 +254,9 @@ class Exec:
|
||||
self.execs: dict = {} # key → 该笔的腿与超时时刻
|
||||
self.offset = 0 # 已读到总线的哪一行
|
||||
self.n_seen = self.n_took = self.n_skip = 0
|
||||
# 建仓成功/失败分开计。只看 n_took 分不出"做了但下单被拒"——首日
|
||||
# 那 5 小时里 n_took=4 而实际一笔都没建上
|
||||
self.n_built = self.n_order_fail = 0
|
||||
|
||||
# ── 启动 ──────────────────────────────────────────────────────
|
||||
async def start(self) -> None:
|
||||
@@ -574,7 +577,7 @@ class Exec:
|
||||
hold = "long" if d > 0 else "short"
|
||||
stop_px = self.snap(sym, entry - d * SL_ATR * a)
|
||||
|
||||
opened = []
|
||||
opened, failed = [], []
|
||||
for x in lg:
|
||||
oid = oid_of(r["key"], x["tag"])
|
||||
try:
|
||||
@@ -583,6 +586,7 @@ class Exec:
|
||||
print(f" ⛔ {x['tag']} 入场失败 {e}", flush=True)
|
||||
log_trade({"ev": "entry_fail", "key": r["key"],
|
||||
"tag": x["tag"], "err": str(e)})
|
||||
failed.append(f"{x['tag']} 入场:{e}")
|
||||
continue
|
||||
tp_px = self.snap(sym, entry + d * x["atr"] * a)
|
||||
try:
|
||||
@@ -593,6 +597,9 @@ class Exec:
|
||||
# 超时腿会兜住它,所以只告警不强平
|
||||
print(f" ⚠ {x['tag']} 止盈挂单失败 {e}"
|
||||
f"(仓位有服务端止损,超时腿会兜)", flush=True)
|
||||
log_trade({"ev": "tp_fail", "key": r["key"],
|
||||
"tag": x["tag"], "err": str(e)})
|
||||
failed.append(f"{x['tag']} 止盈:{e}")
|
||||
opened.append({"tag": x["tag"], "oid": oid, "size": half,
|
||||
"tp_px": tp_px, "stop_px": stop_px})
|
||||
print(f" {x['tag']:<7}{half} 币 · 止损 {stop_px} · "
|
||||
@@ -600,7 +607,23 @@ class Exec:
|
||||
|
||||
log_trade({"ev": "opened", "key": r["key"], "legs": opened,
|
||||
"stop_px": stop_px})
|
||||
# 下单失败必须推。这类失败是**静默的经济损失**:日志里在报,但表现只是
|
||||
# "一直没开仓",看起来和"没信号"一样。实盘首日就因为这个白跑 5 小时——
|
||||
# 8 次下单全被 40774 拒掉而无人知道。所以推送不是可选的
|
||||
if failed:
|
||||
self.n_order_fail += 1
|
||||
if not opened:
|
||||
await tg.error(
|
||||
f"{r['key']} 建仓全部失败,这个信号丢了",
|
||||
"\n".join(failed) +
|
||||
f"\n\n累计失败 {self.n_order_fail} 次。"
|
||||
f"链路正常但下不了单——常见是下单体字段被拒"
|
||||
f"(40774 持仓模式不匹配)、保证金不足、或该币被限制交易")
|
||||
else:
|
||||
await tg.error(f"{r['key']} 部分腿失败,收益结构已偏离设计",
|
||||
"\n".join(failed))
|
||||
if opened:
|
||||
self.n_built += 1
|
||||
self.execs[r["key"]] = {
|
||||
"sym": sym, "pair": pair, "hold": hold,
|
||||
"deadline": time.time() + MAXB * 60, "legs": opened,
|
||||
@@ -743,10 +766,19 @@ class Exec:
|
||||
await tg.day_rolled(*self.guard.pending_roll)
|
||||
self.guard.pending_roll = None
|
||||
n_open = sum(1 for v in self.execs.values() if v)
|
||||
# 「已做 N 但建仓 0」是明确的故障,不能只把数字并排列出来让人自己
|
||||
# 看。首日那 5 小时的心跳里 "已做 4 · 在场 0/3" 一直在打,但没有
|
||||
# 任何一处说这是异常
|
||||
bad = ""
|
||||
if self.n_took and not self.n_built:
|
||||
bad = f" ⛔ 做了 {self.n_took} 笔却一次都没建上,下单被拒"
|
||||
elif self.n_order_fail:
|
||||
bad = f" ⚠ 有 {self.n_order_fail} 次下单失败"
|
||||
print(f" [心跳] 见信号 {self.n_seen} · 已做 {self.n_took} · "
|
||||
f"跳过 {self.n_skip} · 在场 {n_open}/{MAX_OPEN} · "
|
||||
f"建仓 {self.n_built} · 跳过 {self.n_skip} · "
|
||||
f"在场 {n_open}/{MAX_OPEN} · "
|
||||
f"当日 {self.guard.n_day}/{MAX_DAY} 笔 · "
|
||||
f"当日 PnL {self.guard.pnl_day:+.2f}/-{MAX_DAY_LOSS}",
|
||||
f"当日 PnL {self.guard.pnl_day:+.2f}/-{MAX_DAY_LOSS}{bad}",
|
||||
flush=True)
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user