生产与研究分家:实盘执行器独立成 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:
@@ -20,11 +20,14 @@ SHADOW_LEAN="${SHADOW_LEAN:-1}"
|
||||
# 币池。默认三个流动性最好的做滑点测量;十币池是实际要交易的那批(TRX 剔除,
|
||||
# ATR 门控几乎全刷掉)。
|
||||
#
|
||||
# 币数超过核数时排队会成为主项:所有币同一秒收盘,2 核上十币实测清空要
|
||||
# 约 640ms,最后一个币的信号落在 1376ms。此时**加 worker 没用**——CPU 密集
|
||||
# 的活,worker 超过核数不增吞吐,只会把等待从 queue_ms 挪到 inner_ms。
|
||||
# 唯一出路是压单币耗时,走 init_stream/append_bar 增量路径(实测约 3.7x,
|
||||
# 换算后十币 / 2 核清空约 265ms)。
|
||||
# 币数超过核数时排队会成为主项:所有币同一秒收盘。此时**加 worker 没用**
|
||||
# ——CPU 密集的活,worker 超过核数不增吞吐,只会把等待从 queue_ms 挪到
|
||||
# inner_ms。增量路径(SHADOW_INCR=1,默认开)已把清空压到 300~560ms。
|
||||
#
|
||||
# 再往下压的顺序见 HANDOFF §5.72(口径对齐后的实测):单币 inner 100ms ≈
|
||||
# 信号链 30ms + 追加 2.81 根 37ms + 2 核争抢 33ms。争抢只有 1.49x,所以
|
||||
# **加核收益有限**;最便宜的一刀是按币绑定 worker(现在 symbol 随机落
|
||||
# worker,每份缓存都漏掉对方处理过的根,于是人人要追 2.81 根而非 1 根)。
|
||||
SYMS="${SYMS:-BTC,ETH,SOL}"
|
||||
IMAGE="${SHADOW_IMAGE:-hummingbot/hummingbot:latest}"
|
||||
HOURS="${HOURS:-168}"
|
||||
@@ -33,6 +36,10 @@ MAX_OFFSET_MS="${MAX_OFFSET_MS:-10}"
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||
OUT="$REPO_ROOT/research/out"
|
||||
# 信号总线的宿主机目录。**刻意放在仓库外**:这是交给实盘执行器(另一台机)的
|
||||
# 交接点,而仓库会被 git checkout/clean 动。执行器那台用 ssh tail 拉这个文件,
|
||||
# 所以它也不能在容器内部,必须挂出来
|
||||
BUS_DIR="${BUS_DIR:-$HOME/chan-live/state}"
|
||||
|
||||
die() { printf '\033[31m错误:%s\033[0m\n' "$*" >&2; exit 1; }
|
||||
say() { printf '\n\033[1m==> %s\033[0m\n' "$*"; }
|
||||
@@ -42,6 +49,12 @@ say() { printf '\n\033[1m==> %s\033[0m\n' "$*"; }
|
||||
|
||||
say "站点 $SHADOW_SITE"
|
||||
|
||||
mkdir -p "$BUS_DIR"
|
||||
# 容器内是 root,写出来的总线文件宿主机上归 root。执行器那台用普通用户
|
||||
# ssh 过来 tail,所以目录要可进入、文件要可读
|
||||
chmod 755 "$BUS_DIR" 2>/dev/null || true
|
||||
echo "信号总线:$BUS_DIR/signals_live.jsonl(容器内挂成 /bus)"
|
||||
|
||||
say "校验时钟同步"
|
||||
offset_ms=""
|
||||
if command -v chronyc >/dev/null 2>&1; then
|
||||
@@ -119,8 +132,10 @@ docker run -d --name "$NAME" -w /home/hummingbot \
|
||||
-e TG_NOTIONAL="${TG_NOTIONAL:-500}" \
|
||||
-e TG_LEVERAGE="${TG_LEVERAGE:-10}" \
|
||||
-e TG_STALE_S="${TG_STALE_S:-90}" \
|
||||
-e SIGNAL_BUS=/bus/signals_live.jsonl \
|
||||
-v "$REPO_ROOT:/repo:ro" \
|
||||
-v "$OUT:/out" \
|
||||
-v "$BUS_DIR:/bus" \
|
||||
--entrypoint /opt/conda/envs/hummingbot/bin/python \
|
||||
"$IMAGE" /repo/research/live/shadow_hb.py \
|
||||
--hours "$HOURS" --workers "$WORKERS" --syms "$SYMS" >/dev/null
|
||||
|
||||
Reference in New Issue
Block a user