第 2 章 · 01 交易主循环与状态机 本节摘要:本节把 freqtrade 的「心跳」拆给你看。机器人的所有动作——拉行情、问策略、下单、风控——都由一个由两层组成的循环驱动:外层 用 throttle(节流)机制每隔几秒唤醒一次,并对齐到 K 线边界;内层 在每次唤醒时执行完整的「数据→策略→订单→持仓」闭环。整个机器人在任意时刻处于四种状态之一(RUNNING/PAUSED/STOPPED/RELOADCONFIG),由这个状态机决定该不该交易、要不要重载配置。读完本节,你能用一张图画清 freqtrade 进程从启动到退出的全部控制流,并在出问题时知道去看哪个环节。 内容来源:原项目源码 、 、 ,文档 ,汉化并套用体系化模板。
本节摘要:本节把 freqtrade 的「心跳」拆给你看。机器人的所有动作——拉行情、问策略、下单、风控——都由一个由两层组成的循环驱动:外层
Worker用 throttle(节流)机制每隔几秒唤醒一次,并对齐到 K 线边界;内层FreqtradeBot.process()在每次唤醒时执行完整的「数据→策略→订单→持仓」闭环。整个机器人在任意时刻处于四种状态之一(RUNNING/PAUSED/STOPPED/RELOAD_CONFIG),由这个状态机决定该不该交易、要不要重载配置。读完本节,你能用一张图画清 freqtrade 进程从启动到退出的全部控制流,并在出问题时知道去看哪个环节。
内容来源:原项目源码
freqtrade/worker.py、freqtrade/freqtradebot.py、freqtrade/enums/state.py,文档docs/bot-basics.md,汉化并套用体系化模板。
⚠️ 风险提示:理解主循环是排查实盘异常的前提——「为什么我的信号没触发」「为什么止损没生效」往往都能从循环执行时序里找到答案。实盘前务必先在 Dry-Run 下观察循环行为。
阅读完本节,你应当能够:
FreqtradeBot.process() 一次迭代内的 8 个核心步骤。freqtrade 进程启动后,控制权先交给 Worker,它再创建一个 FreqtradeBot 实例。两者职责分明:
💡 核心心法:把「调度」和「业务」分到两个类,是 freqtrade 能稳定长跑的关键——业务代码抛异常不会让循环崩掉,调度层会捕获并按状态机决定下一步。
Worker.run() 是一个无限循环,但每次迭代之间必须休眠——既是为了省 CPU,更是为了对齐到 K 线收盘时刻,避免在 K 线未成形时算指标。
节流的核心逻辑(_throttle() 方法):
process())。sleep_duration = throttle_secs - 已耗时。timeframe,进一步把 sleep_duration 夹取到「下一根 K 线收盘 + 1 秒」——确保唤醒时新 K 线已就绪。两个关键参数(在配置文件的 internals 段):
| 参数 | 默认 | 作用 |
|---|---|---|
process_throttle_secs |
5 | 业务迭代的最小间隔秒数 |
heartbeat_interval |
60 | 心跳日志间隔(0 关闭) |
⚠️ 不要把
process_throttle_secs调到 1 以下:迭代内会做大量网络请求与 DataFrame 计算,过快的循环既无意义(指标在 K 线收盘前不会变)又会触发交易所限流。
State 是一个 Python 枚举(源码 freqtrade/enums/state.py),定义了机器人的四种状态:
| 状态 | 数值 | 含义 |
|---|---|---|
RUNNING |
1 | 正常运行,会执行 process() 全流程 |
PAUSED |
2 | 暂停——不开新仓,但已有持仓仍被监控、可被止损/ROI 平仓 |
STOPPED |
3 | 停止——不再交易,等待用户手动清仓后退出 |
RELOAD_CONFIG |
4 | 重载配置——清理当前实例,重新读 JSON,重建 FreqtradeBot |
状态切换由用户通过 Telegram(/start、/stop、/pause、/reload_config)或 WebUI 触发,引擎内部修改 freqtrade.state 后,下一轮 _worker() 调用就会读到新状态。
💡 PAUSED 与 STOPPED 的关键差异:
PAUSED只是不开新仓,旧仓照常管理(可以止损出场);STOPPED几乎完全停摆,只检查是否还有未平仓。临时观望用pause,要下线维护用stop。
当状态是 RUNNING 或 PAUSED 时,每次唤醒都会调用 FreqtradeBot.process()。这是引擎的真正心脏,完成一个完整的「拉数据 → 问策略 → 管持仓 → 开新仓」闭环(顺序按源码与文档):
populate_indicators → populate_entry_trend → populate_exit_trend,把信号挂回 DataFrame。order_filled 回调;检查超时订单,触发 adjust_order_price。custom_exit、custom_stoploss 决定是否平仓;平仓前调用 confirm_trade_exit。max_open_trades 是否还有空位,扫描入场信号,通过 entry_pricing 或 custom_entry_price 定价,经 confirm_trade_entry 最后确认后下单。_process_running() 用两层异常捕获保护循环:
RETRY_TIMEOUT 秒重试,状态不变。⚠️ 看到 Telegram 收到 OperationalException 通知一定要重视:引擎已经自保进入 STOPPED,需要你
/start才会恢复;在没排查清楚前别盲目重启,否则可能反复崩在同一个错。
收到 /reload_config 后,Worker 进入 _reconfigure() 流程:
freqtrade.cleanup(),取消所有未成交订单(已成交持仓保留)。FreqtradeBot 实例。这是不重启进程就能改参数(如调整 max_open_trades、更换策略)的官方途径。注意:策略文件本身的修改不一定能通过 reload 生效——策略类是在实例化时加载的,通常需要重启进程。
Worker 负责调度与状态机,FreqtradeBot 负责业务闭环;分离让循环对业务异常免疫。process_throttle_secs(默认 5 秒)控制最小间隔,且自动对齐 K 线收盘 +1 秒,避免在半根 K 线上算指标。/reload_config 不重启进程换参数,但策略文件改动通常需要重启进程。下一节,我们看主循环赖以驱动的「大脑」——配置文件 JSON 的完整结构,以及交易所、风控、并发等关键参数如何设置。