KB / ARTICLE

策略基础与生命周期

策略文档修订 R1发布于 2026-11-05

本文介绍期魔方证券版软件策略编写的操作入口、编写前需要掌握的核心概念与基本规则,并讲解事件驱动模型下各回调的触发时机、先后顺序与关键细节。

软件操作

策略的新建与编译

打开期魔方软件,导航栏点击仓库,策略仓库 -> 选择策略与指标 -> 新增策略,填写基础信息 -> 生成文件并打开,右下角点击保存、校验并编译,完成策略新建,进行策略编辑,注意每次编写完一定要进行保存并编译。

策略新建

回测运行与结果展示

导航栏点击量化,回测分析 -> 新建回测 -> 填写基础参数和策略参数 -> 确认创建 -> 点击运行 -> 选择策略回测/参数优化,运行完成后可以查看结果(参数优化是表格)。

回测

核心概念

术语 说明
Bar(K 线) 某一时间段内的行情,包含开盘价、最高价、最低价、收盘价、成交量
Tick 逐笔或快照报价。Tick 策略调用频率高于 Bar 策略
Strategy(策略) 继承 Strategy 的交易逻辑。核心工作是看行情,再决定买还是卖
持仓 Position 当前持有的股票或 ETF 数量。证券现券账户中,正数表示多头,0 表示空仓
可卖持仓 T+1 下当天买入部分通常不可卖。卖出必须看 get_available_position()
回测 Backtest 用历史数据模拟策略,检验过去这样做会有怎样的盈亏路径
OrderReceipt 下单回执。表示请求已提交,不表示已经成交

编写策略的基本规则

  • 策略必须继承 Strategy。
  • 回调方法的名称和参数必须按本文书写,例如 on_bar(self, bar)。
  • 用户参数用内联字段声明(IntParam / FloatParam 等),运行中通过 self.params.xxx 读取。
  • 自定义状态保存为 self.xxx,不要使用模块级全局变量保存交易状态。
  • 行情事件中不要编写无限循环、长时间等待或阻塞式任务。
  • 下单后不代表立即成交。订单状态看 on_order(),实际成交看 on_trade()。
  • 股票卖出前优先使用 get_available_position() 检查可卖数量。
  • 多标的策略应根据 bar.symbol 或 tick.symbol 区分当前事件属于哪个标的。
  • 普通 A 股现券账户不要调用 short() 开空;平掉已有多头请用 sell() 或 close_position()。

策略结构与生命周期

事件驱动是什么意思

策略不需要自己写 while 循环。期魔方收到行情或交易事件后,会自动调用策略类中的相应方法:

创建策略实例
    ↓
执行参数注入(self.params 就绪)
    ↓
执行 __init__()(如有)
    ↓
若从快照恢复:先执行 on_resume()
    ↓
执行 on_start()
    ↓
反复接收事件
    ├─ 盘前钩子           → on_pre_open()(仅回测;实盘不会触发)
    ├─ 交易日开始         → on_before_trading()
    ├─ K 线到达           → on_bar()
    ├─ 高周期窗口闭合     → on_window_bar()(须先在 __init__ 中 subscribe_bars)
    ├─ Tick 到达          → on_tick()
    ├─ 横截面切片就绪     → on_cross_section()
    ├─ 定时器触发         → on_timer()
    ├─ 订单状态变化       → on_order() / on_reject()
    ├─ 订单成交           → on_trade()
    ├─ 账户变化           → on_portfolio_update()
    └─ 交易日结束         → on_after_trading()
    ↓
执行 on_stop()

只需重写实际需要的回调。没有重写的方法保持默认空实现,不影响策略运行。

类策略骨架

一个完整的证券策略一般包含:参数声明、on_start、on_bar(或 on_tick),以及按需实现的 on_order / on_trade / on_reject / on_stop。

from qmfquant import IntParam, Strategy


class DemoStrategy(Strategy):
    fast_period = IntParam(5, ge=2, le=200, title="快线周期")
    slow_period = IntParam(20, ge=3, le=500, title="慢线周期")
    quantity = IntParam(100, ge=100, title="交易数量")

    def on_start(self):
        self.set_history_depth(int(self.params.slow_period) + 1)
        self.log("策略启动")

    def on_bar(self, bar):
        pass

    def on_order(self, order):
        pass

    def on_trade(self, trade):
        pass

    def on_reject(self, order):
        pass

    def on_stop(self):
        pass

回调速查表

回调 何时触发 典型用途 回测 实盘
__init__ 创建策略对象时的初始化 不依赖引擎的普通字段及引擎启动前就要定下来的声明 是 是
on_start 策略实例启动后 订阅标的、设置历史深度、注册定时器 是 是
on_resume 热启动恢复时,且早于 on_start 恢复连接、处理快照续跑逻辑 是 视任务
on_bar 每根 K 线闭合时 主交易逻辑、指标更新、信号计算 是 是
on_window_bar subscribe_bars 的高周期窗口闭合时 多周期信号。窗口不参与撮合,下单放在 on_bar 是 是
on_tick 每个 Tick 到达时 高频/盘口响应、逐笔监控 是 是
on_order 订单状态变化时 跟踪下单生命周期 是 是
on_trade 收到成交回报时 成交日志、成交后状态更新 是 是
on_reject 订单首次进入 Rejected 记录拒单原因、降级处理 是 是
on_before_trading 本地交易日首次进入常规会话 盘前检查、生成交易日级信号 是 是
on_pre_open 每个交易日首个常规行情前 盘前信号、开盘成交语义 仅回测 不触发
on_cross_section 当日首个跨标的完整 bar 切片后 横截面同周期调仓 是 视数据切片
on_after_trading 离开常规会话时 日终统计、收盘后清理 是 是
on_portfolio_update 账户快照变化时 监控现金/权益变化 是 是
on_timer 定时器到点时 定时调仓、盘前任务、节律检查 是 是
on_error 用户回调抛异常时 记录异常源 是 是
on_stop 策略停止时 汇总统计、资源释放 是 是

