整点在线推 Telegram,并带上搬运管道的新鲜度

执行器活着不代表链路活着——搬运死了一样心跳正常、一样什么都不做。
所以每小时那条必须读 ship_alive.json:ssh 是否在连、文件是否还在刷。
连上/断开立刻落盘,不靠 5 分钟心跳,否则第一轮会误报上游断了。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jack
2026-08-29 00:57:11 +08:00
co-authored by Cursor
parent 3bbd92784c
commit 080ff7d20e
6 changed files with 152 additions and 7 deletions
+62 -2
View File
@@ -8,10 +8,18 @@
推 平仓 带已实现盈亏(含手续费与资金费),这是唯一的真账
推 闸拦截 仅 MAX_OPEN / MAX_DAY / MAX_DAY_LOSS —— 说明有 bug 或策略在流血
推 报错、对账平仓、跨日结算
推 整点在线 每 60 分钟一条,见下
不推 信号过期跳过 这是常态(重连重放会带上旧信号),推了就淹掉真事
不推 心跳 日志里有,推了每天 288 条
不推 5 分钟心跳 日志里有,推了每天 288 条
量级:信号 6.8 个/天、日开仓上限 15,所以最多约 30 条/天。
量级:信号 6.8 个/天、日开仓上限 15、在线 24 条,所以最多约 55 条/天。
## 整点在线那条为什么不违反上面的标准
只说「我还活着」的推送看两天就会被忽略,那时它就成了噪声。所以这条必须带
**能暴露问题的数字**,尤其是上游新鲜度——执行器活着不代表链路活着,搬运
管道死掉时执行器一样心跳正常、一样什么都不做,那是最危险的状态。异常时这
条会显式标出来,而不是把数字并排列出来让人自己看。
## 失败一律只打日志
@@ -106,6 +114,58 @@ async def day_rolled(day: str, n: int, pnl: float) -> None:
await send(f"[{TAG}] {day} 结算 · {n} 笔 · {pnl:+.2f} USDT")
def _dur(s: float) -> str:
s = max(0, int(s))
if s < 60:
return f"{s}"
if s < 3600:
return f"{s // 60}分钟"
if s < 86400:
h, m = s // 3600, (s % 3600) // 60
return f"{h}小时{m}" if m else f"{h}小时"
return f"{s / 86400:.1f}"
async def alive(up_s: float, seen: int, built: int, took: int, n_open: int,
max_open: int, day_n: int, max_day: int, day_pnl: float,
max_loss: float, order_fail: int, ship: dict | None,
dry: bool) -> None:
"""整点在线。异常在第一行,正常时才是「在线」。
`ship` 是搬运器落的 ship_alive.json 解出来的字典,None 表示读不到——
那本身就是要报的事:搬运没在跑、或者跑的是没有这个文件的旧版本。
"""
warn = []
if order_fail and not built:
warn.append(f"⛔ 做了 {took} 笔却一次都没建上,下单全被拒")
elif order_fail:
warn.append(f"⚠ 累计 {order_fail} 次下单失败")
if ship is None:
warn.append("⛔ 读不到搬运状态,信号可能根本没在进来")
else:
gap = time.time() - ship.get("ts", 0)
# 搬运连上/断开/每 5 分钟都会落一次。超过 12 分钟是进程自己死了
if gap > 720:
warn.append(f"⛔ 搬运状态已停更 {_dur(gap)},上游可能已断")
elif ship.get("connected") is False:
warn.append("⛔ 搬运 ssh 已断开,正在重连")
if ship.get("n_skew"):
warn.append(f"⛔ 搬运侧时钟倒流 {ship['n_skew']}")
head = warn[0] if warn else ("在线(空跑)" if dry else "在线")
lines = [f"[{TAG}] {head} · 已跑 {_dur(up_s)}",
f"信号 {seen} · 建仓 {built} · 在场 {n_open}/{max_open}",
f"当日 {day_n}/{max_day} 笔 · 盈亏 {day_pnl:+.2f}/-{max_loss:.1f}"]
if ship is not None:
last = ship.get("last_signal_ts") or 0
lines.append(
f"搬运 ssh 在线 {_dur(ship.get('up_s', 0))} · "
f"重连 {ship.get('n_reconnect', 0)} 次 · 最近信号 "
+ (f"{_dur(time.time() - last)}" if last else "启动后还没有"))
lines += warn[1:]
await send("\n".join(lines))
async def stopping(n_open: int) -> None:
await send(f"[{TAG}] 收到停机信号,平掉在场 {n_open} 笔后退出。"
f"\n注意:停机后不再有超时平仓与新开仓。"