freqtrade convert-db 详解:交易数据库跨系统迁移命令与源码原理
本篇基于 docs/commands/convert-db.md 与仓库源码,完整讲解 freqtrade convert-db 命令的用途、全部参数含义与默认值、典型迁移操作方式,以及底层 migrate_db 实现 究竟迁移了哪些数据表、又如何在 PostgreSQL 上正确处理自增序列。读完之后,你可以把机器人运行了很久的 SQLite 交易库完整搬到 PostgreSQL(或从一个 PostgreSQL 实例迁到另一个),并理解迁移过程每一类数据的落库逻辑与序列重置原理。
命令概述
convert-db 是 freqtrade 提供的数据库迁移子命令。它的作用是把交易数据库从一个系统搬到另一个系统,例如 SQLite 迁往 PostgreSQL、PostgreSQL 迁往另一个 PostgreSQL 实例,迁移内容包括全部 trades、orders 以及 PairLock 等关联数据。
命令在 CLI 中的完整帮助信息如下(继承自 docs/commands/convert-db.md 原文):
usage: freqtrade convert-db [-h] [--db-url PATH] [--db-url-from PATH]
options:
-h, --help show this help message and exit
--db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///tradesv3.sqlite` for
Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for
Dry Run).
--db-url-from PATH Source db url to use when migrating a database.
该子命令在 命令注册代码 中定义,帮助文案为 "Migrate database to different system",执行入口绑定到 start_convert_db 函数。
参数详解
convert-db 只接受两个业务参数(外加 -h),对应 arguments.py 中的 ARGS_CONVERT_DB = ["db_url", "db_url_from"],参数定义位于 cli_options.py。
--db-url
目标数据库 URL,即迁移完成后机器人将要使用的数据库。它是 freqtrade 全局通用的 db_url 配置项的命令行覆盖形式。
默认值定义在 constants.py:
DEFAULT_DB_PROD_URL = "sqlite:///tradesv3.sqlite"
DEFAULT_DB_DRYRUN_URL = "sqlite:///tradesv3.dryrun.sqlite"
从 configuration.py 的赋值逻辑看,dry-run 模式下默认使用 tradesv3.dryrun.sqlite,实盘模式下默认使用 tradesv3.sqlite,这也正是帮助文本中"default: sqlite:///tradesv3.sqlite for Live Run mode, sqlite:///tradesv3.dryrun.sqlite for Dry Run"的来源。
--db-url-from
源数据库 URL,即迁移的起点库。这个参数是 convert-db 专属的,用于指明"从哪个库读数据"。在典型的 SQLite 迁 PostgreSQL 场景中,目标库(--db-url)指定 PostgreSQL 连接串,源库(--db-url-from)指向已有的 tradesv3.sqlite 文件。
源码调用链:start_convert_db 做了什么
db_commands.py 中的入口函数逻辑非常紧凑:
def start_convert_db(args: dict[str, Any]) -> None:
from freqtrade.configuration.config_setup import setup_utils_configuration
from freqtrade.persistence import Trade, init_db
from freqtrade.persistence.db_migration import migrate_db
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
init_db(config["db_url"])
session_target = Trade.session
init_db(config["db_url_from"])
logger.info("Starting db migration.")
migrate_db(session_target)
从源码结构可以读出以下要点:
- 以工具模式启动配置:
setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)说明convert-db属于纯离线工具命令——不连接交易所、不加载策略行情,只需要解析出db_url与db_url_from两项配置即可运行。 - 先后两次
init_db决定了源与目标的角色:先对config["db_url"](目标库)初始化,并立刻通过session_target = Trade.session拿到目标库的会话对象;随后再次对config["db_url_from"](源库)初始化。由于init_db会重建默认Trade.session,后一次初始化使得默认会话指向源库。 - 单行迁移调用:
migrate_db(session_target)负责把源库(当前默认会话所连的库)中的全部数据写入session_target(目标库)。
migrate_db 内部实现:哪些数据被迁移
真正的数据搬运逻辑在 db_migration.py。该函数按以下五类实体逐类迁移,且每类独立 commit 一次:
| 数据类别 | ORM 模型 | 迁移方式 |
|---|---|---|
| 交易(含其下的订单) | Trade / Order |
遍历 Trade.get_trades(),对每个 trade 及其 trade.orders 逐个 make_transient 后 add 到目标会话 |
| 交易对锁 | PairLock |
遍历 PairLock.get_all_locks() 逐条写入 |
| 键值存储 | _KeyValueStoreModel |
全表 select 后逐条写入 |
| 自定义交易数据 | _CustomData |
全表 select 后逐条写入 |
| 钱包历史 | WalletHistory |
全表 select 后逐条写入 |
其中 make_transient(obj) 是关键手法:把从源会话读取的对象"脱钩",使其可以被 add 进目标会话而不会带着旧的身份信息与目标库产生冲突。Trade 迁移时特意连同其 orders 关系一起搬运,因此 orders 表也随交易一并完成迁移。
所有数据写入完成后,函数会查询五张表各自的 max(id),并调用 set_sequence_ids:
max_trade_id = session_target.scalar(select(func.max(Trade.id)))
max_order_id = session_target.scalar(select(func.max(Order.id)))
# ... 同理查询 pairlock / kv / custom_data / wallet_history
set_sequence_ids(
session_target.get_bind(),
trade_id=(max_trade_id or 0) + 1,
order_id=(max_order_id or 0) + 1,
# ... 各表 max(id) + 1
)
这段处理只在目标库是 PostgreSQL 时生效——set_sequence_ids 内部以 engine.name == "postgresql" 为条件,对各序列执行 ALTER SEQUENCE ... RESTART WITH <max_id + 1>(涉及 trades_id_seq、orders_id_seq、pairlocks_id_seq、KeyValueStore_id_seq、trade_custom_data_id_seq、wallet_history_id_seq 六个序列)。从源码结构看,这正是跨库迁移最容易踩的坑:PostgreSQL 的自增序列不会因导入数据而自动推进,若不重置,新插入的行会与源库已有的主键冲突;而 SQLite 的自增由 rowid/sqlite_sequence 维护,则不需要此步骤。
整个迁移结束后,日志会输出形如 Migrated {n} Trades, {n} Pairlocks, {n} Key-Value pairs, {n} Custom Data entries, and {n} Wallet History entries. 的汇总信息,可据此核对迁移条数与源库是否一致。
使用示例
典型的"SQLite 迁往 PostgreSQL"操作方式是:
freqtrade convert-db \
--db-url "postgresql://user:pass@host:5432/freqtrade" \
--db-url-from "sqlite:///tradesv3.sqlite"
反向迁移(PostgreSQL 迁回 SQLite 或迁往另一个 PostgreSQL)同样适用,只需交换两个 URL 的角色。命令运行后会以 INFO 级别输出 Starting db migration. 与最终的迁移条数汇总。
注意事项与适用边界
- 目标库必须是空库:官方在 utils.md 中明确警告——请确保只在空的目标数据库上使用此命令,因为 freqtrade 执行的是常规迁移,若目标库中已存在数据可能会失败。
- 不依赖交易所凭据:从
RunMode.UTIL_NO_EXCHANGE的启动方式看,该命令属于离线工具,不需要交易所 API key,可在无网络环境下对数据库文件直接操作。 - 迁移范围:与 utils.md 的表述(trades、orders 与 PairLocks)一致,源码实际还覆盖 KeyValueStore、CustomData 与 WalletHistory 三类表,因此这是一次覆盖持久层全部业务表的完整迁移,而不仅是交易记录。
- 适用前提:两个数据库的表结构需兼容(同一版本 freqtrade 建表)。数据库版本升级场景的表结构变更走的是启动时自动 schema 迁移机制,而非本命令;跨系统迁移时建议保持迁移前后 freqtrade 版本一致。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00