【重要】实盘下 on_pre_open 不会触发。该回调依赖回测交易日历推导的盘前时点,实盘无此数据源。请改用 schedule_daily(...) 在盘前时点触发 on_timer,或把盘前逻辑放到 on_before_trading 中。

回调触发顺序

对于每个 bar / tick / timer 事件,框架大致按以下顺序分发:

  1. on_order / on_trade(若拒单则额外触发 on_reject)
  2. 框架钩子(on_before_trading / on_after_trading、on_cross_section、on_portfolio_update)
  3. 用户事件回调(on_bar / on_tick / on_timer)

说明:

  • on_reject 对同一订单 id 只触发一次。
  • on_before_trading 始终按“前一交易日/前一时点信息可见”工作;其中 get_history()、get_account()、equity 不应看到当日新 bar 或当日更新后的账户视图。
  • on_cross_section 在见到当日首个跨标的完整切片后触发;可以看到当日历史和当前账户快照。每天最多一次,适合选股轮动、同周期调仓。
  • on_after_trading 是结束/收尾型钩子,适合日终统计、清理与归档。若意图是“收盘决策、次日开盘成交”,更清晰的写法是在 on_bar 中按下一根开盘成交,或在回测中使用 on_pre_open;实盘请用 schedule_daily。
  • on_portfolio_update 采用增量触发:初始化时触发一次,后续仅在订单/成交或持仓相关价格变化时触发。可用 self.portfolio_update_eps 过滤微小资产波动(默认 0.0,不过滤)。
  • 停止阶段会在 on_stop 之前补发待触发的 on_after_trading。
  • on_error 参数为 (error, source, payload)。推荐通过 self.error_mode = "raise" | "continue" 控制行为(默认 raise)。

各回调更适合处理的任务:

回调 当前行情 是否适合下单 典型用途
on_start 无 否 订阅、定时器、一次性准备
on_before_trading 尚未进入当日新行情 可以,但只能用前一日可见数据 盘前选股、生成当日计划
on_pre_open 尚未进入当日正常行情 回测可以;实盘不会进入 盘前决策、开盘成交
on_bar 当前 Bar 是 K 线信号和交易
on_tick 当前 Tick 是 逐笔信号和交易
on_cross_section 当日切片已齐 是 横截面调仓
on_timer 不保证有新行情 是,但应确认价格来源 定时风控、定时调仓、实盘盘前
on_order / on_trade 不应依赖当前行情 谨慎 跟踪订单与成交
on_after_trading 当日交易阶段已结束 通常不下单 日终汇总
on_stop 无新行情 不应下单 结束日志、资源清理

启动阶段细节

一般按以下顺序运行:

  1. 框架创建策略对象并注入页面参数到 self.params。
  2. 如果任务从快照恢复,调用 on_resume()。
  3. 调用 on_start()。
  4. 开始接收 Bar、Tick、订单、成交和定时器事件。

on_start() 适合订阅标的、注册定时器以及执行依赖运行环境的初始化。

热启动时不要在 on_start() 中无条件重置已经恢复的状态:

def on_start(self) -> None:
    if not self.is_restored:
        self.trade_count = 0
    self.set_history_depth(20)

Bar 与 Tick

  • Bar 策略:重写 on_bar(self, bar),每根 K 线触发一次,适合日线、分钟线和大多数选股策略。
  • Tick 策略:重写 on_tick(self, tick),每个行情事件触发一次,调用频率更高。
  • 两者可以同时使用,但必须避免同一交易条件在 Bar 和 Tick 中重复下单。

warmup_period 只限制用户的 on_bar() 在积累足够 Bar 后再开始执行。即使设置了预热期,也建议在使用历史数组前检查其中是否存在 NaN。

下单、订单和成交

策略调用 buy() / sell()
    ↓
返回 OrderReceipt(表示已提交请求)
    ↓
on_order() 接收订单状态变化
    ↓
on_trade() 接收实际成交
    ↓
持仓、现金和权益随成交更新

不要在调用 buy() 的下一行就假设持仓已经增加。需要成交确认的逻辑,应放在 on_trade() 或后续行情事件中。

订单状态流转:

New → Submitted → Filled
                ↘ PartiallyFilled → Filled
                ↘ Cancelled
                ↘ Rejected
                ↘ Expired

Filled、Cancelled、Rejected 和 Expired 是常见终态。只有订单进入终态后,才适合清除策略保存的“等待订单”标记。

已复制到剪贴板
策略文档修订 R1

返回策略文档板块

评论