Files
Chan/live/deploy/README.md
T

7.1 KiB
Raw Blame History

小额实盘执行器 · 部署

为什么是两台机

Bitget 的 API key 绑了 IP 白名单,只能从 AWS 那台发单;信号是新加坡那台采集器 算出来的。于是分工固定成:

新加坡(采集/研究机)                    AWS(生产机)
  shadow_hb.py 算信号                     ship_signals.py 拉总线
    └→ ~/chan-live/state/                   └→ /var/lib/chan-live/state/
         signals_live.jsonl  ──ssh tail──→        signals_live.jsonl
                                            live_exec.py 读总线 → Bitget REST

生产机上不装采集侧的任何东西Docker / Hummingbot / pandas / chanlun)。 理由不是洁癖,是四条具体代价:

  1. live_state.json 原先落在 research/out/,而那个目录 shadow_hb.py 会在 CSV 表头变化时自动 rename 归档、研究脚本会写、人也会手工清数据。那个文件装 的是 MAX_DAY_LOSS 累计与已处理信号键,被清掉不报错,只是两道闸静默 失效。现在改到 /var/lib/chan-live
  2. 采集器十币清空 300~560ms,直接叠在信号到达执行器的延迟上。
  3. 研究侧的探针 OOM 过一次(14.9 GB、负载 12)。当时若有仓位在场,执行器会被 一起杀掉,只剩交易所侧止损兜着。
  4. 依赖面:执行器只需标准库 + aiohttp。原先为读两个常量 import 研究侧的 step43,把 numpy/pandas/pyarrow 全拖进实盘进程。

install.sh 里有一条断言会真的挡住第 4 条回归。

机器要求

CPU 无所谓(执行器几乎不算东西,信号 6.8 个/天)。要的是:

  • 出口 IP 固定,且已加进 Bitget 该 key 的白名单
  • chrony 能同步。这一条是硬要求LIVE_STALE_S 那道闸靠两机时钟一致才 有意义,采集机时钟快 5 分钟就等于把闸放宽 5 分钟,一个早已失效的参考价会被 当成新鲜的照做
  • 能 ssh 到采集机(拉总线用)

一、生产机(AWS

# 1. 取代码。只需要 live/ 这一个子树,但整仓克隆更省事
git clone -b chan <repo> /tmp/chan && cd /tmp/chan
sudo ./live/deploy/install.sh
#    或让它自己克隆:sudo REPO=<repo> ./live/deploy/install.sh

# 2. 填密钥与参数
sudo vi /etc/chan-live/live.env

live.env 里必须改的四项:BITGET_API_KEY / SECRET / PASSPHRASE / SHIP_FROM。密钥权限只勾只读 + 交易,不要勾提币

# 3. 装拉总线用的 ssh key
sudo -u chan ssh-keygen -t ed25519 -N '' \
     -f /var/lib/chan-live/home/.ssh/id_ed25519
sudo cat /var/lib/chan-live/home/.ssh/id_ed25519.pub
#    把这一行加到采集机的 ~/.ssh/authorized_keys

# 4. 空跑验全链(不下真单)
sudo ./live/deploy/dryrun.sh

dryrun.sh 验的是那些"上线才暴露、且暴露方式是花钱"的环节:密钥能不能用、 IP 白名单对不对、chrony 同步没有、ssh 通不通、对端总线有没有信号、数量与价位 取整合不合交易所规则。不要跳过。

# 5. 真跑
sudo systemctl enable --now chan-live-ship chan-live-exec
./live/deploy/status.sh

二、采集机(新加坡)

采集器要重启一次才会开始往总线写——signal_bus.emit 是后加的,跑着的进程没有 加载。重启会丢已采的几分钟,数据本身不受影响(CSV 是追加的)。

cd <repo> && git pull
docker stop shadow && docker rm shadow
SHADOW_SITE=sg-tencent SYMS=BTC,ETH,SOL,BNB,XRP,DOGE,ADA,AVAX,LINK,LTC \
    bash research/live/deploy/start.sh

start.sh 会把 $HOME/chan-live/state 挂进容器成 /bus,总线落在 $HOME/chan-live/state/signals_live.jsonl总线刻意放在仓库外,因为它是 交给另一台机的交接点,而仓库会被 git 动。

确认在写:

ls -la ~/chan-live/state/
# 等一个信号(6.8 个/天,可能要等几小时)
tail -f ~/chan-live/state/signals_live.jsonl

日常

./live/deploy/status.sh                      # 一屏体检
journalctl -u chan-live-exec -f              # 执行器日志
journalctl -u chan-live-ship -f              # 搬运日志

怎么判健康: 信号 6.8 个/天,所以"很久没有新信号"是正常的,不能当健康 指标。要看的是 chan-live-ship 的心跳(每 5 分钟一条),里面报 ssh 在线时长与 重连次数。管道死了但进程还活着是这里最危险的状态——ServerAliveInterval=15 负责让它变成一次可见的断开。

停机与回滚

# 停新开仓,但保留在场仓位的管理(48 分钟超时平仓在执行器进程里)
sudo systemctl stop chan-live-ship

# 全停。执行器收到 SIGTERM 会**撤挂单 + 市价平掉在场仓位**再退出
# (内部平仓上限 60s,systemd 给了 90s 停机窗口)
sudo systemctl stop chan-live-exec

# 代码回滚
cd /opt/chan && sudo git reset --hard <sha> && sudo systemctl restart chan-live-exec

⚠️ 状态目录 /var/lib/chan-live 不要跟着回滚。 它存的是当日计数与已处理 信号键;清掉等于日上限归零、且可能重开已经做过的仓。

故障处理

症状 大概率原因
启动即 40018 / 签名错 出口 IP 不在白名单,或密钥抄错。curl https://api.ipify.org 对一下
搬运日志 Permission denied (publickey) 第 3 步的 pubkey 没加到采集机
搬运在线但一直没信号 采集机没重启过(signal_bus.emit 没加载),或对端总线路径不对
日志 ⛔ 时间倒流 Xs 两机时钟不同步,staleness 闸已不可信。查两边 chronyc tracking
信号收到但都被跳过 age > LIVE_STALE_S。看是搬运慢还是时钟偏;也可能是重连重放的旧信号(这种跳过是对的)
systemctl status 显示 start-limit-hit 5 分钟内重启 5 次,systemd 停手了。先看 journal 找真因,再 systemctl reset-failed
执行器起不来,报缺 numpy/pandas 有人给生产侧加了研究侧的 import。install.sh 的依赖断言就是挡这个

已知的退化边界

  • 进程死掉不会变成裸仓。 止损与止盈都挂在交易所侧(presetStopLossPrice 与 post-only reduce-only 限价单),只有 48 分钟超时平仓在本进程。所以进程死 掉的后果是持仓超过 48 根,不是失去保护。
  • 崩溃与主动停机的处理不同,是刻意的。 崩溃后 systemd 几秒内重启, reconcile 接着撤挂单 + 平掉遗留仓位,空窗期由交易所侧止损兜着。主动 systemctl stop 则在退出前就平掉——因为停机后没人重启,仓位会一直挂到止损 或止盈,超时腿丢了就不是回测那个出场结构了。
  • 断线超过 20s 就等于漏掉那期间的信号。 重连会把总线重放上来,但旧信号会被 staleness 闸挡掉。这是对的——参考成交价是次根开盘价,过了就不是回测那个价。
  • 重启时会平掉交易所上已有的仓位reconcile)。接管要重建入场价、ATR、 剩余半仓状态和已过根数,任一项猜错就跑成另一个收益结构,所以选择平掉。