基于 Rust 编写的高性能币安 USDⓈ-M 合约网格量化交易机器人,支持同时配置和运行 SOLUSDC、BTCUSDT 等多个交易对。配套独立 Web 监控与控制面板,支持 WebSocket 毫秒级行情推送、只做 Maker(Post-Only GTX)挂单、动态滑动窗口、网页直接在线配置策略以及内嵌 SQLite 数据库持久化。
- 无需配置文件,网页直接配置:
- 启动无需任何
config.toml或环境变量文件,直接打开浏览器控制台即可配置所有参数。 - 可在网页上随时修改:交易对(如 SOLUSDC)、网格间距(如 0.1)、每格金额(如 100 USDC)、买入窗口深度、卖出窗口深度、API Key & Secret 等;策略固定使用 Post-Only Maker 挂单。运行模式由全局 API Key 决定:已配置 API Key 和 Secret 时以实盘运行,未配置时以模拟盘运行。
- 点击「保存并立即生效」,策略引擎自动重新对齐和更新挂单。
- 启动无需任何
- 内嵌 SQLite 数据库数据持久化:
- 使用内置嵌入式 SQLite(
data/bot.db),零外部数据库依赖。 - 自动持久化保存策略运行配置、历史成交记录、币安已实现盈亏与手续费、网格循环统计等。
- 重启后恢复配置、成交记录及机器人挂单元数据,并先与交易所对账;无法确认交易所状态时暂停新增实盘订单。
- 使用内置嵌入式 SQLite(
- 安全管理员密码认证:
- 密码来自启动配置:通过命令行参数
--admin-password或环境变量ADMIN_PASSWORD指定(至少 6 位),不写入 SQLite。建议使用环境变量,避免密码出现在进程列表中。 - 未设置密码时不启用认证:控制台和交易 API 无需登录即可操作,任何能访问监听端口的人都能操作。请只在受信任网络或本机这样运行。
- 启用密码后的全站鉴权:敏感操作(参数配置、策略启停、挂单撤销、密钥信息)及行情推送均受会话 Token 保护;会话撤销与已在执行的请求之间仍存在并发窗口。
- 在线会话管理:会话 24 小时后失效,支持退出登录;登录尝试有频率限制。每次重启后端都会清除持久化会话;修改启动密码后需重启并重新登录。
- 密码来自启动配置:通过命令行参数
- Maker 单(Post-Only GTX):
- 使用
timeInForce: "GTX",只以 Maker 方式挂单;拒单后先对账再更新窗口。 - 具备自动价格检查与防穿仓拒单重试机制。
- 使用
- 严格的币安精度规则适配:
- 自动在启动时向币安查询
exchangeInfo。 - 严格按币种的
tickSize对价格规范化、按stepSize对数量截断,并严格校验minNotional(最小下单金额),杜绝非法参数拒单。
- 自动在启动时向币安查询
- 相邻网格与动态挂单窗口:
- 以
0为固定锚点,买卖共用相邻档位,挂单窗口围绕标记价格移动。间距0.1、标记价格111.86、买卖窗口各3时,买单为111.8 / 111.7 / 111.6,卖单为111.9 / 112.0 / 112.1。标记价格本身不挂单;尚未取得标记价格时暂用最新成交价。 - 最近一次已确认成交只用于避免立即在相同价格附近重复成交:新档位与该成交价至少相差一格。历史成交价不再锁定买单上沿或卖单下沿;例如此前买入
110.2,标记价格上涨到111.86后,买单仍会移到111.8 / 111.7 / 111.6。遇到保留档位时跳过并补齐附近窗口,后续成交会更新保留档位。 - 同价防护按交易对及运行模式分别从完整成交历史恢复,不受页面最近成交数量限制。同一订单的多次部分撮合仍计为一笔订单成交;升级前已挂出的订单和撤单期间发生的成交以交易所实际结果为准。
- 不追踪开仓批次成本,不生成配对补单。成交后统一补齐当前窗口;每个普通单按配置目标金额和交易所数量步长向下取整,尾仓平仓单使用剩余可平数量。
- 仅使用 Post-Only GTX 挂单,提交前仍用最新成交价检查买卖方向,拒单后重新对账,不降级为吃单。间距必须是交易所价格步长的正整数倍,不支持的配置会在撤单前被拒绝。修改间距会围绕标记价格重新计算相邻档位。
- 所有未成交订单都遵守当前窗口和方向规则,包括旧版止盈单和余量单。窗口内保留已有订单的排队位置,同方向同价重复单保留较早的一笔;窗口外和方向不符的订单先撤销并确认终态及期间成交,再补齐窗口。部分成交的原订单先核实和完成,不创建同价替代订单。
- 每个交易对可独立选择「做多 / 做空」,默认做多,旧配置自动按做多读取。做多时买入开仓、卖出平仓;做空时卖出开仓、买入平仓。配置持仓上限后,即使未开启达到上限时暂停,开仓单仍受已有持仓、未成交开仓单预留和拟下单金额的合计敞口限制;超过上限时跳过该开仓单。平仓单只使用已有对应方向的仓位,扣除其他平仓单预留数量,并以
reduceOnly=true仅减仓方式提交。价格范围、最近成交价和仓位限制可能使挂单数量少于窗口配置。 - 策略参数可选择「达到最大持仓名义价值时暂停策略」(新增交易对表单默认开启,旧配置缺少该设置时默认关闭;开启需填写最大持仓上限)。持仓数量绝对值 × 标记价格达到或超过上限时,暂停整个策略并发起机器人挂单撤销,保留持仓;撤单结果需检查交易所挂单和策略日志。未取得行情标记价格时依次使用持仓标记价格、最新成交价。成交、行情更新及配置生效后均会检查。提交新开仓单前,还会按交易所步长取整后的完整开仓单数量检查成交后的预计持仓名义价值;若将超过上限,立即暂停,不提交该开仓单,也不缩量补齐。预计值刚好等于上限时允许挂单,持仓实际达到上限后暂停。未成交开仓单继续预留合计敞口,但仅因这些预留导致新增开仓单超限时只跳过新增开仓单,等待已有开仓单成交。暂停状态持久化,名义价值回落后不会自动恢复;手动恢复时若仍达到上限或下一笔开仓单将超限,会再次暂停。
- 另可开启「达到上限时仅撤开仓单」(与暂停策略互斥,需设置最大持仓上限):持仓名义价值(持仓数量绝对值 × 新鲜标记价格,取值规则见下方保护说明)达到上限时,只撤销开仓方向的窗口挂单,策略保持运行,继续维护
reduceOnly平仓窗口和余量单;回落到上限以下后下一轮自动恢复开仓。该模式只依据已成交持仓判断,不做下一笔成交后的预计值检查,开仓单仍受上方合计敞口限制约束。 - 可选「强平距离阈值(%)」:持仓标记价格距交易所返回的强平价不超过该百分比(占标记价,多头看下方、空头看上方)时,只撤销开仓方向的窗口挂单,策略保持运行并继续维护平仓单;距离回升后自动恢复开仓。每笔开仓单提交前也会按当时的持仓与行情复核强平距离。强平价为 0(无持仓或交易所未返回)、模拟盘无强平价时不生效。该保护不会平仓,也不会降低杠杆。
- 上述两类撤开仓保护优先于行情新鲜度、待恢复意图和全局补单准入检查;未满足补单条件时仍会先处理保护性撤单。保护判断优先使用 15 秒内的行情标记价,否则使用新鲜的持仓标记价(有效期为同步间隔的 3 倍,至少 30 秒),不接受来自未来的时间戳。已有持仓且相关保护生效时,如果两个标记价来源都不可用,保守限制开仓并尝试撤销开仓单,保留平仓单;最新成交价不用于代替强平距离所需的标记价。
- 剩余仓位满足最小数量和金额时,在当前允许的平仓档挂一笔余量单(做多为卖单,做空为买单)。明确标记的余量可以合并,小额追加最多每 30 秒更新一次;合并目标同样遵守标记价格窗口和同价防护,不使用开仓成本定价。
- 余量合并先撤单、核实期间成交、刷新仓位,再按持久化计划提交。响应丢失或重启时先查询固定订单 ID;已接受的目标继续核实,查询不确定时阻止新增订单。确认未接受且目标已不符合当前窗口、方向或最近成交价限制时,结束旧计划并重新补窗口。
- 旧版配对意图只用于恢复可能已经接受的交易所订单;确认不存在的旧意图不再提交。新成交不再写入配对意图,历史配对价差与循环统计保留,新窗口成交只更新实际成交及盈亏统计。
- 切换做多 / 做空前不能持有相反方向的仓位(已有同向仓位可直接切换为对应方向)。保存时先核实仓位方向、撤销并对账旧方向挂单,再次确认无反向持仓后才切换;撤单期间若发生反向开仓成交,保留原方向并暂停。已有持仓方向与配置不一致时也会暂停并撤销机器人挂单。
- 实盘仅支持币安单向持仓模式(One-way / BOTH),检测到双向持仓模式会拒绝交易。机器人不会替用户切换账户持仓模式。币安下单接口说明中规定
reduceOnly不适用于双向持仓模式。 - 相邻网格和连续同价限制不保证盈利,多头平仓可能低于历史持仓成本,空头平仓可能高于历史持仓成本。
- 以
- 独立的实时 Web 控制台:
frontend/使用 React、TypeScript、Ant Design、TanStack Query 和 Recharts;Rust 后端只提供 API 与 WebSocket。开发时 Vite 代理 API,生产环境由 Nginx 托管静态资源并转发请求。- 左侧固定侧栏列出全部交易对(状态点和多空箭头)并提供总览、设置入口;窄屏(≤900px)收为顶部栏、底部固定“总览 / 交易对 / 设置”标签栏和抽屉。
⌘K(Windows / Linux 为Ctrl+K)打开命令面板,可跳转页面、切换交易对、编辑参数、暂停、恢复、重建网格、撤单并暂停、切换主题和退出,并记住最近使用的命令;这些操作沿用原有确认流程。在非输入状态下,?打开键盘快捷键说明,g o、g s、g n分别跳到总览、设置和新增交易对,[、]在交易对之间切换(停留在参数页时保持在参数页)。 - 策略总览支持交易对搜索、排序、状态和模式筛选、卡片操作与批量启停;默认按运行中优先、其余状态在后分组,各组内按持仓绝对金额从大到小排序,金额相同按交易对名称排序。顶部信号条中的“异常 / 已暂停 / 已停止 / 实盘策略”可点击筛选。搜索、排序和状态筛选以及详情页、设置页的标签页都写入网址,刷新或分享链接后保持。实盘和模拟盘的共享账户都按计价资产取最新账户快照去重,筛选不影响账户汇总。
- 策略卡上的暂停 / 恢复为独立按钮,请求期间显示“暂停中… / 恢复中…”;重建网格和撤单并暂停在更多菜单中,删除策略只在策略参数页提供,删除实盘策略需输入交易对名称确认。批量启停的结果在抽屉中按交易对列出,只有确定未提交的交易对提供重试,结果不明的需先核对状态。
- 策略卡显示当前持仓加权均价作为开仓价格,以及标记价相对开仓价的涨跌幅;做空时同样按价格涨跌显示,不按杠杆调整。无持仓或价格不可用时显示
--。 - 策略卡的今日成交及买单 / 卖单数量按北京时间当天已成交笔数统计;数据不可用时显示
--。 - 账户权益趋势同时展示近 24 小时的整点数据和近 7 天每天北京时间 00:00 的权益总额,并提供最近 30 天的每日运行快照(每天北京时间 00:00 自动归档前一日的账户概览、成交笔数、已实现盈亏与持仓概览);默认选择当前账户,实盘不同 API Key 的历史分开显示。模拟盘共享资金后的快照与旧版按交易对累加本金的历史分开显示,旧记录保留原值,避免本金口径变化被连成亏损。身份未确认的旧实盘或未知模式快照可单独查看,显示为不连线的数据点;缺失或不可用的快照不会补值。
- 交易对详情展示行情、持仓、盈亏、订单、成交和日志,以及今日成交和网格深度图。详情通过 WebSocket 更新,断流后通过 HTTP 自动刷新;超时数据会提示,暂停和撤单仍可使用。数据超过 10 秒未更新时,数值会变淡并显示“更新于 N 秒前”,避免把旧数字当作实时数据。
- 总览只在该页面打开时轮询轻量摘要;各交易对的完整挂单、成交和日志由详情页获取。侧栏和账户概览共用轻量账户推送,首次通过
GET /api/accounts读取;连续 5 秒没有有效账户推送后,每 3 秒通过该接口补取,恢复推送后停止轮询。拒收的旧帧不会延后补取。账户观察与元数据模式不一致或数据过期时,依赖最新状态的命令会暂时禁用。 - 控制台外壳及各页面按需加载,图表在使用时加载;连接和登录入口不提前下载图表依赖。
- 挂单、成交历史和运行日志可按方向或级别筛选,并导出当前筛选结果的 CSV(UTF-8 带 BOM,以
=、+、-、@开头的文本会加前缀避免被表格软件当作公式执行);点击价格可复制原始数值。窄屏下这三张表改为卡片列表。 - 全部策略都在模拟盘时,总览顶部显示可关闭的新手指引(检查参数 → 观察运行 → 再接入实盘),关闭后不再显示。
- 新增交易对、交易对详情和策略参数页面提供面包屑,可返回策略总览或对应交易对详情;保存或删除进行中暂不能通过面包屑离开。
- 策略、全局连接及通知设置(Telegram / ntfy)使用独立表单。离开未保存的表单或还原修改时会提示;实盘恢复、切换实盘配置、重建网格、撤单和清理历史均需确认。保存或添加实盘策略时,确认框逐项列出修改前后的值,方向、价格区间、最大持仓、持仓上限处理方式和每格金额高亮显示。策略参数页的保存栏显示“已修改 N 项”,可展开查看每项的旧值和新值。
- 策略参数页按当前标记价(新增交易对时选中交易对会自动查询并展示最新价格,同时带出标记价、价格步长、数量步长、最小下单量和最小名义金额,并将网格间距默认设为标记价格的 1%)预览将挂出的买卖价位、相对标记价的相差百分比及每档按数量步长截断后的预计数量与金额,计算与引擎一致;每格金额低于最小名义金额,或在参考价格下按数量步长截断后低于最小下单量/最小名义金额时会拦截保存,预览也会将无法挂单的档位标红提示;开仓侧全部成交的新增名义价值按可挂单档位的截断后金额求和,超过最大持仓名义价值时显示风险提示但不拦截保存;网格间距在输入时校验为价格步长的正整数倍,价格上下限在输入时即校验为大于 0 且下限小于上限。网格间距低于标记价的 0.04%(按 Maker 往返手续费 2 × 0.02% 估算)时给出提示,仅为提示,不拦截保存;实际费率以账户为准。当
floor(最大持仓 / 每格金额) × 间距 / 标记价小于 3% 时,预览还会显示按目标金额估算的格数和价格距离。3% 仅为容量提示参考,不是经验证的盈利或风险阈值;估算未计入已有持仓、挂单预留和数量取整,不能预测下一次触顶。提示会区分暂停、撤开仓单和限制新增开仓三种行为;平仓仍按当前窗口执行,可能产生已实现亏损。 - 暂停或撤销机器人挂单会停止自动补单;控制请求成功只表示暂停状态已保存且撤单动作已提交,不代表交易所已完成撤单或核实。请检查交易所挂单和策略日志;撤单不平仓。恢复运行后重新对账并补齐网格。
- 控制请求发出后若返回错误,控制台会提示结果不确定并要求核对,即使返回的是业务错误也如此;请刷新状态并检查交易所挂单和策略日志,再决定是否重试。
- 重建网格仅适用于运行中的策略;暂停或停止时需先恢复。概览数据超过 10 秒未更新时会提示连接异常,并禁用依赖最新状态的恢复和重建操作,暂停仍可使用。
- 运行模式由 API Key 决定:
- Paper Trading(模拟盘):未配置全局 API Key / Secret 时运行,实时订阅币安真实 WebSocket 行情,在本地撮合并持久化账户、持仓和收益统计。
- Live(实盘):在「全局配置」保存 API Key 和 Secret 后运行,连接币安合约主网执行真实真金白银挂单。API Key 和 Secret 必须同时配置或同时清空。
- 切换运行模式须在「全局配置」中保存或清除 API 凭证;切换成功后所有交易对保持暂停,核对目标环境的配置、持仓和挂单后须手动确认并恢复。旧模式撤单失败时配置不切换;目标模式对账或撤单失败时,新配置可能已经保存,仍保持暂停,需检查实际状态。
- 全套 Docker 容器化与 GitHub Packages 支持:
- 包含多阶段构建
Dockerfile与docker-compose.yml。 - 配置 GitHub Actions 自动化 CI/CD,仅在发布 GitHub Release 后编译多架构镜像,将后端和前端镜像发布至 GitHub Packages(
ghcr.io/zuoban/binancebot和ghcr.io/zuoban/binancebot-frontend)。
- 包含多阶段构建
- Telegram 与 ntfy 通知:支持独立或同时启用 Telegram(Bot Token + Chat ID)与 ntfy(默认
https://ntfy.sh或自建服务根地址 + Topic + 可选 Bearer 访问令牌)。启用后,每笔确认成交的标题按“方向|交易对|成交均价|成交金额”显示,成交均价按该订单实际成交均价去除尾随零展示,成交金额保留 2 位小数。计数按北京时间当天 00:00 起和成交所在小时分别统计,买单、卖单分开计数。正文展示“成交笔数:当天计数D|本小时计数H”和成交后的持仓金额,不再展示账户权益、人民币估值及可用余额;平仓单附已实现盈亏(做多为卖单,做空为买单)。持仓金额按持仓数量绝对值 × 标记价格计算,以计价资产显示并保留 2 位小数;没有标记价格时暂用最新成交价,持仓或估值价格暂不可用时显示--。每天北京时间 00:00 生成前一日运行数据快照(账户概览、成交笔数、已实现盈亏、持仓概览)并自动发送通知。策略启动、恢复及暂停不发送通知;全局风控触发时发送告警(ntfy 使用高优先级priority: 4),包含触发原因和北京时间,同一轮持续触发只发送一次,风险解除后再次触发会重新通知。各通知渠道异步独立发送,单渠道失败记录日志且互不阻塞。模拟盘及实盘均支持。
无需创建配置文件,直接运行:
# 启用登录保护
ADMIN_PASSWORD='请替换为强密码' docker compose up -d --build
# 或不设置密码(无需登录,任何能访问端口的人都能操作)
docker compose up -d --build也可以把 ADMIN_PASSWORD 写入当前目录的 .env 文件。设置后打开控制台需输入该密码登录;未设置时直接进入控制台。在「策略参数」页面填写交易对和网格参数,点击「保存并立即生效」。API 密钥以及 Telegram / ntfy 通知在独立的「全局配置」页面保存。设置会存入 SQLite;后续启动继续使用页面保存的设置。
程序只从 SQLite 读取策略配置;管理员密码可通过 ADMIN_PASSWORD 提供。Compose 的 BOT_VERSION 只选择镜像版本,不参与策略配置。旧的 config.toml、.env、BINANCE_*、GRID_*、TELEGRAM_*、PAIR_*、TRADING_PAIRS 和 SERVER_* 环境变量不再读取,也不再支持 --config、--symbol、--interval、--amount、--buy-window、--sell-window、--live 或 --testnet。升级前已保存到数据库的配置继续保留;旧的单交易对数据库会自动转换为页面可管理的交易对列表。
测试网模式已移除:旧全局或任一交易对配置保存了 is_testnet: true 时,升级会清除全局及全部交易对的旧 API Key / Secret,将所有已配置策略改为模拟盘并持久化暂停,包括原来的实盘策略,避免旧密钥被重新继承后自动进入实盘。配置与暂停状态在同一事务中迁移,重启不会重新暂停已经人工恢复的模拟策略。原测试网的运行状态、挂单意图、恢复元数据和统计在升级时删除,成交记录保留并归入 UNKNOWN;其他模式的恢复证据、历史与持仓记录保留。配置接口收到 is_testnet: true 时会拒绝请求,不会按实盘处理。
不涉及上述测试网迁移时,运行模式由 API Key 是否配置决定:升级前保存了 API Key 但设为模拟盘的配置,升级后按实盘处理,并在模式变化时保持暂停。恢复实盘前须重新核对凭证、主网持仓及挂单,再逐个手动恢复策略。
从旧版本升级时,SQLite 中的旧管理员密码表会在首次启动时删除并压实数据库。升级后首次启动前必须设置 ADMIN_PASSWORD 或 --admin-password,否则控制台将以无认证模式开放,任何能访问端口的人都可以操作。
首次启动提供 SOLUSDC 模拟盘默认参数,不需要 API 密钥。在「策略参数 → 交易方向」选择「做空」并保存,即可运行卖出开仓、买入平仓的空头网格;各交易对的方向独立保存。添加其他合约时,请在页面中选择与该合约价格步长相符的网格间距;新增交易对默认暂停,需检查配置后手动恢复。
前端容器默认仅将宿主机回环地址 127.0.0.1 的 8080 端口映射到容器的 80 端口,HTTP 传输未加密;远程访问请参照下方指南配置安全访问。Compose 启动后端时固定监听容器内的 0.0.0.0:8080,不修改数据库中保存的监听配置。前端通过 Docker 内部 DNS 动态解析后端地址,后端容器重建后可自动恢复连接。独立运行后端时,新数据库默认监听 127.0.0.1:8080;已有数据库中保存的监听地址不受默认值变更影响,若此前保存了 0.0.0.0,升级后仍会监听所有接口,请在控制台修改监听设置并重启。也可使用 --host 和 --port 临时指定当前进程的监听地址和端口;日志级别可通过 RUST_LOG 调整。
启动后在浏览器打开控制台: 👉 http://localhost:8080
所有策略配置在页面上填写保存后,会自动存储在 ./data/bot.db 中。
后端容器以非 root 用户(UID/GID 10001)运行。绑定挂载的 ./data 目录及其中的数据库、-wal、-shm 等文件必须归该用户所有,否则程序会拒绝启动。首次部署或从旧版(root 运行)升级前,请先停止服务并执行:
mkdir -p data && sudo chown -R 10001:10001 data && sudo chmod 700 data如需使用其他宿主机用户,可通过 BOT_UID 和 BOT_GID 环境变量覆盖,并让 data 归同一用户所有。
管理员密码可选,由后端启动参数或环境变量提供,不会显示在日志中,也不写入数据库。未设置时无需登录即可操作;设置或修改密码后需重启后端生效,重启会清除所有登录会话。
首次使用实盘时机器人默认暂停,需在控制台确认配置后手动恢复。暂停状态会写入数据库,重启后继续保持暂停。
远程访问请通过 HTTPS 反向代理、SSH 隧道或受控 VPN 使用控制台;不要把 HTTP 端口直接开放到公网。API 凭证保存在 data/bot.db,请限制该文件的访问权限并做好备份。
Unix 上新建的数据库及目录使用私有权限;已有数据库及其 -wal、-shm、-journal 文件如果允许组或其他用户访问、文件本身是符号链接,或者所有者不是服务的有效用户,程序会拒绝启动并提示修复。升级前请停止服务,检查并调整这些文件的所有权与权限(例如仅允许服务用户读写);Docker 用户应注意容器内运行用户和挂载文件的所有者。还须保护数据库备份和下载的导出文件。数据库路径应使用普通文件系统路径,不支持 SQLite file: URI;数据库目录及其父路径必须可信,权限位检查不涵盖 ACL。非 Unix 系统须通过操作系统的访问控制保护文件。
登录按后端看到的 TCP 来源限流,不信任客户端提供的转发头;默认 Compose 的 Nginx 代理会使所有用户共享同一来源额度。请限制管理入口的访问来源,并注意全局认证限流和并发保护在负载过高时也可能暂时拒绝合法请求。
同一账户、同一交易对请只运行一个本程序实例。机器人目前用 gb_ 订单前缀识别自己创建的订单,多个实例会相互识别并可能撤销对方订单。
收到 Ctrl+C 或 SIGTERM(例如 docker compose stop)时,程序关闭新增订单和恢复策略的准入,并保存暂停状态、撤销和核实机器人挂单,保留持仓。已经进入或跨过最后一次停机检查的请求仍可能发往交易所;停机检查与网络发送不是原子操作。停机前已受理的交易对添加或删除会完成并发布结果,排队和后续成员变更会被拒绝;等待期间其他可清理的引擎会并发开始停机,最终再清理所有成员。符合恢复资格且停机提交时复核通过的策略会保存停机前的运行状态;重启后仍须完成初始化、订单对账和风控检查,原本暂停或不符合恢复条件的策略保持暂停。每个引擎的停机请求与退出共用 30 秒期限,Web 服务另有 5 秒等待;在途成员变更、失败后的暂停持久化和恢复状态提交等可能超出期限,数据库工作也可能等待共享锁,因此这不是整个停机过程的硬上限。Compose 已设置 45 秒停机宽限,直接使用 docker run 时建议添加 --stop-timeout 45,但宽限时间不能保证覆盖所有等待。清理失败或超时会返回错误并保留订单恢复元数据,下次启动保持暂停并重新对账,需核实挂单后手动恢复。
删除交易对只有在取得成员锁及目标控制锁,并确认策略已暂停、内存挂单为空后才接管目标;若停机先发生,删除会被拒绝,目标可由提前清理处理。接管后的目标由删除流程处理,其他引擎仍可并发停机。提前停机失败或超时时会立即中止对应引擎,不必等待成员变更结束;后续仍需完成暂停持久化和错误汇总。
普通服务在打开数据库和创建策略之前注册退出信号,先绑定监听端口再启动策略。启动期间收到信号或部分策略准备失败时,不再启动后续策略,并清理已经准备的策略;有在途准备时等待其完成,避免丢失数据库写入,因而启动中断的等待也可能超过停机期限。初始化被中断时,非模拟盘清理会先恢复持久化的机器人订单,再撤销并核实;若清理也失败,启动错误会同时报告清理错误。
策略引擎启动前会记录运行中的安全标记,正常完成停机清理后清除;成功切换运行模式时,在保存新配置的同一事务中清除旧模式的标记并设置目标模式的标记。进程异常退出、暂停状态无法保存或停机清理失败后,重启将保持暂停;任何跨模式切换后也保持暂停。切换到此前异常退出且安全标记仍在的运行模式时,会撤销和核实目标模式恢复的机器人挂单。目标模式撤单或对账失败时保持暂停并保留恢复信息,需核实交易所持仓和挂单后手动恢复。若删除交易对失败且引擎无法重建,该交易对仍保留在全局风控中,其数据不可用会阻止启用的全局风控放行其他策略;请修复错误后重启并对账。
交易所返回执行结果未知(包括 -1006、-1007 和不确定的服务端错误)时,机器人保留原订单 ID,停止新增订单并等待对账。只有尚未确认接受的订单意图,在创建至少 30 秒后仍被交易所明确查询为不存在,才会释放预留;查询失败和已有交易所订单 ID 的订单不会按此规则清理。
「全局配置」中的「可用保证金比例下限(%)」与「可用保证金不足时暂停」共用同一套全局风控:任意策略的可用保证金占保证金余额的比例小于或等于该值时,暂停所有策略、撤销机器人挂单并保留持仓,需手动恢复。保证金余额小于或等于 0 时同样触发比例下限保护暂停。
最新成交价超过 15 秒未更新,或已有标记价格超过 15 秒未更新时,暂停新增普通单和余量单,也不根据过期行情移动挂单窗口。数据恢复且账户、订单对账有效后继续维护窗口;尚未取得标记价格时可使用有效的最新成交价。已有挂单仍可能在交易所成交,后台继续对账,手动暂停和撤单仍可使用。
每个交易对通过一条 /market WebSocket 组合连接接收成交价与每秒标记价格。成交价或标记价格缺失或至少 8 秒未更新时,下一次同步周期尝试通过 REST 补取;失败后按交易对及行情类型分别退避,成功或收到有效推送后重置。行情兜底使用较低的本地请求预算上限,给周期账户、持仓和挂单对账留出空间;持续高负载下,行情兜底仍可能被延迟。请求失败不会刷新行情时间,同步周期较长或发生网络延迟时,REST 兜底可能晚于 15 秒,过期保护仍会阻止新增订单。行情时间依赖本机时钟,需保持系统时间同步;明显过旧或超前的推送会被丢弃。
标记价格 REST 兜底在同一交易所地址的 10 秒内有至少 10 个不同交易对请求时,会共享全市场标记价格快照;请求开始时间作为行情时间,主网进行缓存。共享请求失败会短暂冷却,等待同一请求超过 100 毫秒的交易对会继续后续对账并按退避规则重试。快照没有对应交易对时使用单对请求。该优化降低多对断流时的标记价格请求量,但不保证在预算长期耗尽时每个交易对都能获得行情。
标记价和成交价 REST 兜底分别最多保留一个在途请求,完成后复核作用域和新鲜度并执行仓位保护;行情与对账就绪时继续维护窗口,包括当前无挂单的策略。暂停、停机或实盘对账未完成时不补单。
镜像仅在发布 GitHub Release 时构建并推送;面向 main 的 Pull Request 和推送到 main 都执行后端及前端质量检查(含前端 ESLint),单独推送版本标签或保存 Release 草稿不会更新镜像。版本标签应与 Cargo.toml 一致,例如 v0.13.0;应在最终代码提交后创建新标签,不移动已推送的旧标签。正式 Release 会更新 latest,预发布 Release 会发布对应版本镜像,但不会覆盖 latest。每次发布仍须通过后端和前端检查后才会构建镜像。CI 与后端 Docker 构建均固定使用 Rust 1.98.1,镜像构建按 Cargo.lock 锁定依赖。依赖安全审计(cargo audit 与前端生产依赖的 npm audit)由独立的 安全审计工作流 在依赖文件变更及每周定时执行,Dependabot 只提交次要和补丁版本更新(Cargo 与 npm 按生态合并为一个 Pull Request),大版本、Rust 与 Node 基础镜像需手动评估和升级;安全公告触发的更新不受此限制。
仓库 main 已将 GitHub Actions 的 checks 设为必需状态检查,并要求待合并分支跟上最新 main;管理员保留默认豁免。对应触发与检查定义见 GitHub 工作流。
发布后的两个镜像均需要。Compose 默认固定使用 0.13.0;可通过同一个 BOT_VERSION 同时选择前后端版本,避免独立跟随 latest。使用仓库内的 Compose 配置运行:
BOT_VERSION=0.13.0 ADMIN_PASSWORD='请替换为强密码' docker compose pull
BOT_VERSION=0.13.0 ADMIN_PASSWORD='请替换为强密码' docker compose up -d不设置 ADMIN_PASSWORD 时容器以无认证模式运行。后端镜像本身只提供 API,单独运行后端容器不会提供网页。镜像默认在容器内监听 0.0.0.0,端口沿用数据库配置(新数据库为 8080),不修改数据库中保存的监听配置;直接使用 docker run 时可通过 -e ADMIN_PASSWORD=... 启用登录,发布默认端口时请指定 -p 127.0.0.1:8080:8080,避免将未加密的 HTTP 服务暴露到所有宿主机接口。若覆盖镜像默认命令,需自行指定 --host 0.0.0.0 才能通过容器网络访问后端。前端通过同源 /api、/ws 代理连接后端,内置 Nginx 对 POST /api/auth/login 提供独立的源 IP 速率限制并传递 X-Real-IP;若后端仅能通过受控反向代理访问,可通过 TRUSTED_PROXIES(或 --trusted-proxies,逗号分隔 IP/CIDR,默认不信任任何转发头)允许后端按真实客户端 IP 隔离登录频控。生产反向代理必须支持 WebSocket Upgrade、透传包含端口的原始 Host 请求头并显式覆盖转发协议头(例如外层 TLS Nginx 必须配置 proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme;,切勿使用 $proxy_add_x_forwarded_proto 追加,以通过后端 WebSocket 同源 Origin 校验),并将所有前端路由回退到 index.html。
- 先暂停策略并核实机器人挂单已撤销、成交已完成对账,再停止所有使用该数据库的进程。确认退出后备份整个
data目录;若仍有 SQLite WAL/SHM 文件,须一并保留并保护文件权限。控制台的脱敏分析导出不包含凭证,不能替代完整恢复备份。 - 首次启动新版前设置
ADMIN_PASSWORD,检查数据库及附属文件的所有权和私有权限。旧数据库中的管理员密码不再用于新版登录。 - 前后端使用同一个固定镜像版本拉取和启动;可通过二进制
binance-grid-bot --version和控制台侧栏核对版本。不要在镜像尚未发布完成时仅更新其中一个服务。 - 登录后核对所有交易对的运行模式、暂停状态、持仓和挂单。旧配置包含测试网时,全部策略转为模拟盘并暂停;恢复实盘前须重新配置密钥并核实主网实际订单与持仓。模拟盘同一计价资产现在共用一份 10000 初始资金,已有持仓与累计盈亏保留,历史权益曲线按旧、新账户口径分别展示。
- 回滚前再次暂停并完成对账;存在订单身份冲突、未确认成交或未完成对账时不要回滚。停机后恢复与旧版本匹配的完整数据库备份,不要仅换旧镜像继续读取迁移后的数据库。备份之后发生的真实成交不会因还原数据库而撤销,恢复后仍须按交易所实际结果核实。
- Rust 1.89+(使用
cargo) - Node.js 22.22.2+(22 LTS)、24.15.0+ 或 26+ 和 npm;CI 与前端 Docker 构建固定使用 Node.js 22.23.4。测试使用 JSDOM 31 的选择器与样式实现,Node.js 23/25 不受测试工具支持。
在仓库根目录执行:
ADMIN_PASSWORD='本地开发密码' bash dev.shADMIN_PASSWORD 可省略;省略时本次启动不启用管理员认证。脚本会在缺少前端依赖时运行 npm ci,然后同时启动后端和前端。前端默认仅监听回环地址(127.0.0.1,可通过 DEV_HOST=0.0.0.0 显式覆盖,覆盖前请务必设置 ADMIN_PASSWORD);本机可打开 http://127.0.0.1:5173。设置密码时使用该密码登录,未设置时直接进入控制台。按 Ctrl+C 可停止两个服务。后端默认使用 data/bot.db,已有数据库中的配置和运行状态会继续生效,开发时请使用模拟盘。可通过 bash dev.sh --db data/dev.db 指定独立数据库;其他后端参数也可直接追加。指定 --port 时,脚本会将前端代理指向该端口;如设置了 API_PROXY_TARGET,则使用该变量指定的地址。程序后台会定期请求公开接口 https://api.coinbase.com/v2/exchange-rates 获取 USDC/USDT 的人民币展示参考汇率(不携带任何账户凭证或余额信息,网络受限时仅影响人民币估值展示)。
浏览器通过前端地址请求 /api 和 /ws,由 Vite 在运行脚本的机器上转发到后端;默认的 127.0.0.1:8080 是服务器内部代理目标。若页面一直停在“正在准备工作台”,请确认访问的是 Vite 输出的网络地址,并在同一设备打开该地址下的 /api/auth/status 检查接口连接。
在两个终端分别执行:
# 后端:密码来自环境变量(也可使用 --admin-password 参数)
ADMIN_PASSWORD='本地开发密码' cargo run --release# 前端:开发服务器将 /api 和 WebSocket 代理到 127.0.0.1:8080
cd frontend
npm ci
npm run dev打开 Vite 输出的地址(默认 http://127.0.0.1:5173),使用启动时配置的管理员密码登录。若后端监听其他地址,在启动前端时设置 API_PROXY_TARGET,例如 API_PROXY_TARGET=http://127.0.0.1:18080 npm run dev。生产构建使用 npm run build,生成的 frontend/dist 由前端容器的 Nginx 提供。
在「策略参数」页面调整参数并保存后,策略引擎实时热更新。
backtest 子命令离线回放一组网格参数,不读写数据库,也不需要 API Key(下载行情和交易所规则只用公开接口)。格点、数量计算和网格配置校验复用引擎代码;撮合、挂单维护和余量调整使用确定性的回放模型。回放在撮合前检查已成交持仓上限,保留窗口内余量单的预留数量,并在平仓成交前记录风险敞口。实盘的撤单确认、网络延迟和排队过程不在模型中。
# 下载最近 7 天的 1 分钟 K 线并读取交易所规则
cargo run --release -- backtest --symbol BTCUSDC --days 7 --grid-interval 50 --amount 200 \
--max-position 2000 --cancel-opening-on-max-position --capital 2000
# 使用本地 CSV(time_ms,price 或 time_ms,open,high,low,close[,...];币安 K 线导出可直接使用)
cargo run --release -- backtest --csv prices.csv --grid-interval 0.5 --tick-size 0.01 --step-size 0.01 --json间距(--grid-interval)、每格金额(--amount)、买入窗口(--buy-window)和卖出窗口(--sell-window)可写成逗号分隔的多个值,按组合逐一回放(行情只下载一次,最多 200 组,任一组合无效则整体报错),结果按净收益从高到低列表,例如 --grid-interval 25,50,100 --amount 100,200。加 --json 输出完整报告。排序只按净收益,不含风险调整;请同时查看最大回撤和持仓峰值,并留意样本区间是否足够长,单一行情区间上的最优参数不代表通用。
输出已实现盈亏、手续费、资金费、未实现盈亏、净收益、最大回撤和持仓名义价值。--maker-fee 默认 0.0002,--funding-rate 为每 8 小时占持仓名义价值的比例(正数表示多头支付)。--json 的标准输出只包含报告;下单数量不合规等诊断信息写入标准错误。最大持仓必须为正数,价格上下限必须为正数且下限小于上限,与策略配置使用相同校验。
回放里有一个仅回放、实盘引擎不具备的实验开关,用于评估策略改动是否值得接入引擎:
--exit-floor <N>:有持仓时,平仓单只挂在高于均价 N 个间距之上(做空为低于),即不在亏损价位平仓;0表示不低于均价。副作用是价格长期不回到均价之上时不会挂出任何平仓单,浮亏会一直保留。
回放结果偏乐观,仅用于比较参数,不能当作收益预测:
- 挂单价被行情触及即全部成交,不计排队位置和部分成交;间距越小偏差越大。
- K 线内的价格路径按“涨:开→低→高→收,跌:开→高→低→收”假设,真实顺序无法从 OHLC 得知;用更细的周期或逐笔数据可缩小误差。
- 不模拟杠杆、保证金、强平和账户级风控,因此强平距离阈值与可用保证金比例下限不在回放中生效。
- 手续费和资金费为固定费率,不含滑点。
- 在 Telegram 使用 @BotFather 创建 Bot,复制 Bot Token。
- 给 Bot 发送一条消息;打开
https://api.telegram.org/bot<Bot Token>/getUpdates,从返回内容中的message.chat.id获取 Chat ID。群组通知需先将 Bot 加入群组并获取该群组的 Chat ID。 - 在网页「全局配置」页面填写 Bot Token 和 Chat ID,点击「发送测试消息」确认能收到(可在保存前使用表单中的值,留空的字段使用已保存的值,不会保存设置),再勾选「启用 Telegram 通知」,点击「保存全局设置」。Bot Token 不会在网页回显;留空可保留已保存的 Token。
- 如使用 ntfy,可在「ntfy 通知」卡片填写服务根地址(留空默认
https://ntfy.sh,自建服务填写http://或https://根地址,不含 Topic 路径)、Topic(1-64 位字母、数字、下划线或连字符,建议使用随机私有名称)及可选的 Bearer 访问令牌,点击「发送 ntfy 测试消息」验证后开启「ntfy 通知开关」并保存。访问令牌不会在网页回显;留空可保留已保存的令牌。
所有交易对共享全局通知设置,Telegram 与 ntfy 可单独或同时启用,配置存入 SQLite;关闭对应开关即可暂停该渠道通知。页面支持分别清除已保存的 Telegram 或 ntfy 凭证(清除前需先关闭对应通知)。
开仓通知在确认成交后发送。实盘平仓通知(做多卖出、做空买入)等待币安成交明细完整、实际已实现盈亏和手续费核实入库后发送,零盈亏也会显示具体金额;明细暂不可用或核实受限时,平仓通知随后台同步延迟,重复核实不会重复发送。模拟盘平仓盈亏在本地确认后直接通知。
延迟通知的当天及小时计数按原成交时间计算,账户权益、可用余额和持仓金额取准备通知时的最新数据。同步结果提交前已关闭对应通知渠道或清空对应成交历史的,不再向已关闭渠道发送该笔延迟通知。升级前已发送的“待同步”消息不会自动修改。
全局配置中可设置「全局最大持仓金额」,留空时关闭。系统将已配置策略的持仓绝对名义金额相加,多空不抵消;不同运行模式和计价资产按数值直接相加,不进行汇率换算。达到或超过上限时暂停全部策略并发起机器人挂单撤销,保留持仓;撤单结果需检查交易所挂单和策略日志。
开启「可用保证金为零时暂停所有策略」后,任一已配置策略所属账户的可用保证金为零或负数时,同样暂停全部策略并发起机器人挂单撤销,保留持仓;撤单结果需检查交易所挂单和策略日志。模拟盘按计价资产汇总所有交易对的盈亏及持仓保证金后判断;实盘根据各策略对应计价资产的账户数据判断。数据暂不可用时不会将默认零值当作真实余额,已初始化策略的数据失效会阻止新增订单并暂停所有策略。
ADMIN_PASSWORD='本地开发密码' cargo run --release -- --db data/my_bot.db
# 监听参数仅作用于当前进程
ADMIN_PASSWORD='本地开发密码' cargo run --release -- --host 127.0.0.1 --port 8080每个交易对有独立的网格引擎、行情订阅、挂单、持仓、累计统计、日志和启停状态。所有交易对共享一个 Web 控制台、可选的管理员登录和 SQLite 数据库;某个交易对初始化失败、行情中断或达到持仓上限时,只暂停该交易对。
- 在「策略总览」点击「新增交易对」,搜索并选择合约代码,填写网格间距、每格金额和买卖窗口。表单默认买卖窗口各 3,最大持仓名义价值为 1000,达到上限时暂停策略。
- 点击「保存并添加」。系统先查询币安合约交易规则:合约必须存在、处于交易状态,价格和数量步长有效,网格间距必须是价格步长的正整数倍。查询、校验或安全标记保存失败时不会保存或添加交易对,可修复问题后重试。成功后该交易对立即出现在侧栏的交易对列表中,策略保持暂停;检查参数后点击「恢复」。每个新增交易对使用独立的默认网格参数,并自动共享全局连接与通知设置。
- 在侧栏或命令面板中切换交易对,再保存各自的参数。网格参数按交易对独立保存;API 凭证、请求有效窗口、同步间隔以及 Telegram / ntfy 通知在独立的「全局配置」页面统一配置,点击「保存全局设置」后应用于所有交易对。运行模式由全局 API Key 决定,不能按交易对单独设置。重启不会被配置文件或环境变量覆盖。
- 移除交易对时,先暂停策略、等待挂单撤销完成并平掉该交易对持仓,再在策略参数页底部点击「删除策略」(实盘需输入交易对名称确认)。系统停止策略并再次核实撤单后,实盘向交易所查询持仓,模拟盘检查本地持仓;存在持仓、查询失败或无法确认持仓时拒绝移除。成交历史、统计及恢复元数据保留;至少需要保留一个交易对。需要更换合约时,添加新的交易对后再移除旧的交易对。
- 同一账户内的交易对共用账户保证金,页面的账户权益不能按交易对相加;持仓上限按每个交易对分别计算。模拟盘同一计价资产只提供一份 10000 初始资金,新增交易对不增加本金;钱包余额为这份本金加全部交易对的累计已实现盈亏,保证金余额再加全部持仓未实现盈亏,可用余额扣除全部持仓保证金。升级时复用已有持久化子账本,保留成交和持仓,仅去掉重复本金;重启、清理成交历史或删除已空仓的交易对不会重置其累计盈亏。
- 内部账户及持仓缓存由同一运行时的交易对共享,按交易所地址、API Key、API Secret 和请求有效窗口隔离;模拟盘不使用这条实盘同步路径。周期对账复用接收后不足 1 秒的快照,普通读取等待同一在途请求最多 100 毫秒,请求失败共享 2 秒冷却且不回用旧快照。关键对账独立查询单交易对持仓并强制刷新账户,不等待普通缓存的加载锁;并发成交使缓存代际失效时,关键读取仍会重新查询以取得新鲜数据。
- 部分成交会将敞口从挂单转移至持仓,也可能改变账户可用保证金。对账在减少相关挂单预留前须成功刷新账户和持仓;同次挂单对账确认的多笔终态成交合并为一次风险刷新,再依次持久化。整个批次保留风险屏障和订单预留,刷新或提交失败时保留可恢复状态并阻止本次对账完成;恢复已记账的全成交订单时也会在移除预留前刷新持仓。交易所的挂单、账户和持仓由独立请求获取,查询之间仍可能发生新的成交,因此这些数据不是同一时刻的原子快照;风控检查、下单和撤单也不能与交易所撮合原子执行,限额不保证实际敞口绝不会短暂超出。
- 交易所挂单被改价后,周期对账会将有效价格和剩余数量同步到机器人订单及数据库,并按新价格计算后续开仓预留;改价的发现依赖对账,不保证实时。部分成交需要先刷新账户和持仓再减少预留,刷新或持久化失败会阻止本次对账完成和新增实盘订单。交易所返回非正价格或无法解析的价格时,本次对账通常受阻;已成交终态且平均成交价为正的快照是例外。系统尽力保留订单及保守预留,无有效历史价格的新订单无法可靠估值,不能把预留视为准确敞口。后续须待价格、身份和成交状态可核实且必要的刷新与持久化成功后才能恢复;其他未解决的身份或终态问题仍可能阻断,需检查交易所订单和日志。
- 恢复时,部分成交或终态响应中缺失、非正的价格可以在满足订单身份、成交数量、状态及时间一致性检查后分步补正;同一正成交量下已知正均价发生变化或丢失、已知时间倒退等矛盾仍会阻断。终态有成交时,记账使用该次交易所响应的正均价,均价无效则使用该响应的有效订单价;两者均无效时继续核实。本地已知限价只用于保守预留,不能代替成交价记账。
- 启用全局持仓上限、零可用保证金保护或可用保证金比例下限(
min_available_margin_pct)时,挂单快照出现部分成交、异常价格或本地活动订单缺失,会先标记对账待处理,阻止新的发送,并等待已经取得交易所发送许可的请求返回,再进入相关同步;旧配对意图和余量目标的恢复及终态处理也受保护。三项全局保护均关闭时,这一跨策略发送门闩不生效。已发出的请求无法撤回。同步失败或被取消时全局保护继续阻止发送,须待后续对账和全局风控检查恢复就绪;如已触发暂停,还需手动恢复。 - 下单 POST 等待响应时若任务被取消,结果无法确认:提交保护器立即撤销该交易对的风控就绪状态;启用全局保护时也立即阻止其他策略继续提交。普通订单的持久化意图或余量计划会保留,需按订单 ID 核实交易所结果;重启会恢复托管订单并对账。数据库意图未必会在当前进程的下一轮对账中自动载入,不能假定取消后立刻恢复。
- 恢复订单时若交易所观察身份与已保存的订单来源冲突,系统保留双方并阻断;可写入数据库时冲突记录可用于重启后恢复,中途失败或重启后仍保持阻断。整组身份分别核实且完整对账成功后,才清理记录并解除阻断。冲突记录按交易所端点和 API Key 隔离,更换 API Key 后系统无法自动识别是否为同一账户;存在未解决冲突时,请先核实处理后再更换密钥。若数据库完全不可写且进程在恢复前崩溃,仅保存在内存中的观察身份可能丢失,需核对交易所订单和日志。
- 未解决的订单身份冲突可能保存
UNVERIFIED订单用途标记,旧版本无法反序列化该标记;旧版本也可能不具备新证据与阻断逻辑。降级前应在当前版本核实交易所订单并完成对账,确认相关冲突及屏障已解除、记录已清理;不要在冲突未解决时直接回滚。 - 身份恢复会保存完整订单响应及查询批次;同次开放订单快照内的记录没有先后顺序。成交数量或时间倒退、互相矛盾的终态会保留证据并持续阻断;正常进展也需一致复查。
terminal_order_disagreements没有自动清除入口。先核实交易所订单及逐笔成交。只有确认零成交且无需补账时,才可停止服务、备份 SQLite 数据库,按account_key、expected_symbol和client_order_id导出并核实terminal_order_disagreements的全部相关证据(first_json、conflicting_json),同时核对initial_order_responses的完整响应和批次以及身份观察,然后精确移除该范围内的终态矛盾屏障记录,重新启动后让正常对账再次核验。不要修改成交记录、托管订单、意图、初始响应或身份观察记录;保留的证据可能使屏障再次出现。只要存在任何成交或无法确认,就保持阻断,不能通过移除屏障继续运行。 - 身份恢复证据写入时,若新开放订单快照与同账户、预期交易对最近保存的快照逐条顺序和内容完全相同,则不重复保存响应;顺序或内容变化会保留新批次。同一身份的单查与该身份最新证据相比,满足单查批次及完整响应相同等条件时也会折叠,其他身份的交错单查不影响判断;最新证据为快照或响应有变化时仍保留。去重不表示每次查询都留下独立响应,也不能恢复旧版本已丢失的观察;快照内记录顺序不代表事件先后。
- 全账户持仓快照缺少目标交易对时,另查单交易对持仓,有效的单向持仓观察与双向持仓模式错误会在有效期内(
MAX_AGE)写入当前快照缓存;若仍无记录或查询失败,本次对账失败,不将缺失记录视为空仓。 - API Key、API Secret、Telegram Bot Token 和 ntfy 访问令牌不会明文回显。留空密钥输入框保留已有值;勾选「清除已保存的 API Key 和 Secret」会将所有交易对切换为模拟盘并保持暂停,需手动恢复。
- 旧版本的交易对连接与通知配置会在启动时自动迁移,以列表中的第一个交易对为全局配置基准;若原先各交易对使用不同设置,升级后请在「全局配置」中核对。
- Ctrl+C / SIGTERM 会关闭全部交易对的新增订单准入,并并发清理可用引擎的机器人挂单、保存独立暂停状态,保留持仓;已跨过最后检查的请求仍可能发送,撤单结果须核实。
启用管理员密码时,所有接口与 WebSocket 仍需认证;未设置密码时无需 Token,任何能访问该端口的人都可以调用:
| 接口 | 作用 |
|---|---|
GET /api/pairs |
列出全部交易对、运行状态、模式和网格摘要 |
GET /api/exchange/symbols?environment=mainnet |
获取币安正在交易的合约代码,按字母排序;无效环境返回 400,上游查询失败返回错误 |
GET /api/exchange/symbol-preview?environment=mainnet&symbol=<SYMBOL> |
获取指定交易对的最新价格(last_price)、当前标记价(mark_price)、价格步长(tick_size)、数量步长(step_size)、最小下单量(min_qty)和最小名义金额(min_notional),用于新增交易对时的实时预览与校验 |
GET /api/overview |
返回全部交易对的轻量摘要、今日盈亏、生成时间和全局最近 20 笔成交;不包含各交易对完整挂单、日志和小时明细 |
GET /api/accounts |
返回 generated_at 和各交易对的轻量账户观察,供首次读取与账户推送断流时补取 |
GET /api/overview/history |
返回 snapshots(最近 7 天的账户整点快照)、current_accounts(当前账户分组)和 daily_snapshots(最近 30 天的每日运行数据快照) |
POST /api/pairs |
保存并添加交易对,初始暂停 |
DELETE /api/pairs/{symbol} |
移除已暂停且挂单已清理的交易对,请求体需含 confirm: true |
GET / POST /api/global/config |
查看和修改所有交易对共享的交易所连接、Telegram 与 ntfy 通知设置 |
POST /api/global/test-exchange |
用请求中的(或已保存的)API Key / Secret 读取合约账户以验证凭据,不保存设置;使用独立的请求额度,3 秒内只接受一次 |
POST /api/global/test-telegram |
用请求中的(或已保存的)Bot Token / Chat ID 发送一条测试消息,不保存设置;3 秒内只接受一次 |
POST /api/global/test-ntfy |
用请求中的(或已保存的)ntfy 服务地址、Topic 和可选访问令牌发送一条测试消息,不保存设置;3 秒内只接受一次 |
GET / POST /api/server/config |
查看当前与保存的监听设置,保存后重启生效 |
GET /api/pairs/{symbol}/status |
指定交易对的完整快照 |
GET /api/pairs/{symbol}/orders、/trades、/logs |
指定交易对的订单、成交、日志 |
GET / POST /api/pairs/{symbol}/config |
查看和在线修改指定交易对的网格参数;全局字段请使用 /api/global/config |
POST /api/pairs/{symbol}/control |
对指定交易对执行 pause、resume、cancel_all、rebalance |
GET /api/pairs/{symbol}/database/export |
导出指定交易对所有运行模式的成交分析数据库 |
POST /api/pairs/{symbol}/trades/clear |
使用 {"confirm":true} 清理该交易对所有模式的成交及统计 |
GET /api/database/export |
导出脱敏的全库分析快照 |
POST /api/database/export |
使用 {"targets":["trade_history","account_hourly_snapshots"]} 导出选定数据(account_hourly_snapshots 涵盖账户小时与每日快照,即 account_hourly_snapshots 与 daily_snapshots) |
POST /api/database/clear |
指定相同 targets 和 "confirm":true 清理选定数据(含账户小时与每日快照) |
/api/pairs/{symbol}/ws |
指定交易对的快照、日志和控制通道,认证方式同 /ws |
/api/accounts/ws |
使用 auth WebSocket 子协议认证,每秒推送 accounts 帧;包含 generated_at、各交易对模式、状态、标记价、持仓数量、未实现盈亏、账户余额及人民币换算率,不包含凭证 |
账户历史接口的实盘 account_id 是本数据库生成的随机标识,不是币安账户 ID,也不包含 API 凭据。更换 API Key 后即使仍是同一币安账户,也会作为不同历史账户展示;身份未确认的旧实盘、未知模式及旧版模拟盘快照的 account_id 为 null。共享资金模型的模拟盘当前账户和新快照使用 paper-shared-v1,与旧版本的多份本金口径隔离。
原 /api/status、/api/config、/api/control 和 /ws 在多交易对模式下指向列表中的第一个交易对。全局数据库操作支持选择成交历史及统计、账户小时与每日快照(account_hourly_snapshots 与 daily_snapshots);币种操作覆盖该币种所有运行模式。成交清理保留交易去重标识及执行前沿,避免历史回放和策略恢复受到影响。导出文件用于分析,并非完整恢复备份。
总览接口的 pairs[].snapshot 现在是摘要,挂单数量改读 stats.active_buy_orders 和 stats.active_sell_orders,今日成交改读 today_trade_counts。最近成交位于顶层 recent_trades,按时间降序合并并限制为 20 笔,只包含各当前交易对当前模式的成交;完整数据继续通过状态、订单、成交及日志接口获取。直接使用总览接口的客户端须同步迁移,前后端应使用同一次构建。
同一路由实例的账户 WebSocket 客户端共享每秒一次的采集与编码,最后一个订阅者离开后停止采集,重新订阅时恢复;每个连接仍独立检查会话及交易对退休状态,并限制慢客户端的发送等待。HTTP 补取与推送均携带生成时间,控制台拒绝早于已有观察的响应。
恢复策略或重建网格时,HTTP 控制接口和 WebSocket 控制消息均须提供确认时的运行模式,例如 {"action":"resume","expected_mode":"PAPER"} 或 {"action":"rebalance","expected_mode":"PAPER"};可选值为 PAPER、LIVE。实盘恢复前应明确提示真实资金风险。若策略模式已变化,请求会被拒绝,调用方应刷新状态并重新确认;缺少模式的旧请求也会被拒绝。
WebSocket 控制消息的执行结果以 type: "control" 返回,包含 action、success、data 和 message;无效消息的 action 为 null。结果按操作完成时间返回,客户端应检查 success 和 message。
暂停或撤单正在等待控制队列容量时,其他控制请求可能被拒绝并提示稍后重试;调用方需自行重试。暂停状态可能已持久化,后续撤单动作入队仍可能失败;错误响应、超时或网络中断均不能证明操作未生效。重试前应刷新状态,并检查交易所挂单和策略日志,以核对暂停和撤单的实际结果。WebSocket 恢复和重建在提交前复核会话,但复核后与会话撤销之间仍有竞争,已提交的动作不能由撤销会话撤回;已开始准备的暂停或撤单不做该次提交前复核。连接发送消息前及定期复核会话,检查与发送之间仍有并发窗口。
修改已有交易对配置时,先通过对应的 GET /api/pairs/{symbol}/config(或旧版 GET /api/config)读取 data.config_version,再在对应 POST 请求中提供 baseline_version。缺少版本的更新会被拒绝;版本过期时返回 HTTP 409,需重新读取配置并检查修改后再提交。版本在服务重启或交易对重建后也会失效。添加交易对的 POST /api/pairs 不需要版本。升级后,直接调用配置 API 的旧客户端需增加上述版本字段。
交易对配置更新中的 min_price、max_price、max_position_usdc 和 min_liquidation_distance_pct 被省略或设为 null 时都会清空。全局配置中的 global_max_position_notional 和 min_available_margin_pct 则在省略时保留原值,显式设为 null 时清空。
下面的命令运行独立的模拟盘突发负载测试,不连接交易所,也不读取或修改现有数据库:
BENCH_PAIRS=50 BENCH_ROUNDS=6 cargo test --release --lib simulated_pair_burst -- --ignored --nocaptureBENCH_PAIRS 是合成交易对数量,BENCH_ROUNDS 是突发行情轮数(至少 2);BENCH_BUY_WINDOW 和 BENCH_SELL_WINDOW 分别控制窗口大小(1–50,默认均为 2)。BENCH_DB=memory(默认)使用内存 SQLite,BENCH_DB=disk 使用独立临时目录中的磁盘 SQLite,结束后清理数据库及附属文件。测试使用 4 个 Tokio 工作线程,每轮并发处理合成行情、模拟成交和网格维护。
输出成交数、剩余活跃订单数,以及行情处理、外层网格维护、单交易对总耗时、批次耗时和完整及账户快照耗时的样本数和分位数。行情处理可能包含成交及其触发的网格维护;完整快照耗时不含广播序列化和发送。单交易对耗时从任务开始执行计时,调度排队体现在批次总耗时中。分位数使用最近秩法,样本不足 20 或 100 时 p95 或 p99 的分辨率有限。
该测试用于比较相同参数下的代码或机器表现,不包括真实 WebSocket、交易所网络及限流、实盘下单和长时间运行,也不能直接换算安全的实盘交易对数量。磁盘结果依赖文件系统及缓存。
本地模拟交易所的同步路径测试可通过以下命令单独运行:
BENCH_PAIRS=30 BENCH_SECONDS=65 cargo test --release --lib simulated_live_reconciliation -- --ignored --nocapture该测试使用暂停状态的实盘引擎、合成行情和本地 HTTP 服务,每 3 秒错峰执行实际的挂单、账户及持仓同步,共用缓存和本地请求预算;同样支持 BENCH_DB=memory|disk。输出包括调度延迟、行情处理及同步周期耗时分位数、跳过的计划周期数、同步成功与未成功次数和模拟服务收到的请求数。未成功不等同于限流拒绝;快速失败可能降低耗时分位数,应结合成功率判断。estimated_weight 按本地权重累计,并非交易所实测权重。结束时还执行一次关键挂单查询和撤单探测,不计入周期请求数或估算权重。
该测试不会发送订单,模拟服务不主动返回 429,也不提供活跃挂单或成交;它无法覆盖真实网络延迟、其他进程共享 IP、交易所响应头、行情连接或长时间稳定性。建议至少运行 65 秒以覆盖本地 60 秒滚动权重窗口。
可在同一测试中模拟所有交易对的行情推送在启动 6 秒后同时中断 40 秒,再恢复:
BENCH_PAIRS=50 BENCH_SECONDS=65 BENCH_OUTAGE_SECS=40 BENCH_FAIL_MARK=1 cargo test --release --lib simulated_live_reconciliation -- --ignored --nocaptureBENCH_FAIL_MARK=1 让模拟标记价格 REST 接口在断流期间返回 503;设为 0 则允许 REST 兜底。ticker_sent 和 mark_sent 分别统计模拟服务收到的成交价和标记价格请求,其中 mark_bulk_sent 是全市场标记请求数,其余为单对请求;估算权重分别按 10 和 1 计。outage_fresh、outage_stale 统计断流期间同步后行情有效和过期的次数,recovery_fresh 统计恢复推送后行情有效的次数。这些次数是同步轮次,不是交易对数;模拟引擎处于暂停状态,不发送真实订单。
模拟活跃挂单及成交对账的独立场景:
BENCH_ORDERS_DB=disk BENCH_ORDERS_PAIRS=4 BENCH_ORDERS_PER_PAIR=8 BENCH_ORDERS_ROUNDS=3 BENCH_ORDERS_FILLS_PER_ROUND=1 cargo test --release --lib simulated_live_orders_and_fills -- --ignored --nocapture该场景使用暂停的实盘引擎、虚构凭据及本地模拟交易所;订单先出现在挂单列表,再通过单订单查询确认成交,测试核对成交持久化和剩余活跃订单。每对每轮成交数乘以轮数必须小于每对初始订单数。BENCH_ORDERS_DB 可选 memory(默认)或独立临时磁盘数据库 disk。输出订单对账、账户持仓、批次及独立 PnL 补偿耗时,并报告已持久化、已核实及待核实成交数。终态成交按观察批次刷新风险数据;持仓 HTTP 计数还包含全市场查询和并发失效后的必要重试。该合成突发场景不代表交易所限流响应或实盘容量。
基准按交易对、轮次和订单或账户持仓阶段输出警告及失败日志,并按客户端预留时的警告统计本地权重、订单速率和冷却拒绝;这些拒绝数不等于失败阶段数,也不是交易所响应数。成功与失败耗时分别统计,诊断开销包含在耗时中;无法从日志解释的失败标记为原因未知。挂单对账须全部成功;普通账户同步受预算、共享等待及故障冷却影响的失败会单独计数。判断结果还须核对账户同步成功率和待核实积压。
订单场景可通过 BENCH_ORDERS_DELAY_OPEN_MS、BENCH_ORDERS_DELAY_LOOKUP_MS、BENCH_ORDERS_DELAY_TRADE_MS、BENCH_ORDERS_DELAY_POSITION_MS 和 BENCH_ORDERS_DELAY_ACCOUNT_MS 分别配置模拟服务端延迟,默认均为 0;这是服务端延迟,不是网络 RTT。输出还包含 blocking 线程排队和已埋点数据库连接互斥锁的等待分布;不包括 SQL、SQLite 文件锁或外层成交锁等待,采样本身也会增加开销。
真实引擎循环在行情请求期间处理控制消息的本地场景:
BENCH_LOOP_ROUNDS=10 BENCH_LOOP_DELAY_MS=100 cargo test --release --lib control_during_market_request -- --ignored --nocapture该场景在独立内存数据库和暂停的模拟盘引擎中运行,通过回环服务保证控制命令在标记价格请求期间入队,并要求配置确认在本地 HTTP 响应仍被持有时完成。输出控制消息入队到确认、标记价格推送到引擎观察,以及模拟服务处理耗时;服务耗时包含释放握手,不是网络 RTT。配置更新使旧作用域请求退役,随后观察新作用域的兜底完成;配置确认不代表撤单完成,场景不测量行情丢失。BENCH_LOOP_TIMEOUT_MS 默认 10000;模拟延迟必须小于客户端的 10000 毫秒请求超时,接近超时时限仍可能因调度或连接耗时失败。
一轮本机测试的数据及适用范围见 多交易对容量测试记录。
运行时可以通过 RUST_LOG 启用性能诊断日志,例如
RUST_LOG=binance_grid_bot=info,binance_grid_bot::exchange::client=debug,binance_grid_bot::strategy::grid=debug,binance_grid_bot::db=debug。
日志包括交易所请求到响应头的耗时、周期同步各阶段的累计耗时、SQLite 阻塞线程排队时间,以及部分关键写操作的连接锁等待时间。调试日志在多交易对场景下可能较多;限流拒绝仍记录为警告。请求耗时不包含响应体解析,数据库锁指标也不覆盖所有操作。
机器人的所有状态与数据自动保存在 SQLite 数据库中(默认路径 data/bot.db)。文件数据库使用 WAL 和 synchronous=FULL,以提高已提交订单意图在断电时的持久性;启动时会检查配置是否生效。这可能增加磁盘写入延迟,持久性仍取决于文件系统和存储设备:
app_config表:存储当前生效的交易所参数、网格间距、下单金额、滑动窗口、风控范围与 API 凭证。trades表:记录每笔已确认成交的价格、数量、运行模式、币安实际已实现盈亏、报价资产手续费及核实状态。尚无法核实的记录显示“待同步”,不计入已实现盈亏汇总。升级前的成交及已移除测试网的成交标为UNKNOWN,不会自动归入模拟盘或实盘。scoped_grid_stats表:按交易对及运行模式分别累计成交量、成交笔数、已完成网格循环次数及配对价差估算。当前模式的已实现盈亏与手续费从同一范围的trades记录汇总;原grid_stats表保留旧版历史数据。trade_hourly_rollups表:按交易对、运行模式和小时保存成交方向计数、精确盈亏及待核实数量;trades.stats_hour提供边界明细索引。首次升级在结构事务内回填旧历史,完成标记保证重启不重复扫描;保留历史较多时首次启动会更久。managed_orders表:保存机器人挂单及配对元数据,供重启对账使用。pair_intents表:保留旧版恢复元数据;升级后先查询交易所核实可能已接受的订单,确认不存在时结束旧意图,不生成新配对单。bot_runtime表:单交易对配置继续同步运行或暂停状态,兼容旧版本。pair_runtime表:按交易对及运行模式独立保存启停状态,单交易对与多交易对配置均优先读取该表,缺失时兼容旧状态。在线跨模式切换时,新配置和目标暂停状态在同一事务中保存;切换后须手动恢复。paper_accounts表:按交易对保存模拟盈亏子账本及持仓,用于恢复同一计价资产的共享账户;子账本中的 10000 为累计盈亏的计算基线,不代表新增资金。模拟成交与子账本状态在同一事务中提交,重启时恢复。清理成交历史或移除已空仓的交易对不会重置共享余额。pair_execution_guard表:按交易对及模式记录未完成正常停机的引擎,防止状态保存失败或异常退出后按过期运行状态自动交易。
成交统计缓存的版本在数据库写入成功后、释放数据库连接前更新,避免快照读取在磁盘提交期间等待版本锁;写入期间快照仍可能异步等待成交提交或数据库查询。
成交写入、PnL 补核实和历史清理在同一事务中维护小时汇总,任一步失败时一起回滚;重复成交不重复累计。通知使用该次成交提交对应的当天及小时序号,页面统计读取小时汇总并对边界明细复核。待核实成交查询使用仅包含未核实记录的部分索引。
已实现盈亏统计仅覆盖本程序保存的已确认订单,扣费后金额扣除同一报价资产的成交手续费;资金费和手工交易不计入。
币安成交明细用于核实订单的实际已实现盈亏和手续费。每页请求最多 1000 条,每次核实最多请求 3 页,每页本地计入权重 5;盈亏核实共享每 60 秒最多 60 权重的本地预算,实际额度也可能受更低的正常请求预算约束。请求超时为 10 秒。每个客户端最多缓存 8 个订单的分页进度,每个订单最多保留 100 万条不同成交;超过上限会清除进度并报错。缓存满时新订单进入最多 1024 项的等待队列,活跃等待者按队列顺序争取空位或淘汰符合条件的闲置进度;尚未取得空位的调用需稍后重试。等待者三分钟未轮询后视为不活跃,可被活跃等待者跳过;未被移除的等待项再次轮询时仍保留原位置,队列满时会移除不活跃项。等待和进度保留期限会随观察到的待核实积压增长。连续实际查询失败且未推进,或长期未推进的闲置进度可能被淘汰,淘汰后需从头获取;本地预算限流或取消等未实际完成查询的情况不计入连续失败,但长期闲置仍可能被回收。此机制让等待订单有机会进入,同时尽量保留持续推进的进度,但不保证等待时间或完成核实。清理成交历史会使相应旧分页状态失效;分页进度保存在内存中,重启后丢失。
恢复历史订单 ID 的查询按权重 1 与成交明细分页共用上述盈亏核实预算,也受普通请求预算限制;该共享额度不超过普通权重预算的四分之一。订单确认、撤单等关键恢复调用继续使用关键请求等级。
终态成交先持久化为“待同步”,随后由独立补偿任务核实实际盈亏和手续费,明细请求不占用成交提交锁或跨策略新增订单屏障。后台每秒及周期同步完成后检查补偿进度,每批最多 32 笔、并发最多 4 笔;上一批未结束时跳过,查询、核实或提交失败以及本地额度耗尽后约 60 秒再试,实际请求仍受共享预算限制。程序以成交 ID 去重,累计数量与订单已成交数量完全一致才视为核实完成;未完成或请求失败时记录保持“待同步”。首次请求未完成时从 fromId=0 继续,随后使用每页最大成交 ID 加一作为游标;短页仍不足预期数量时清除进度并报错。
盈亏验证等待提交锁期间可取消;取得锁后,即使调用方退出,数据库提交与缓存发布仍会完成。已退休实例不再接纳新的验证;删除交易对的成功和失败恢复路径都先排空旧实例已受理的提交,再移除或重建实例。
这些分页行为依赖尚未核实的交易所语义:币安合约账户成交列表文档列出了 orderId、fromId 和分页参数,但没有明确保证二者组合、fromId=0、游标包含性、返回顺序及短页是否必然表示结束。仓库中的模拟接口测试不能证明真实币安行为。接口文档还说明未同时指定起止时间时默认查询最近 7 天、最长可查询最近 3 个月,且 fromId 不能与起止时间组合;当前实现不提供更早历史的回退查询。上述限制或假设不成立时,成交可能长期待同步、反复重试或遗漏,数量一致也不构成交易所分页完整性的保证。
任何 SQLite 客户端(如 sqlite3, DBeaver, TablePlus)均可直接打开 data/bot.db 查阅和导出交易数据。
新版不会仅凭旧成交记录猜测模拟账户余额或持仓。若某交易对没有 paper_accounts 记录,但存在 PAPER 或 UNKNOWN 成交或保留的成交恢复元数据,模拟策略会保持暂停,直到明确初始化账户并重启。UNKNOWN 不足以证明历史交易属于模拟盘;请先核对原账户和历史记录。
此操作将该交易对的子账本初始化为空仓、累计盈亏为零,不恢复旧模拟持仓和余额,也不向共享账户额外注入本金。 每个计价资产仍只有一份 10000 初始资金。历史成交、统计和恢复元数据保留,因此历史数据与新账户基线可能不连续。仅在接受此结果后操作;在线分析导出已经脱敏,不能作为完整恢复备份。
-
停止所有使用该数据库的机器人,包括不遵守新版进程锁的旧版本;确认进程已退出。备份完整数据库及必要的 SQLite WAL/SHM 文件,保护备份中的凭证。迁移会打开数据库并可能更新数据库结构,即使随后资格检查失败也不能假设文件完全未变化。
-
在 Unix 上,对每个需要迁移的交易对单独运行以下命令,将路径和交易对替换为实际值:
cargo run --release -- migrate-legacy-paper --db data/bot.db --symbol SOLUSDC --confirm INITIALIZE-EMPTY-PAPER-ACCOUNT
已构建二进制可直接使用相同的子命令和参数。数据库必须是已存在的普通文件,不支持符号链接、多个硬链接或 SQLite
file:URI;交易对须为 3–32 位大写 ASCII 字母或数字。命令不会验证该交易对是否已配置或存在于币安。它使用数据库旁的进程锁,无法替代停止旧版程序。仅有实盘历史、没有符合条件的模拟或未知历史时会拒绝;已有模拟账户记录时也会拒绝,成功后不可重复执行。 -
启动机器人,核对该交易对的模拟余额、空仓状态和配置;策略仍保持暂停,确认新基线符合预期后手动恢复。账户初始化和暂停在同一事务中提交,失败时这两项一起回滚。
登录控制台后,在交易对详情的「成交历史」下载当前币种全部运行模式的成交分析快照,不受页面最近 50 条成交的限制。在「全局设置 → 数据库操作」可导出全库快照,或选择成交历史及统计、账户小时与每日快照导出。
导出使用 SQLite 一致性快照,包含已提交的 WAL 数据,无需暂停策略或手工复制 .db-wal。副本中的 Binance API Key / Secret、Telegram Bot Token / Chat ID、ntfy 服务地址 / Topic / 访问令牌和登录会话均被移除;管理员密码本就不在数据库中。原数据库保持不变。文件用于离线分析,不是包含凭证的恢复备份;系统运行日志仅保存在内存中,不包含在数据库导出里。
同一数据库同时只允许一个分析导出;超过限制的并发请求返回 500 和稍后重试提示,具体原因记录在服务日志中。限制覆盖全库、选择数据及单交易对导出,复制和脱敏完成后释放。
当前币种接口为 GET /api/pairs/{symbol}/database/export,全库接口为 GET /api/database/export,选择数据使用 POST /api/database/export;启用密码认证时需有效的管理员 Authorization: Bearer <token>。
在交易对详情的「成交历史」清理当前币种全部运行模式的历史成交(包括旧版 UNKNOWN 记录)及对应统计;在全局设置可选择清理所有币种的成交历史及统计、账户小时与每日快照。页面数据同步更新,清理无法撤销,建议先导出。
清理保留当前持仓、账户余额、挂单、配置和登录信息,策略可继续运行。数据库保留已处理成交 ID、各交易对及模式的最近成交边界,以及已清理订单的方向、价格和数量,供防重复入账、重启恢复及存续配对订单的周期计算使用;这些恢复数据不显示在成交历史中。清理不会删除币安交易所的成交记录,也不承诺立即缩小 SQLite 文件大小。
旧版 grid_stats 表没有币种标识,无法可靠归属到某个交易对,按币种清理时保留该表;选择性成交历史导出不包含此表,全库分析快照仍包含它。全局清理成交历史会删除该表的数据。
在数据库设置中同时清理成交历史和账户小时与每日快照时,两类数据在同一个事务中删除;任一删除失败时均回滚。
当前币种接口为 POST /api/pairs/{symbol}/trades/clear,请求体为 {"confirm":true};全局操作使用 POST /api/database/clear 并指定 targets 和 confirm。启用密码认证时接口须携带有效的管理员 Authorization: Bearer <token>;未确认返回 400,需要认证但未登录返回 401,事务失败时保留原数据。
Compose 默认仅在宿主机回环地址发布前端的明文 HTTP 端口。直接通过公网 HTTP 访问时,管理员密码和会话令牌可能被链路上的第三方截获;未设置管理员密码时任何人都能直接操作,模拟盘同样需要保护访问入口。不要将 8080 端口直接开放到公网。
默认的 docker-compose.yml 中 frontend 的 ports 配置如下。升级已有部署时,更新配置后运行 docker compose up -d,使容器使用新的端口绑定:
ports:
- "127.0.0.1:8080:80"Docker Engine 早于 28.0.0 的版本可能允许同一二层网络中的其他主机访问发布到回环地址的端口。请升级 Docker,或将不可信主机与服务器隔离并从同网段验证端口不可访问;详见 Docker 端口发布文档。
检查云安全组和宿主机防火墙,移除面向公网的 8080 入站规则。Docker 发布端口可能绕过部分宿主机防火墙规则,因此还要确认端口绑定地址,不能只依赖防火墙。
- HTTPS 反向代理:在服务器配置具有有效证书的 HTTPS 代理,将请求转发到
127.0.0.1:8080,确保支持 WebSocket 升级、透传原始Host头与端口,并显式覆盖转发协议头(如外层 TLS Nginx 必须配置proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme;,切勿使用$proxy_add_x_forwarded_proto追加客户端伪造头);安全组和防火墙只放行代理所需的 HTTPS 端口,按需限制来源。 - SSH 隧道:保持前端仅监听服务器回环地址,在本地运行
ssh -N -L 8080:127.0.0.1:8080 <用户>@<服务器>,然后在本地浏览器访问http://127.0.0.1:8080。若本地8080已被占用,可改用其他本地端口。 - 受控 VPN:也可仅向 VPN 网络提供服务,并限制允许访问的客户端;应将前端绑定到适当的 VPN 接口或通过 VPN 访问受保护的代理。
在服务器执行以下命令,分别检查容器状态、前端页面及后端认证状态接口:
docker compose ps
docker compose logs --tail=100 frontend binance-bot
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/api/auth/status确认前端端口映射符合预期,再检查 HTTPS 代理或 SSH 隧道、证书、WebSocket 转发,以及云安全组和宿主机防火墙中对应安全入口的规则。页面可访问只表示前端有响应;认证状态接口也正常后,才能确认后端接口可访问。
可通过环境变量 METRICS_TOKEN(或 --metrics-token,至少 16 位可见 ASCII 字符,建议使用环境变量)配置专用的只读指标抓取令牌,也可继续使用已登录管理员会话的 Authorization: Bearer 令牌访问 GET /api/metrics(未设置 ADMIN_PASSWORD 且未设置 METRICS_TOKEN 时无需令牌),内容为 Prometheus 文本格式,指标均为进程内累计值,重启后归零:
binance_bot_sqlite_connection_lock_wait_seconds:等待共享 SQLite 连接互斥锁的耗时直方图。binance_bot_sqlite_blocking_queue_wait_seconds:SQLite 任务从提交到阻塞线程开始执行的排队耗时直方图。binance_bot_websocket_reconnects_total{stream="market|user_data"}:行情流与用户数据流的重连次数。binance_bot_sync_failures_total{kind="open_orders|position|account"}:挂单、持仓、账户同步失败次数。binance_bot_http_requests_total{status="2xx|4xx|5xx"}:后端 API 的 HTTP 响应状态分类;前端静态资源由 Nginx 提供,不计入;101 WebSocket 升级及 1xx/3xx 响应不计入。
METRICS_TOKEN 仅对只读的 GET /api/metrics 有效,不能访问控制台状态、交易控制、配置修改或数据库导出等其他接口,也不会在每次抓取时查询 SQLite 会话表,适合配置为 Prometheus 的长期抓取凭证。管理员登录会话令牌仍会在 24 小时后或进程重启后失效。指标没有按交易对区分,也不包含价格、持仓、订单或凭证信息。
运行项目完整测试套件:
cargo test --locked
cd frontend
npm ci
npm run lint
npm test
npm run build前端回归测试覆盖账户汇总、认证和交易对切换。CI 同时运行 Rust 与前端测试;Node.js 仅用于构建前端,前端运行时使用 Nginx。