第 9 章 · 01 交易所适配与 ccxt 本节摘要:freqtrade 支持几十个交易所,底层靠 ccxt 这个统一封装库抹平各交易所 API 的差异,上层再用 类和每个交易所的独立子类( 、 、 等)做针对交易机器人的二次封装。本节讲清这套适配层的工作原理:ccxt 是什么、Exchange 类的核心职责(下单、行情、订单管理、 能力声明)、各交易所子类为什么要存在(处理特有行为和坑)、以及配置交易所时的常见要点(限流、key、止损上交易所)。读完你会理解 freqtrade 是怎么做到「一套策略跑遍几十个交易所」的。 内容来源:原项目文档 ,源码 及各子类,汉化并套用体系化模板。 ⚠️ 风险提示:不同交易所的限制、费率、地理封锁各不相同。
本节摘要:freqtrade 支持几十个交易所,底层靠 ccxt 这个统一封装库抹平各交易所 API 的差异,上层再用
Exchange类和每个交易所的独立子类(binance.py、bybit.py、okx.py等)做针对交易机器人的二次封装。本节讲清这套适配层的工作原理:ccxt 是什么、Exchange 类的核心职责(下单、行情、订单管理、_ft_has能力声明)、各交易所子类为什么要存在(处理特有行为和坑)、以及配置交易所时的常见要点(限流、key、止损上交易所)。读完你会理解 freqtrade 是怎么做到「一套策略跑遍几十个交易所」的。
内容来源:原项目文档
docs/exchanges.md,源码freqtrade/exchange/exchange.py及各子类,汉化并套用体系化模板。
⚠️ 风险提示:不同交易所的限制、费率、地理封锁各不相同。部署前务必阅读对应交易所的专属说明,确认你的服务器所在地不被封锁。
阅读完本节,你应当能够:
_ft_has 能力声明机制。加密货币世界有上百个交易所,每个的 API 都不一样——下单参数名不同、返回格式不同、限流规则不同。ccxt 这个开源库把这些差异抽象成一套统一接口:不管哪个交易所,fetch_ohlcv、create_order、fetch_balance 的调用方式都一样。
freqtrade 在 ccxt 之上再做一层封装(即 Exchange 类),原因有二:一是 ccxt 偶尔有 bug 或不准确的地方,需要针对交易机器人场景修正;二是交易机器人有特殊需求(止损上交易所、异步行情、订单簿定价等),需要统一处理。配置里只要写交易所名,freqtrade 就会自动实例化对应子类:
"exchange": { "name": "binance", "key": "your_exchange_key", "secret": "your_exchange_secret", "ccxt_config": {}, "ccxt_async_config": {} }
💡 ccxt 支持远不止 freqtrade 测试过的那些。freqtrade 官方测试覆盖 Binance、Bybit、OKX、Gate、Kraken 等,但 ccxt 支持 100+ 交易所。其他交易所大多能跑,但可能有边缘问题,社区会持续提交反馈和 PR。
Exchange 类(freqtrade/exchange/exchange.py)是所有交易所子类的基类。它的一个关键设计是 _ft_has(freqtrade has)能力声明——用字典声明这个交易所支持哪些功能、有哪些限制:
class Exchange: _ft_has_default: FtHas = { "stoploss_on_exchange": False, # 是否支持止损单挂到交易所 "ohlcv_has_history": True, # 是否能拉历史 K 线 "tickers_have_quoteVolume": True, # ticker 是否含成交额 "trades_limit": 1000, # 单次拉成交的上限 "ccxt_futures_name": "swap", # ccxt 里合约的叫法 "ws_enabled": False, # 是否启用 websocket # ... 还有几十项 } _ft_has: FtHas = {} # 子类覆写自己的能力 _ft_has_futures: FtHas = {} # 合约模式下的额外覆写 _supported_trading_mode_margin_pairs = [ (TradingMode.SPOT, MarginMode.NONE), # 默认只支持现货 ]
每个子类通过覆写 _ft_has 来声明自己的特殊能力。比如 Binance 子类会声明 stoploss_on_exchange: True(支持止损上交易所),而 Kraken 子类会覆写 ohlcv_has_history: False(历史 K 线要从成交数据重建)。
构造函数里还读取 trading_mode 和 margin_mode,决定是现货还是合约:
def __init__(self, config, ...): self._api: ccxt.Exchange # 同步接口 self._api_async: ccxt_pro.Exchange # 异步接口(行情订阅) self.trading_mode = TradingMode(config.get("trading_mode", TradingMode.SPOT)) self.margin_mode = MarginMode(config.get("margin_mode", MarginMode.NONE)) self.liquidation_buffer = config.get("liquidation_buffer", 0.05)
Exchange 类的核心职责:
fetch_ohlcv)、ticker、订单簿。打开 freqtrade/exchange/ 目录,每个主流交易所都有独立的 .py 文件:
exchange/ ├── exchange.py # 基类 ├── binance.py # 币安 ├── bybit.py # Bybit ├── okx.py # OKX ├── gate.py # Gate.io ├── kraken.py # Kraken ├── krakenfutures.py # Kraken 合约 ├── bingx.py # BingX ├── bitget.py # Bitget ├── htx.py # HTX(火兔) ├── hyperliquid.py # Hyperliquid(链上 DEX) ├── kucoin.py # Kucoin └── ...
子类要做的事:
_ft_has 声明能力(如是否支持止损上交易所、K 线历史、websocket)。_supported_trading_mode_margin_pairs 声明支持哪些交易模式。💡 为什么不用 ccxt 原生就够了? 因为 ccxt 是通用库,不会为「交易机器人」做专门优化。比如止损上交易所、异步行情订阅、订单簿定价、强平价计算这些机器人刚需,ccxt 要么不支持要么各交易所不一致,freqtrade 的子类就是来填这些缝的。
限流(rate limit) 是最容易踩的坑。ccxt 默认的限流通常靠谱,但遇到 DDOS 异常时可以手动调:
"exchange": { "name": "kraken", "key": "...", "secret": "...", "ccxt_config": {"enableRateLimit": true}, "ccxt_async_config": { "enableRateLimit": true, "rateLimit": 3100 // Kraken 建议 3.1 秒一次 } }
⚠️ rateLimit 单位是毫秒(延迟),不是每秒请求数。Kraken 报「Rate limit exceeded」时,要把这个值调大而不是调小。最优值取决于交易所和白名单大小。
API key 与密码短语:大多数交易所只要 key 和 secret,但 Kucoin 和 OKX 还要 password(API 密钥的密码短语):
"exchange": { "name": "okx", "key": "...", "secret": "...", "password": "your_api_key_passphrase" }
💡 Binance RSA 密钥:Binance 支持 RSA 格式 API 密钥。推荐用环境变量传入,避免 JSON 里处理换行符的麻烦:
export FREQTRADE__EXCHANGE__SECRET="$(cat ./rsa_binance.private)"
止损上交易所(stoploss_on_exchange):把止损单直接挂到交易所,而不是靠机器人轮询触发。好处是即使机器人掉线,止损也会执行。配置在 order_types.stoploss:
"order_types": { "stoploss": "limit", // 或 "market" "stoploss_on_exchange": true }
各交易所支持的止损类型不同——Binance 现货用 stop-loss-limit、合约支持 stop-limit 和 stop-market;Kraken 支持 stop-loss-market 和 stop-loss-limit。
| 交易所 | 关键坑与要点 |
|---|---|
| Binance | 地理封锁(加拿大、马来西亚、荷兰、美国);分 binance(国际)和 binanceus(美国)两个 ID;合约需设「单向仓位」「单资产模式」;建议黑名单加 BNB 避免手续费扣币导致卖不掉;合约必须用订单簿定价 |
| Kraken | API 只给 720 根历史 K 线,回测必须用 --dl-trades 下成交数据再重建;下载极耗内存和时间;rateLimit 是毫秒延迟 |
| OKX | API key 要密码短语;每次只返回 100 根 K 线(回测数据偏少);合约有「仓位模式」(买卖/对冲),建议用买卖模式,不能交易中途切换;my.okx.com 注册的要用 myokx 作为交易所名 |
| Kucoin | API key 要密码短语;建议黑名单加 KCS(同 BNB 道理) |
| Gate.io | API key 需「现货交易」或「永续合约」+「钱包(只读)」+「账户(只读)」权限;支持用 POINT 付手续费需配 unknown_fee_rate |
| Hyperliquid | 链上 DEX,适配层覆盖 CEX 和链上 |
⚠️ 多 bot 同账户:合约/保证金模式下,不能在同一账户跑两个 bot。freqtrade 假设自己是账户唯一使用者,强平价计算基于此假设。
合约模式下,止损和强平的关系需要特别关注。freqtrade 不会自动追踪强平手续费,所以用 liquidation_buffer(默认 0.05)在真实强平价和止损价之间留缓冲:
freqtrade强平价 = 强平价 ± |开仓价 - 强平价| × liquidation_buffer (+ 做多,- 做空)
⚠️
liquidation_buffer设 0 或太低会真的被强平,而 freqtrade 不追踪强平手续费,导致盈亏统计不准。建议配合stoploss_on_exchange使用,且别把 buffer 设太低。
_ft_has 字典声明能力(止损上交易所、K 线历史、websocket 等),子类覆写;构造时读 trading_mode/margin_mode。order_types.stoploss + stoploss_on_exchange。liquidation_buffer(默认 0.05)在强平价和止损间留缓冲;设太低会被真强平且统计不准。下一节,我们深入现货与合约杠杆——
trading_mode、margin_mode(isolated/cross)、leverage 回调、强平机制。