第 10 章 · 04 SQL 查询速查


文档摘要

第 10 章 · 04 SQL 查询速查 本节摘要:freqtrade 把所有交易记录、配对锁、订单、自定义数据存进 SQLite 数据库(默认 )。虽然 Telegram 和 REST API 能查大多数信息,但有时你想直接问数据库——做自定义盈亏统计、排查异常交易、修复手动卖出后状态不同步的仓位。本节讲清几件事:怎么用 sqlite3(或 Docker 里的 sqlite3、或可视化工具 SqliteBrowser)打开数据库;trades 表的核心字段;常用的盈亏统计查询(按币种、按月、按出场原因);以及危险的写操作(修复手动平仓、删除交易)——强调绝对不要在 bot 运行时写数据库,且务必先备份。 内容来源:原项目文档 ,汉化并套用体系化模板。

第 10 章 · 04 SQL 查询速查

本节摘要:freqtrade 把所有交易记录、配对锁、订单、自定义数据存进 SQLite 数据库(默认 user_data/tradesv3.sqlite)。虽然 Telegram 和 REST API 能查大多数信息,但有时你想直接问数据库——做自定义盈亏统计、排查异常交易、修复手动卖出后状态不同步的仓位。本节讲清几件事:怎么用 sqlite3(或 Docker 里的 sqlite3、或可视化工具 SqliteBrowser)打开数据库;trades 表的核心字段;常用的盈亏统计查询(按币种、按月、按出场原因);以及危险的写操作(修复手动平仓、删除交易)——强调绝对不要在 bot 运行时写数据库,且务必先备份。

内容来源:原项目文档 docs/sql_cheatsheet.md,汉化并套用体系化模板。

⚠️ 风险提示:SQL 写操作(update/insert/delete)有数据损坏风险。永远先备份数据库,且绝不在 bot 连着数据库时执行写操作——会导致不可恢复的损坏。优先用 Telegram/REST API 的命令(如 /delete)而非直接写 SQL。

学习目标

阅读完本节,你应当能够:

  1. sqlite3 或 Docker 打开 freqtrade 数据库。
  2. 查看 trades 表结构与核心字段。
  3. 写常用的盈亏统计查询(按币种/月/出场原因)。
  4. 安全执行修复与删除写操作。

一、打开数据库

freqtrade 默认用 SQLite,数据库文件一般在 user_data/tradesv3.sqlite(配置里 db_url 可改,也支持 PostgreSQL/MariaDB)。

安装 sqlite3:

  • Ubuntu/Debian:sudo apt-get install sqlite3
  • Docker 镜像里自带 sqlite3:
    docker compose exec freqtrade /bin/bash sqlite3 <database-file>.sqlite
  • 可视化:用 SqliteBrowser 等图形工具更直观。

打开与基本操作:

sqlite3 .open <filepath> .tables # 列出所有表 .schema <table_name> # 看表结构 SELECT * FROM trades; # 查所有交易

💡 切换 PostgreSQL/MariaDB 后,查询语句相同,只是客户端工具不同。

二、trades 表核心字段

trades 表是核心,记录每一笔交易。关键字段(简化):

字段 含义
id 交易 ID
pair 交易对
is_short 是否做空(0/1)
is_open 是否仍开仓(0/1)
open_date / close_date 开/平仓时间
open_rate / close_rate 开/平仓价格
amount 交易数量
stake_amount 投入本金
close_profit 平仓收益率(小数,如 0.05 = 5%)
close_profit_abs 平仓绝对盈亏(计价币)
exit_reason 出场原因(exit_signal/stop_loss/roi/...)
enter_tag 入场标签
leverage 杠杆倍数
fee_open / fee_close 开/平仓费率

其他常用表:

  • orders:每笔交易的所有订单(含部分成交)。
  • pairlocks:被锁定的交易对(protection 触发)。
  • trades / orders / trade_custom_data 之间通过 ft_trade_id 关联。

三、盈亏统计查询

按交易对统计盈亏:

