生产与研究分家:实盘执行器独立成 live/ 子树,加 AWS 部署
实盘要跑在 AWS(API key 绑了 IP 白名单),而信号在新加坡那台算。借这次 把生产从研究侧摘出来,四条具体代价里第一条已经咬过: 1. live_state.json 原先落在 research/out/,而那里 shadow_hb 会自动 rename 归档、研究脚本会写、人也手工清过。那文件装的是 MAX_DAY_LOSS 累计与已 处理信号键,被清掉不报错,只是两道闸静默失效。改到 LIVE_HOME。 2. 采集器十币清空 300~560ms 直接叠在信号到达执行器的延迟上。 3. 研究侧探针 OOM 过一次(14.9GB),当时若有仓位在场会连坐执行器。 4. 为读两个常量 import 研究侧 step43,把 numpy/pandas/pyarrow 拖进实盘 进程。抽出 stdlib-only 的 live/exit_params.py,install.sh 加断言挡回归。 新增 live/ship_signals.py:AWS 侧 ssh tail 拉总线,每次重连从文件头重放 + 按幂等键去重,断线期间的信号自愈;旧信号由 staleness 闸挡掉不补做。 带时钟倒流检测——两机时钟不同步会让那道闸静默放宽。 部署件:systemd 两单元(搬运挂了执行器仍管在场仓位的超时平仓)、 install.sh、dryrun.sh(验密钥/白名单/时钟/ssh/取整)、status.sh、README。 验证:live_exec 重构后端到端空跑,SOL 多头与 ADA 空头的止损/两级止盈/ 数量取整逐项核对正确,isolated + post_only + reduceOnly 都在;搬运的去重、 重启不重复追加、脏数据跳过、断线重连重放均已测。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# 空跑验全链:真连交易所读规则/持仓,**不下任何真单**。
|
||||
#
|
||||
# 上真单之前必须过这一步。它验的是那些"上线才会暴露、且暴露方式是花钱"的
|
||||
# 环节:密钥能不能用、IP 白名单对不对、时钟同不同步、搬运通不通、
|
||||
# 数量与价位取整合不合交易所规则。
|
||||
set -euo pipefail
|
||||
|
||||
APP=/opt/chan
|
||||
CONF=/etc/chan-live/live.env
|
||||
STATE=/var/lib/chan-live
|
||||
USER_NAME=chan
|
||||
SECS="${SECS:-90}"
|
||||
|
||||
die() { echo "⛔ $*" >&2; exit 1; }
|
||||
ok() { echo " ✓ $*"; }
|
||||
|
||||
[[ $EUID -eq 0 ]] || die "要 root:sudo $0"
|
||||
[[ -f "$CONF" ]] || die "缺 $CONF,先跑 install.sh"
|
||||
|
||||
set -a; . "$CONF"; set +a
|
||||
|
||||
echo "── 1. 配置自检 ──"
|
||||
for v in BITGET_API_KEY BITGET_API_SECRET BITGET_PASSPHRASE SHIP_FROM; do
|
||||
[[ -n "${!v:-}" ]] || die "$CONF 里 $v 还是空的"
|
||||
done
|
||||
ok "密钥三项与 SHIP_FROM 都已填"
|
||||
[[ "$LIVE_HOME" != /opt/chan* ]] || die "LIVE_HOME 不能指到仓库里(会被 git 清掉)"
|
||||
ok "LIVE_HOME=$LIVE_HOME 在仓库外"
|
||||
|
||||
echo "── 2. 时钟 ──"
|
||||
# staleness 闸靠两机时钟一致才有意义。这里只能验本机;跨机偏差由
|
||||
# ship_signals 在收到信号时报「时间倒流」
|
||||
if command -v chronyc >/dev/null; then
|
||||
chronyc tracking | grep -E "Reference ID|System time|Leap status" | sed 's/^/ /'
|
||||
src="$(chronyc tracking | awk '/Reference ID/{print $NF}')"
|
||||
[[ "$src" != "()" && -n "$src" ]] || die "chrony 还没同步上,等一会再跑"
|
||||
ok "chrony 已同步"
|
||||
else
|
||||
die "没装 chrony。staleness 闸不可信,先 apt install chrony"
|
||||
fi
|
||||
|
||||
echo "── 3. 出口 IP 是否在白名单内 ──"
|
||||
myip="$(curl -s --max-time 10 https://api.ipify.org || true)"
|
||||
[[ -n "$myip" ]] && echo " 本机出口 IP:$myip" || echo " ⚠ 取不到出口 IP"
|
||||
echo " 对照 Bitget 后台该 key 的 IP 白名单,不一致下面会报 40018 之类"
|
||||
|
||||
echo "── 4. 能否 ssh 到采集机 ──"
|
||||
if sudo -u "$USER_NAME" ssh -o BatchMode=yes -o ConnectTimeout=10 \
|
||||
"$SHIP_FROM" 'echo ok' >/dev/null 2>&1; then
|
||||
ok "ssh $SHIP_FROM 通"
|
||||
rb="${SHIP_REMOTE_BUS:-~/chan-live/state/signals_live.jsonl}"
|
||||
n="$(sudo -u "$USER_NAME" ssh -o BatchMode=yes "$SHIP_FROM" \
|
||||
"wc -l < $rb 2>/dev/null || echo 0")"
|
||||
echo " 对端总线现有 $n 条信号"
|
||||
[[ "$n" -gt 0 ]] || echo " ⚠ 对端总线是空的。采集机接总线了吗?"
|
||||
else
|
||||
die "ssh $SHIP_FROM 不通。装 key:
|
||||
sudo -u $USER_NAME ssh-keygen -t ed25519 -N '' -f $STATE/home/.ssh/id_ed25519
|
||||
再把 $STATE/home/.ssh/id_ed25519.pub 加到采集机的 authorized_keys"
|
||||
fi
|
||||
|
||||
echo "── 5. 执行器空跑 ${SECS}s(真连交易所,不下单)──"
|
||||
# --dry-run 下 Bitget 客户端只读不写:合约规则、持仓、费率照查,
|
||||
# 下单一律只打印。所以这一步会真实验到密钥与白名单
|
||||
# 让 chan 自己 source 配置($CONF 是 640 root:chan,它读得到)。
|
||||
# 不用 `env "$(grep ...)"` 那种拼法:值里有空格就会被切开
|
||||
set +e
|
||||
sudo -u "$USER_NAME" bash -c \
|
||||
"set -a; . '$CONF'; set +a; exec timeout $SECS \
|
||||
'$APP/.venv/bin/python' '$APP/live/live_exec.py' --dry-run"
|
||||
rc=$?
|
||||
set -e
|
||||
# timeout 到点是 124,属于预期
|
||||
[[ $rc -eq 124 || $rc -eq 0 ]] || die "空跑退出码 $rc,看上面报错"
|
||||
ok "空跑没有报错退出"
|
||||
|
||||
echo
|
||||
echo "空跑过了。真跑:"
|
||||
echo " sudo systemctl enable --now chan-live-ship chan-live-exec"
|
||||
echo " $APP/live/deploy/status.sh"
|
||||
Reference in New Issue
Block a user