本文介绍如何用内联字段声明策略参数并只读读取,同时汇总策略中会遇到的各类数据容器:如何读取、分别有哪些字段,以及哪些是对象、哪些是字典。
参数声明方式
推荐用内联字段声明策略参数:直接在类体内用 IntParam / FloatParam / BoolParam / ChoiceParam / DateRangeParam 赋值,需要提前导入。构造期完成校验,运行中通过 self.params.<name> 只读访问。
参数字段工具:
| 工具 | 主要参数 | 用途 |
|---|---|---|
IntParam(default, ge=None, le=None, title=None, description=None) |
整数默认值、上下限 | 整数输入 |
FloatParam(default, ge=None, le=None, title=None, description=None) |
小数默认值、上下限 | 小数输入 |
BoolParam(default, title=None, description=None) |
布尔默认值 | 开关输入 |
ChoiceParam(default, choices, title=None, description=None) |
默认项、可选项列表 | 单选输入 |
DateRangeParam(default=None, title=None, description=None) |
日期区间默认值 | 日期区间输入 |
要点:
self.params是 frozen 对象,不支持在运行期赋值修改。- 派生初始化(指标、缓存结构等)放在
on_start()。 - 如果希望 IDE 能推断字段类型,可以写成
fast: int = IntParam(10, ge=2, le=200)。
示例:
from qmfquant import BoolParam, ChoiceParam, FloatParam, IntParam, Strategy
class ConfigurableStrategy(Strategy):
window = IntParam(20, ge=2, le=250, title="均线周期", description="计算均线使用的 K 线数量")
quantity = IntParam(100, ge=100, title="下单数量")
allow_trade = BoolParam(True, title="允许交易")
mode = ChoiceParam("trend", choices=["trend", "reversal"], title="策略模式")
stop_pct = FloatParam(5.0, ge=0, le=50, title="止损百分比")
def on_start(self) -> None:
self.set_history_depth(int(self.params.window))
self.log(f"参数就绪:window={self.params.window} quantity={self.params.quantity}")
框架自带变量和快捷属性
使用时先区分两类属性:
- 只读属性:由框架维护,只能读取,不能在策略中赋值,例如
cash、equity。 - 可配置属性:允许在
on_start()中设置,例如warmup_period、lot_size。
属性值代表当前回调时点的状态。订单刚提交但尚未成交时,cash、positions 等值可能还没有发生最终变化。
行情与时间
| 变量 | 类型 | 说明 |
|---|---|---|
self.current_bar |
Bar \ None |
当前正在处理的 K 线;仅在 Bar 事件中保证有值 |
self.symbol |
str |
当前行情事件的标的代码;没有当前 Bar/Tick 时不要依赖此属性 |
self.open |
float |
当前 Bar 开盘价;Tick 模式下为 0.0 |
self.high |
float |
当前 Bar 最高价;Tick 模式下为 0.0 |
self.low |
float |
当前 Bar 最低价;Tick 模式下为 0.0 |
self.close |
float |
当前 Bar 收盘价,或当前 Tick 最新价 |
self.volume |
float |
当前 Bar 或 Tick 成交量 |
self.now |
pandas.Timestamp \ None |
当前策略时间,已按 timezone 转为本地时间。尚无有效运行时间时为 None |
self.timezone |
str |
策略时区,默认 Asia/Shanghai |
self.ctx.session |
会话枚举 | 当前交易会话,用于按盘前/连续竞价/午休等分支 |
推荐优先使用回调参数中的 bar.symbol、bar.close 或 tick.price。快捷属性适合单标的策略。
账户与持仓
| 变量 | 类型 | 说明 |
|---|---|---|
self.cash |
float |
当前现金余额,只读;冻结金额另见 get_account()["frozen_cash"] |
self.equity |
float |
当前账户总权益,只读 |
self.positions |
dict[str, float] |
持仓字典。键为标的代码,值为数量。空仓时为 {} |
self.position |
仓位快捷对象 | 当前标的仓位,可读 size、available、entry_price、avg_price |
self.lot_size |
int \ dict[str, int] |
最小交易单位;可设置统一值或按标的设置 |
self.commission_rate |
float |
百分比佣金率的只读视图 |
self.min_commission |
float |
单笔最低佣金,只读 |
self.stamp_tax_rate |
float |
卖出侧印花税比例,只读 |
self.transfer_fee_rate |
float |
过户费比例,只读 |
self.commission_policy |
dict[str, str \ float] |
费用模式字典,只读。键 type 为 str,键 value 为 float |
费用属性由回测或任务配置注入。不要在策略中写 self.commission_rate = ...,会抛出 AttributeError。lot_size 是例外,允许在策略中设置:
def on_start(self) -> None:
self.lot_size = 100
# 或多标的:
# self.lot_size = {"600000.SH": 100, "510300.SH": 100}
def on_bar(self, bar: Bar) -> None:
pos = self.position
self.log(
f"{bar.symbol} 持仓={pos.size} 可卖={pos.available} "
f"成本={pos.entry_price} 现金={self.cash:.2f}"
)
运行控制
| 变量 | 默认值 | 说明 |
|---|---|---|
self.warmup_period |
0 |
执行 on_bar() 前需要积累的 Bar 数量 |
self.is_restored |
False |
当前任务是否由快照恢复,只读 |
self.enable_precise_day_boundary_hooks |
False |
是否提高 on_before_trading / on_after_trading 触发精度 |
self.portfolio_update_eps |
0.0 |
触发账户更新回调的变化阈值 |
self.error_mode |
"raise" |
"raise" 出错终止;"continue" 记录后尝试继续 |
error_mode="continue" 时必须确保策略状态仍然安全。基础策略通常保持默认 "raise"。
对象总览
对象用属性读取,例如 bar.close、order.status。字典用键读取,例如 account["cash"]、event["trading_date"]。
| 来源 | 容器 | 读取方式 |
|---|---|---|
on_bar(bar) |
Bar 对象 |
bar.close |
on_tick(tick) |
Tick 对象 |
tick.price |
on_order / on_reject / get_order() |
Order 对象;查不到单笔时为 None |
order.status |
on_trade(trade) |
Trade 对象 |
trade.price |
get_trades() |
list[ClosedTrade] |
trades[0].pnl |
get_open_orders() |
list[Order],无活动单时为 [] |
orders[0].id |
buy() / sell() |
OrderReceipt 对象 |
receipt.primary |
get_account() |
字典 | account["cash"] |
get_instrument() |
InstrumentSnapshot 对象 |
info.lot_size |
get_instruments() |
字典,值为 InstrumentSnapshot |
infos[symbol].lot_size |
get_instrument_field() |
该字段本身的值 | 直接使用返回值 |
get_execution_capabilities() |
字典 | caps["supports_short_sell"] |
get_history() |
一维 numpy.ndarray |
closes[-1] |
get_history_map() |
字典,值为 numpy.ndarray |
history[symbol][-1] |
get_history_df() |
pandas.DataFrame |
df["close"] |
self.positions |
dict[str, float],空仓为 {} |
self.positions[symbol] |
self.position |
Position 对象 |
self.position.size |
self.commission_policy |
字典 | self.commission_policy["value"] |
on_portfolio_update(snapshot) |
字典 | snapshot["equity"] |
on_pre_open(event) |
字典 | event["trading_date"] |
on_before_trading / on_after_trading / on_cross_section |
两个独立参数,不是字典 | trading_date、timestamp |
bar.extra |
字典 | bar.extra["turnover"] |
Bar K 线对象
每根 K 线触发一次,适合日线、分钟线和大多数选股策略。
on_bar(bar) 和 on_window_bar(bar) 传入 Bar 对象。self.current_bar 在 on_bar 里就是这同一个对象。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
symbol |
标的代码 | str |
与行情源一致。本次日线样本为 "600000",不带交易所后缀 |
timestamp |
时间戳 | int |
UTC 纳秒。窗口 K 线取该窗口终点 |
timestamp_iso |
ISO 时间 | str |
UTC 时间字符串,如 "2026-10-08T07:00:00Z"。北京时间用 self.now 或 format_time(bar.timestamp) |
freq |
周期标签 | str \ None |
任务基础周期的 K 线为 None。on_window_bar 中为 "15min"、"1h"、"1d" 等 |
open |
开盘价 | float |
这根 K 线的开盘价 |
high |
最高价 | float |
这根 K 线的最高价 |
low |
最低价 | float |
这根 K 线的最低价 |
close |
收盘价 | float |
这根 K 线的收盘价 |
volume |
成交量 | float |
这根 K 线的成交量 |
extra |
扩展行情 | dict |
扩展字段字典,键见下表 |
bar.extra 是字典。其中的时间是毫秒,bar.timestamp 才是纳秒。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
bar_start_ms |
K 线开始时间 | float |
毫秒时间戳 |
bar_end_ms |
K 线结束时间 | float |
毫秒时间戳 |
trade_time |
交易时间 | float |
毫秒时间戳 |
auction_event_time_ms |
集合竞价时间 | float |
毫秒。没有集合竞价事件时为 0.0 |
turnover |
成交额 | float |
这根 K 线的成交额 |
pre_close |
前收盘价 | float |
前收。数据源未填时为 0.0,使用前先判断 |
open_interest |
持仓量 | float |
股票现货为 0.0 |
settlement |
结算价 | float |
股票现货为 0.0 |
forming |
形成中标记 | float |
0.0 表示这根 K 线已经完成 |
Tick 对象
每个行情事件触发一次,调用频率更高。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
timestamp |
时间戳 | int |
UTC 纳秒 |
timestamp_iso |
ISO 时间 | str |
UTC 时间字符串 |
symbol |
标的代码 | str |
当前 Tick 的标的 |
price |
最新价 | float |
当前成交价或快照价 |
volume |
成交量 | float |
当前 Tick 成交量 |
Order 订单对象
on_order(order)、on_reject(order) 和 get_order() 给出的都是 Order 对象。一次委托会按状态多次进入 on_order()。未成交时 filled_quantity 为 0.0、average_filled_price 为 None;全部成交后二者变为实际成交数量和均价。
get_open_orders() 返回 list[Order]。没有活动订单时是空列表 []。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
id |
订单号 | str |
与 OrderReceipt.primary、Trade.order_id 对应 |
symbol |
标的代码 | str |
委托标的 |
side |
买卖方向 | OrderSide |
如 OrderSide.Buy、OrderSide.Sell |
order_type |
订单类型 | OrderType |
如 OrderType.Limit、OrderType.Market |
time_in_force |
有效期 | TimeInForce |
如 TimeInForce.GTC、TimeInForce.Day |
status |
订单状态 | OrderStatus |
如 New、Filled。终态见前文状态流转 |
quantity |
委托数量 | float |
申报股数 |
filled_quantity |
已成交数量 | float |
累计成交数量。未成交为 0.0 |
price |
委托价格 | float \ None |
限价单为委托价。市价单可能为 None |
average_filled_price |
成交均价 | float \ None |
未成交为 None,成交后为均价 |
trigger_price |
触发价 | float \ None |
止损、止盈触发价。普通限价单为 None |
trail_offset |
跟踪偏移 | float \ None |
跟踪止损偏移。普通单为 None |
trail_reference_price |
跟踪参考价 | float \ None |
跟踪止损参考价。普通单为 None |
commission |
手续费 | float |
该订单已产生的费用。未成交为 0.0 |
position_effect |
开平方向 | PositionEffect |
如 PositionEffect.Open |
reduce_only |
只减仓 | bool |
是否只允许减仓 |
order_role |
订单角色 | OrderRole |
普通单为 OrderRole.Standalone |
tag |
订单标签 | str |
下单时传入的 tag。未传时可能为空字符串 |
reject_reason |
拒单原因 | str |
未拒单时为 ""。拒单后为原因文本 |
created_at |
创建时间 | int |
UTC 纳秒 |
created_at_iso |
创建时间文本 | str |
UTC ISO 时间 |
updated_at |
更新时间 | int |
UTC 纳秒。状态变化后会更新 |
updated_at_iso |
更新时间文本 | str |
UTC ISO 时间 |
owner_strategy_id |
所属策略 | str |
产生该订单的策略标识 |
graph_id |
复杂订单图 | str \ None |
括号单、OCO 等图编号。普通单为 None |
parent_order_id |
父订单号 | str \ None |
子单指向父单。普通单为 None |
trade.quantity 是这一笔成交的数量。订单累计成交数量看 order.filled_quantity。
Trade 成交对象
on_trade(trade) 传入 Trade 对象,表示这一次实际成交。它没有 group_id。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
id |
成交编号 | str |
这一笔成交的编号 |
order_id |
订单号 | str |
对应 Order.id |
symbol |
标的代码 | str |
成交标的 |
side |
买卖方向 | OrderSide |
如 OrderSide.Buy |
quantity |
成交数量 | float |
这一笔的成交股数 |
price |
成交价格 | float |
这一笔的成交价 |
commission |
手续费 | float |
这一笔成交的费用 |
position_effect |
开平方向 | PositionEffect |
如 PositionEffect.Open |
timestamp |
成交时间 | int |
UTC 纳秒 |
timestamp_iso |
成交时间文本 | str |
UTC ISO 时间 |
bar_index |
K 线序号 | int |
成交发生时的 Bar 序号 |
owner_strategy_id |
所属策略 | str |
产生该成交的策略标识 |
ClosedTrade 闭合交易
get_trades() 返回 list[ClosedTrade]。未完成开平配对的持仓不会出现在这个列表里。side 是字符串 "Long",不要和 Trade.side 的 OrderSide 枚举直接比较。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
symbol |
标的代码 | str |
这轮交易的标的 |
side |
持仓方向 | str |
多头为 "Long" |
quantity |
数量 | float |
这一轮配对的股数 |
entry_time |
开仓时间 | int |
UTC 纳秒 |
exit_time |
平仓时间 | int |
UTC 纳秒 |
entry_price |
开仓价 | float |
开仓成交价 |
exit_price |
平仓价 | float |
平仓成交价 |
pnl |
毛利 | float |
扣除手续费之前的盈亏 |
net_pnl |
净利 | float |
扣除手续费之后的盈亏 |
commission |
手续费 | float |
开仓和平仓合计费用 |
return_pct |
收益率 | float |
百分数。-0.72 表示约 -0.72%,不是 -0.0072 |
duration |
持仓时长 | int |
纳秒。一天为 86400000000000 |
duration_bars |
持仓 K 线数 | int |
从开仓到平仓经过的 Bar 数 |
entry_tag |
开仓标签 | str |
开仓订单的 tag |
exit_tag |
平仓标签 | str |
平仓订单的 tag |
entry_portfolio_value |
开仓时权益 | float |
开仓成交时的账户权益 |
mae |
最大不利变动 | float |
持仓期间的最大不利变动 |
mfe |
最大有利变动 | float |
持仓期间的最大有利变动 |
max_drawdown_pct |
交易最大回撤 | float |
百分数。1.44 表示 1.44% |
Position 持仓对象
self.position 是当前标的的 Position 对象。空仓时四个数量都是 0.0。对象上没有 symbol 属性,标的用当前 bar.symbol。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
size |
持仓数量 | float |
当前总持仓 |
available |
可卖数量 | float |
T+1 下当天买入部分通常不计入 |
entry_price |
持仓成本 | float |
持仓均价。空仓为 0.0 |
avg_price |
持仓均价 | float |
与 entry_price 相同 |
self.positions 是字典 dict[str, float]:键为标的代码,值为持仓数量。空仓时是 {}。
InstrumentSnapshot 标的快照
get_instrument() 返回这个对象。get_instruments() 返回字典,键是标的代码,值是该对象。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
symbol |
标的代码 | str |
如 "600000" |
asset_type |
资产类型 | str |
策略侧名称,股票为 "STOCK",基金为 "FUND" |
multiplier |
合约乘数 | float |
股票为 1.0 |
margin_ratio |
保证金比例 | float |
股票现货样本为 1.0 |
tick_size |
最小变动价位 | float |
股票样本为 0.01 |
lot_size |
每手数量 | float |
这里是 float。股票样本为 100.0。策略里的 self.lot_size 是 int |
option_margin_model |
期权保证金模型 | str \ None |
股票为 None |
option_type |
期权类型 | str \ None |
股票为 None |
strike_price |
行权价 | float \ None |
股票为 None |
expiry_date |
到期日 | int \ None |
股票为 None |
underlying_symbol |
标的物代码 | str \ None |
股票为 None |
implied_volatility |
隐含波动率 | float \ None |
股票为 None |
reference_volatility |
参考波动率 | float \ None |
股票为 None |
settlement_type |
结算类型 | str \ None |
股票为 None |
settlement_price |
结算价 | float \ None |
股票为 None |
static_attrs |
静态附加属性 | dict[str, str] |
数据源附加信息,见下表 |
static_attrs 是字典。本次股票样本有两个键:
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
reference_asset_type |
参考资产类型 | str |
如 "stock" |
instrument_id |
内部合约标识 | str |
如 "SSE.stock.600000" |
commission_policy 费用字典
self.commission_policy 是只读字典。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
type |
计费方式 | str |
百分比佣金为 "percent" |
value |
费率 | float |
与 self.commission_rate 一致。0.001 表示 0.1% |
on_portfolio_update 的 snapshot
回调参数是字典。其中 positions 和 available_positions 仍是 dict[str, float],空仓时为 {}。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
timestamp |
时间戳 | int |
UTC 纳秒 |
session |
交易会话 | TradingSession |
如 TradingSession.Continuous |
cash |
现金 | float |
当前现金 |
equity |
权益 | float |
当前账户权益 |
market_value |
持仓市值 | float |
当前持仓市值 |
margin |
占用保证金 | float |
当前保证金占用 |
frozen_cash |
冻结资金 | float |
未完成订单冻结的资金 |
positions |
持仓 | dict[str, float] |
键为标的代码,值为持仓数量 |
available_positions |
可卖持仓 | dict[str, float] |
键为标的代码,值为可卖数量 |
这个字典不包含 get_account() 的全部键。权益、现金和持仓以这里的字段为准;融资、利息等看 get_account()。
交易日回调的参数
on_before_trading(trading_date, timestamp)、on_after_trading(trading_date, timestamp)、on_cross_section(trading_date, timestamp) 收到的是两个独立参数,框架不会把它们包成一个字典。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
trading_date |
交易日 | datetime.date |
本地交易日 |
timestamp |
时间戳 | int |
UTC 纳秒 |
on_pre_open 的 event
仅回测触发。参数是字典。
| 参数 | 参数名称 | 参数类型 | 描述 |
|---|---|---|---|
trading_date |
交易日 | datetime.date |
即将开始的交易日 |
timestamp |
时间戳 | int |
UTC 纳秒 |
expected_open_at |
预期开盘时间 | int |
UTC 纳秒 |
session |
交易会话 | TradingSession |
会话枚举 |
session_label |
阶段名称 | str |
本次样本为 "pre_open" |
market |
市场标识 | str |
本次样本为 "default" |
相关阅读

评论
登录后参与讨论,与站内账号体系共用。