已知的两个上限
trailing-trade 首买窗口 candleLimit 的上限由 1000 收紧为 999;momentum 慢线 EMA 周期的上限为 998。candleLimit 是首先该查的一个——1000 是过去公开宣传过的合法上限,也正是最容易被人手填进去的整数,而它的默认值只有 60。
binance-trading-bot · 中文排错手册
这一页把官方排错文档整理成中文,按「症状 → 真实原因 → 具体动作」组织。里面多数条目是官方文档直接写出的原文:币安的 -2014 与 -2015、保存时那句 order sizing was not verified、配置上限收紧之后的两条只读 SQL、以及会锁定资产的孤儿单。
官方给出的排查顺序是四问。请按顺序走,不要跳步——前面三问没过,看第四问会得出错误结论。
未启用的 Profile 不会做任何新决策。预期看到:面板上该 Profile 的卡片是启用状态;若你之前用急停停过它,它会带着 kill-switch 标记。
在账户的 API keys 页面,状态必须是正常的。预期看到:绿色状态。若不是,问题只可能在三处——Key 本身、它的权限、或者 IP 白名单,按第 3 节处理。
「什么都不做」是常见且有效的决策,不是故障。预期看到:在 History → Logs 里,每一行都写明了该 tick 决定了什么、依据哪些数字。如果行太稀疏、不足以解释某个 tick,就在该页开启 Capture every tick,等它再次发生。
没有可动用的资金时,策略就停在等待状态。预期看到:Profile 的预算额度与账户里可用的报价资产余额。需要提醒的是,同一账户下的多个 Profile 共享同一个钱包,预算要按账户整体额度来规划。
这些故障的共同点是「容器在,但对外不可用」。官方把原因写得很具体,照着表查比盲重启有效。
| 症状 | 真实原因 | 处置 |
|---|---|---|
/readyz 返回 503,原因是 redis ping failed | Redis 容器还没进入健康状态 | 先看 docker compose logs redis;官方说明这通常是宿主机端口冲突 |
/readyz 返回 503,原因是 db ping failed | Postgres 的健康检查还没通过 | 看 docker compose logs postgres;官方说明首次启动时扩展初始化可能需要 10 秒以上,属于正常等待 |
| 浏览器里 API 请求被 CORS 拦下 | WEB_ORIGIN 与地址栏里的地址不一致 | 改 .env 里的 WEB_ORIGIN,然后 docker compose up -d 让 api 重新加载。该值是一个允许来源清单,必须是精确的 scheme://host:port,不支持通配符 |
docker compose pull 被限流 | Docker Hub 的匿名拉取配额用完了 | 先用任意一个 Docker Hub 账号执行 docker login,再重试拉取 |
backup 服务日志出现 dump failed (exit 1) | Postgres 密码不匹配 | 核对 .env 里的 POSTGRES_PASSWORD 是否与容器实际使用的值一致 |
容器都起来了,但 docker compose ps 里有服务不是 healthy | 依赖链还没走完,或上面某一条正在发生 | compose 用健康依赖串起了启动顺序,非 healthy 的那个服务就是根因所在;配合 logs -f 看它自己的输出 |
| 面板能打开但页面内容与预期不符 | 服务器地址与当初设置的 WEB_ORIGIN 不一致 | 对照部署时设置的 WEB_ORIGIN 与你现在访问的地址 |
| api 与 worker 的构建版本不一致(面板状态栏有提示) | 半成品部署:两个进程跑着不同的代码 | 重启 worker 让它们同步,细节见本页「构建版本偏移」一节 |
/api 与前端同源,宿主端口由 APP_HTTP_PORT 决定,生产默认 80);9100 是 api 的管理端口,9101 是 worker 的管理端口,两者默认都只绑回环地址,所以要从服务器本机上 curl,公网请求一定失败。以官方文档与 .env.example 为准。币安的错误码是判断责任在哪一侧的最短路径。下面这几条是官方文档直接列出的。
| 报错原文 | 含义 | 处置 | 依据 |
|---|---|---|---|
-2014 | API Key 格式不正确 | 多半是粘贴时带了首尾空格或前缀:去掉引号与空格后重新粘贴一次 | 官方部署 runbook 排错表 |
-2015 | 请求被币安配置拒绝 | 两种可能:该服务器的出口 IP 不在 Key 的白名单里,或者这个 Key 没有开通现货交易权限 | 官方部署 runbook 排错表 |
| 订单被拒(金额低于最小下单额、价格离市场太远等) | 订单违反了该币种的交易规则 | 在 History → Logs 里展开该行的 Context,里面是币安返回的完整拒绝载荷;据此调整预算或步长 | 官方排错文档 |
| worker 调币安的 REST 明显变慢 | 按 IP 维护的权重调节器正在主动限速,把调用压在币安每分钟上限之下——这是设计行为 | 没有可调开关。如果慢到反常,去日志里找一个反复重复同一条 REST 调用的失控循环 | 官方部署 runbook 排错表 |
日志出现 weight governor: Redis unavailable | 指向 Redis 不可用,而不是权重问题 | 按第 2 节的 Redis 相关条目处理(容器健康、端口冲突) | 官方部署 runbook 排错表 |
| Key 状态一直是红的,但权限看起来都勾了 | 服务器出口 IP 变了(换机器、换网络、重启后公网地址变化) | 在服务器上执行 curl -s ifconfig.me 取当前出口 IP,把它加进币安 Key 的白名单 | 官方 install 文档第 8 步 |
排查不交易时,最有信息量的界面不是仪表盘,而是单个币种的 Logs 标签。它逐条记录每个 tick 判断了什么、依据哪些数字。
| 你看到的提示 | 它其实在说什么 | 该做什么 |
|---|---|---|
任何 order sizing was not verified 类告警 | 你刚才那次修改已经保存成功(保存策略配置、添加币种、启动回测都成功了)。告警说的是服务器有一项检查没做完,不是你做的事失败了;没有任何内容被回滚,你也不需要重做 | 什么都不用撤销。按下面三条对应处理即可 |
Binance … trading rules have not loaded yet | 该币种的交易规则(最小下单额、价格与数量步长)不在短期缓存里,后台刷新通常几分钟内补齐 | 等几分钟后重新打开该页面,或再保存一次以触发检查 |
No … price is cached for this symbol yet | 价格只为运行中的 Profile 缓存,刚加进列表的币种还没有价格,属正常现象 | 等该 Profile 启用并开始跟踪它即可 |
These settings could not be read by the strategy that would run them | 保存下来的配置与该 Profile 的策略预期不再匹配,通常发生在换过策略之后 | 打开 Strategy 页重新保存一次配置,让它对齐 |
| 检查真的发现问题时(例如买入预算低于该币最小下单额) | 这时不是告警而是直接拒绝保存并报错 | 按错误提示把预算或参数改到合法范围再保存 |
策略的配置 schema 可能在某个版本收紧上限。已存进数据库的超限值不会被自动改写,于是出现一个很别扭的状态:交易照常,解析路径静默降级。
trailing-trade 首买窗口 candleLimit 的上限由 1000 收紧为 999;momentum 慢线 EMA 周期的上限为 998。candleLimit 是首先该查的一个——1000 是过去公开宣传过的合法上限,也正是最容易被人手填进去的整数,而它的默认值只有 60。
实时 tick 路径读取存储的配置时不做解析,所以那个 Profile 会继续交易。但所有需要解析的路径会安静地失效:领养孤儿单、删除 Profile 时证明挂单归属、live gate 的回测匹配、以及保存配置本身。
删除一个配置无法解析的 Profile,会丢掉「订单归属证明」里的指纹那一半。机器人自己记录过的单仍会被认领并撤销;它没记录过的单只剩指纹可认,于是不会撤,继续挂在币安上变成孤儿单。个别币种上甚至不会有日志提示。
| 要点 | 说明 | 为什么 |
|---|---|---|
| 两条 SQL 都要看 | 只有当两条都返回空时才算没问题 | 只查第一条、结果为空,什么都证明不了:一份合法的 Profile 配置恰好是非法逐币覆盖最容易藏身的地方。解析的是合并后的配置,逐币覆盖里一个非法值就能让那个币种单独出问题 |
为什么用 jsonb_path_exists 而不在 WHERE 里强转 | 官方明确写成路径断言 | PostgreSQL 不保证 > 999 这样的比较会先于相邻的 ::numeric 转换执行;只要有一行在该路径上存了非数字值,整条查询就会以 invalid input syntax for type numeric 中止——而这正是你被要求「删 Profile 前先跑」的那条查询。路径断言在宽松模式下对非数字操作数不匹配任何行,且 config 与 override_config 本来就是 jsonb,不需要转换 |
| 怎么修 | 把被标记的那个值改成合法值后保存:首买窗口 ≤ 999,慢线 EMA 周期 ≤ 998 | 保存这个动作本身就是修复手段,同时也是被那个过期值挡住的操作——表单会在该字段合法之前一直拒绝保存 |
| 改哪里取决于它来自哪条查询 | 第一条命中的行在 Profile 的配置表单里修;第二条命中的行要在该币种的逐币覆盖编辑器里修 | 编辑 Profile 表单不会动到逐币覆盖里的值 |
| 时机 | 务必在下一次删除该 Profile 之前修完 | 否则删完之后只能去孤儿单页面确认有没有遗留,别指望日志列全 |
孤儿单是指在币安的挂单簿上处于打开状态、但没有任何 Profile 在跟踪它的订单。它必须由人来处理,原因只有一个但足够严重。
一张挂在市场上的单会锁住它对应的基础资产,并且可能让一个真实持仓处于没有保护的状态。这不是账面上的小麻烦,而是实际占用了你的可动用余额与风险敞口。
在账户层面有一个专门的 Orphan orders 页面。预期看到:机器人能识别归属的单会列出来供你认领(adopt),其余的需要你决定取消还是保留。
该页面同时解释了每种策略能重新推导出哪些订单号,这也是「哪些可以认领」的判据来源。
常规的停用与急停都不会撤销挂单;删除 Profile 是唯一会主动取消该 Profile 挂单的路径。
机器人自己记录过的订单,即使配置无法解析也仍然会被认领并取消(包括它挂下的保护性止损单)。但它从未记录过的订单——也就是记账环节出问题留下的那些——只剩指纹可以认领,因此不会被取消,会继续留在币安上变成孤儿单。
每个被监控的币种都有一个自己的工作区:实时行情、当前信号、挂单与手动干预都在同一屏。排查单个币种的异常时,这是起点。
工作区之外还有一类故障与「哪个进程在跑哪份代码」有关。官方的 GET /status 是一个公开、无需登录的端点,只返回 api 与 worker 的构建 SHA、启动时间,以及最近一次应用迁移的时间戳——它只泄露 SHA 和时间,不含任何账户数据。面板状态栏会轮询它并给出提示。
| 你看到的 | 它的含义 | 处置 |
|---|---|---|
| api 与 worker 的 SHA 不一致 | 两个进程跑的代码不同,典型的半成品部署(只更新了一半) | 重启 worker 让两者同步 |
| worker 的启动时间早于最近一次迁移 | worker 正在使用比它启动时加载的更新的数据库 schema | 重启 worker |
worker: null | worker 的心跳键不存在——它已经不在运行,或者自上次重启以来从未写过状态 | 先确认容器状态与日志,再按第 2 节的启动故障表处理 |
| 想把构建版本注入进去 | SHA 是镜像构建时通过 GIT_SHA 构建参数注入的;没有它时会退回本地 git SHA,在生产用的 alpine 镜像里(不带 git 二进制)则变成 unknown | 构建时显式传入,见下面的命令 |
如果你手上已经有某个币(在币安 App 买的,或者转账进来的),想让它参与管理和卖出,需要把均价告诉机器人。有两条路,任选一条。
添加币种的界面里有一个选填的 Average entry price 字段。填上它,币种就被添加且同时完成了定价,一步到位。
币种页面 → Logs 标签 → Show advanced → Set average entry price。预期结果:两条路径都会写入成本基础台账(ledger),并投递一个 apply-avg-entry-price 任务,把运行中的策略进场价强制设为该值,下一个 tick 就开始接管该持仓,不需要重启。
这条写入是权威的:普通的一次 tick 或者重新配置都不会覆盖一个已经定价的持仓,所以它可以用来修正机器人正在管理的仓位的成本基础。同一入口的「Delete average entry price」以相同方式清除它。
持仓数量是机器人每 tick 从你的钱包读取并钉到钱包真值上的。你记录的数量只是它的一个上界,不是替代品——机器人写入的永远不会超过钱包实际持有的量(上下一个可交易增量)。所以一份过期或夸大的记录不会把策略要卖出的仓位放大。
Not held — nothing sellable backs this cost basis 时含义是:钱包里该币的余额低于最小可交易步长,或者只值交易所最小下单额的一个零头,因此没有任何东西可卖,机器人不会给它建仓位,也不会显示浮动盈亏(对一个它拒绝接管的仓位谈盈亏没有意义)。你记录的价格仍然被保存。提示会自动消失的条件是:每 15 分钟一次、横扫每个币种的持仓对账通过;或者该币出现一次买入成交;或者你重新保存一次价格。对账只有在能正面确认余额足以支撑该记录时才会清除它——没有该币缓存价格、或该币还没被 tick 过时,它会等下一轮能作出判断的对账,而不是基于一次没做的检查就清掉。
分两层。应用层看单个币种页面的 Logs 标签,它逐条记录每个 tick 的判断与依据;进程层看服务器上和容器输出,例如 docker compose ... logs -f 跟踪应用日志。两者回答的是不同问题:前者是「策略为什么这么决定」,后者是「服务本身有没有异常」。具体命令与路径以官方文档为准。
不一定,而且大概率不是。官方明确说明「什么都不做」是常见且有效的决策,策略在等它的规则被触发。请按本页第 1 节的四问顺序确认:Profile 启用、Key 状态正常、买入条件确实没满足、账户有可用余额。真正需要处理的只有第二和第四问。判断依据以官方文档与 Logs 记录为准。
-2015 表示请求被币安的配置拒绝,原因通常是服务器出口 IP 不在 Key 的白名单里,或者这个 Key 没有开通现货交易权限。它本身是一次被拒绝的请求,不涉及资金动作;但它同时提示了一件事——白名单没配好。官方把 IP 白名单视为「密钥泄露后唯一的主要缓解措施」,所以请尽快补上。以官方文档与币安侧的说明为准。
因为能撤销的范围是有限的。机器人自己记录过的订单会被认领并取消,包括它挂下的保护性止损单;但它从未记录过的订单只剩指纹可以认领,于是不会被取消,会继续挂在市场上成为孤儿单。个别已被解绑且没有持仓的币种上,甚至连日志都不会有。所以删完 Profile 之后要主动去账户的孤儿单页面确认。
不会让它停摆,但会安静地削弱它。存下来的超限值不会被改写,实时 tick 路径读配置时不解析,所以交易照常;受损的是所有需要解析的路径:领养孤儿单、删除 Profile 时的订单归属证明、live gate 的回测匹配、以及保存配置本身。处置方式是先用本页第 5 节的两条只读 SQL 查清楚,再把值改回合法范围保存,且务必在下一次删除该 Profile 之前完成。以官方文档为准。
有,但要分清任务。EasyClaw 的本机技能里有加密货币行情、策略回测与出图这类研究能力,适合只想查数据、跑研究、看图表的场景,而且不需要服务器与币安账户。但 EasyClaw 没有下单类技能,不能替你做实盘执行,也无法替代本页这些与运行状态、挂单、账户权限相关的排查。另外需要明确:binance-trading-bot 与 EasyClaw 之间没有已证实集成,这条路线只是另一类任务,不是同一件事的简化版。
不能。本页覆盖的是官方文档明确列出的症状与原因,属于第一手可核验的部分。没被官方写明的现象、以及需要读代码才能判断的深层问题,不在本页范围内,请以官方仓库与官方文档为准,必要时到项目仓库提 issue(安全问题请走官方的 SECURITY 渠道而不是公开 issue)。