SELECT pair, COUNT(*) AS trade_count, ROUND(SUM(close_profit_abs), 4) AS total_profit, ROUND(AVG(close_profit) * 100, 2) AS avg_profit_pct, ROUND(SUM(CASE WHEN close_profit > 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS winrate_pct FROM trades WHERE is_open = 0 GROUP BY pair ORDER BY total_profit DESC;

这会列出每个交易对的:交易次数、总绝对盈亏、平均收益率、胜率,按总盈亏降序——快速找出最赚钱和最亏钱的币。

按月统计:

SELECT strftime('%Y-%m', close_date) AS month, COUNT(*) AS trades, ROUND(SUM(close_profit_abs), 4) AS profit_abs, ROUND(AVG(close_profit) * 100, 2) AS avg_profit_pct FROM trades WHERE is_open = 0 GROUP BY month ORDER BY month DESC;

按出场原因统计(诊断策略问题):

SELECT exit_reason, COUNT(*) AS count, ROUND(AVG(close_profit) * 100, 2) AS avg_profit_pct, ROUND(SUM(close_profit_abs), 4) AS total_profit_abs FROM trades WHERE is_open = 0 GROUP BY exit_reason ORDER BY total_profit_abs;

如果 stop_loss 的总盈亏特别负,说明止损太宽或策略在某种行情下系统性亏损;如果 roi 占比高但单笔小,可能 ROI 太保守。

多空对比(合约策略):

SELECT is_short, COUNT(*) AS trades, ROUND(AVG(close_profit) * 100, 2) AS avg_profit_pct, ROUND(SUM(close_profit_abs), 4) AS total_profit_abs FROM trades WHERE is_open = 0 GROUP BY is_short;

平均持仓时长:

SELECT pair, ROUND(AVG((julianday(close_date) - julianday(open_date)) * 24 * 60), 1) AS avg_minutes FROM trades WHERE is_open = 0 GROUP BY pair;

四、写操作:修复与删除(危险!)

⚠️ 再次强调:永远先备份绝不在 bot 运行时写

修复「手动卖出后状态不同步」:你在交易所手动卖了,bot 不知道,仍以为仓位开着。优先用 /forceexit <tradeid>(bot 会自动处理)。只有不得已才直接改库:

UPDATE trades SET is_open = 0, close_date = '2020-06-20 03:08:45.103418', close_rate = 0.19638016, close_profit = close_rate / open_rate - 1, close_profit_abs = (amount * 0.19638016 * (1 - fee_close) - (amount * (open_rate * (1 - fee_open)))), exit_reason = 'force_exit' WHERE id = 31;

删除交易(优先用 Telegram/REST 的 /delete <tradeid>,它会连带删订单和自定义数据):

-- 注意:先开外键 PRAGMA foreign_keys = ON (Ubuntu 默认关) DELETE FROM trades WHERE id = 31; DELETE FROM orders WHERE ft_trade_id = 31; DELETE FROM trade_custom_data WHERE ft_trade_id = 31;

⚠️ 绝不在没有 WHERE 子句时跑 DELETE/UPDATE——会清空整张表。Ubuntu 的 sqlite3 默认关外键,删交易前先 PRAGMA foreign_keys = ON,否则会留下孤儿订单数据。

五、实战排查场景

场景 1:bot 说不交易了,怀疑被 protection 锁

SELECT pair, side, reason, lock_end_time FROM pairlocks WHERE lock_end_time > datetime('now');

看哪些币被锁、锁到什么时候、什么原因。

场景 2:某笔交易盈亏对不上

SELECT * FROM trades WHERE id = <tradeid>; SELECT * FROM orders WHERE ft_trade_id = <tradeid>;

对比交易记录和订单明细,检查部分成交、费率、资金费率是否都算进去了。

场景 3:统计某段时间的净盈亏

SELECT ROUND(SUM(close_profit_abs), 4) AS net_profit, COUNT(*) AS trades FROM trades WHERE is_open = 0 AND close_date BETWEEN '2024-01-01' AND '2024-03-31';

场景 4:胜率与盈亏比(配合策略调优)

SELECT COUNT(*) AS total, SUM(CASE WHEN close_profit > 0 THEN 1 ELSE 0 END) AS wins, ROUND(SUM(CASE WHEN close_profit > 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS winrate_pct, ROUND(AVG(CASE WHEN close_profit > 0 THEN close_profit END) * 100, 2) AS avg_win_pct, ROUND(AVG(CASE WHEN close_profit < 0 THEN close_profit END) * 100, 2) AS avg_loss_pct FROM trades WHERE is_open = 0 AND exit_reason != 'force_exit';

排除强制平仓(干扰统计),看真实策略的胜率和盈亏比——这两个指标决定策略是否长期正期望。

本节要点回顾

  1. 打开方式:sqlite3 命令行、Docker 内自带、或 SqliteBrowser 图形工具;.tables/.schema/SELECT 基本操作。
  2. trades 表:核心字段含 pair/is_short/is_open/open_rate/close_rate/close_profit/close_profit_abs/exit_reason/enter_tag/leverage;与 orders/trade_custom_data 通过 ft_trade_id 关联。
  3. 统计查询:按交易对/月/出场原因/多空方向聚合,算总盈亏、平均收益、胜率、持仓时长——这是 Telegram/API 给不了的自定义分析。
  4. 写操作三原则:① 永远先备份;② 绝不在 bot 运行时写;③ 优先用 /forceexit//delete 等命令而非直接 SQL。
  5. 修复手动平仓:UPDATE trades 设 is_open=0 及各 close 字段;删除交易:连删 trades/orders/trade_custom_data,Ubuntu 要先 PRAGMA foreign_keys=ON,绝不裸 DELETE/UPDATE。

下一节,也是全书最后一节,我们看策略迁移与常见问题——怎么用 strategy-updater 升级老策略、v2 到 v3 的术语变更、FAQ。


发布者: 作者: 灏天文库 转发
评论区 (0)
U