本篇重点:本篇讲五种触发方式怎么按策略类型选,以及日内多次触发和盘前、盘后回调怎么设。
1 在哪里设置触发方式
主界面分左、中、右三栏。中间一栏最上面是「触发方式设置」分组:
- 点「触发类型」下拉框,可以看到五个选项:Tick触发、1分钟K线触发、5分钟K线触发、日K线触发、自定义定时触发。
- 选中一项后,下拉框下面会换成这一项的说明或参数。Tick、1 分钟、5 分钟、日线四种不需要填参数,只显示一行说明;自定义定时触发会显示时间点列表和时间点生成器。
- 把鼠标停在下拉框上,会弹出各周期数据的来源说明(V2)。

触发方式和其他回测参数一起保存在 .kh 配置文件里。点工具栏「保存配置」后,下次「加载配置」会原样恢复。
2 五种触发方式各自怎么工作
2.1 Tick 触发
- 规则:回测时每一条 tick 数据都会运行一次
khHandlebar。界面说明为「Tick触发无需额外配置,每个Tick都会触发策略」。 - 需要的数据:tick 数据。V2 里 BaoStock 和 Tushare 都不提供 tick,需要自己把 tick 数据导入 DuckDB 才能用。
- 特点:触发次数最多,数据量最大,回测最慢。策略里通常要自己加一层过滤条件,条件满足时才下单。
- 适合:需要逐笔判断价格变化的日内策略。
2.2 1 分钟 K 线触发
- 规则:每根 1 分钟 K 线运行一次。
- 需要的数据:1 分钟线。V2 里用 Tushare 下载,需要在 Tushare 开通
stk_mins权限;BaoStock 没有 1 分钟线。 - 适合:看分钟级信号的日内策略。
2.3 5 分钟 K 线触发
- 规则:每根 5 分钟 K 线运行一次。
- 需要的数据:5 分钟线,可用 BaoStock(免费)或 Tushare 下载。
- 适合:信号节奏比 1 分钟慢一些的日内策略,回测速度比 1 分钟快。
2.4 日 K 线触发
- 规则:每个交易日按一根日 K 线运行一次。界面上的说明文字是「每个交易日开盘后触发一次策略」,实际含义是:运行时当天这根日线已经完整,开盘、最高、最低、收盘都是全天的数据;日线时间显示的 09:30 只是日期标记。这一轮生成的买卖信号,按当天收盘价或策略给出的价格成交。
- 需要的数据:日线,可用 BaoStock 或 Tushare 下载。
- 特点:数据量最小,回测最快。选中后下方会多出「日内触发上限」,用法见第 5 节。
- 适合:按日线信号操作的波段、趋势策略。
2.5 自定义定时触发
- 规则:只在你指定的时间点运行,每个交易日每个时间点只运行一次,运行时刻就是你设定的时间点。
- 适合:定时调仓,或者只在开盘后、收盘前某个固定时刻操作的策略;也可以用来实现 10 分钟、30 分钟这类没有现成选项的间隔。
操作步骤:
- 在「时间点列表(每行一个时间点,格式:HH:MM:SS)」文本框里,每行写一个时间,例如
09:35:00、14:50:00。刚切换到这一项时文本框是空的,只有灰色的格式提示;加载的配置里写好的时间点会显示在这里。 - 时间点多的时候,用下面的「时间点生成器」:
– 「生成器类型」选「均匀分布」「整点分布」或「自定义间隔」,默认是均匀分布。均匀分布和自定义间隔都是从开始时间起每隔 N 秒生成一个点;整点分布只生成整点(如 10:00:00、11:00:00)。
– 设置「开始时间」(默认 09:30:00)、「结束时间」(默认 15:00:00)、「时间间隔(秒)」(默认 300,即 5 分钟)。
– 点「生成时间点」。 - 生成时软件会做三件事:先清空文本框里原有的时间点;把间隔调整为 3 的整数倍(范围 3~3600 秒,不是 3 的倍数时向下取整);去掉不在交易时段(9:30–11:30、13:00–15:00)内的点,并弹窗告诉你生成了几个、过滤掉几个。
- 生成后仍可以在文本框里手动增删。

举个例子:开始时间 09:30:00、结束时间 15:00:00、间隔填 1800(30 分钟),点「生成时间点」。从 09:30 到 15:00 每 30 分钟一个点,一共 12 个;其中 12:00、12:30 在午休时间,被过滤掉。弹窗显示「共生成12个时间点,其中10个在交易时段内,已自动过滤掉2个非交易时段的时间点」。

点「确定」后,文本框里是 10 个时间点:09:30、10:00、10:30、11:00、11:30、13:00、13:30、14:00、14:30、15:00。

自定义定时触发用哪种数据,由时间点自动决定:
- 所有时间点都是整分钟(秒数为 00):使用 1 分钟线。
- 只要有一个时间点不是整分钟:改用 tick 数据。
用 tick 数据时,每只股票取设定时间点之前 5 秒内(含这一刻)最新的一笔 tick 作为这次的行情;这 5 秒内没有 tick 的股票,这一次就没有数据。设定时间点之后的 tick 不会被用到,不会有未来数据。
带秒的时间点尽量避开开盘第一秒。例如写 09:30:00 时,有的股票开盘第一笔 tick 在 09:30:03 之后才出现,那一次就取不到数据。
无论用 1 分钟线还是 tick,「全量加载」和「省内存(分段)」两种加载模式下,触发的时间点和取到的数据都相同。
在 V2 里,1 分钟线要用 Tushare(需要 stk_mins 权限)下载,tick 数据要自己导入。使用自定义定时触发前,先确认对应的数据已经在本地。建议时间点都写成整分钟,这样只需要 1 分钟线。另外建议把股票池的日线也一起下载好:自定义定时触发时,每天收盘后的持仓市值和基准都按当天日线的收盘价估值(tick 时按不复权价格),本地没有日线时,才退回用当天最后一个时间点的价格估值。
3 按策略类型选择触发周期
触发周期不能随便选,要先看策略本身按什么节奏做判断,再决定触发方式,最后去下载对应周期的数据。
| 策略类型 | 触发方式 | 需要的数据 |
|---|---|---|
| 日内策略,要逐笔判断 | Tick 触发 | tick |
| 日内策略,看分钟级信号 | 1 分钟或 5 分钟 K 线触发 | 1m 或 5m |
| 波段、趋势策略,按日线信号操作 | 日 K 线触发 | 1d |
| 定时调仓、在固定时刻操作 | 自定义定时触发 | 整分钟时间点用 1m;有非整分钟时间点用 tick |
周期越短,要准备的数据越多,回测也越慢。策略只在收盘价上做判断时,用日线就够了;用分钟线跑同一个日线策略,结果不会更准确,只会更慢。
4 数据周期要和触发方式对应
左侧「数据设置」分组里有「周期类型」下拉框(tick、1m、5m、1d),它决定回测加载哪个周期的行情。对应关系如下:
| 触发方式 | 周期类型应选 |
|---|---|
| Tick 触发 | tick |
| 1 分钟 K 线触发 | 1m |
| 5 分钟 K 线触发 | 5m |
| 日 K 线触发 | 1d |
| 自定义定时触发 | 不做检查,按上一节规则自动选数据 |
点「开始运行」时,如果两者不对应,会弹出「周期不匹配警告」。例如周期类型选 1m、触发类型选日K线触发时,弹窗内容是:
- 当前配置:数据设置周期为 1 分钟K线,触发类型为日K线触发;
- 建议配置:数据设置周期为日K线,触发类型为日K线触发;
- 不匹配可能导致:性能问题(数据精度过高或过低)、触发精度问题(错过关键时间点)、策略执行异常;
- 最后问「是否继续运行回测?」。

- 点「继续运行」:照当前配置继续回测,运行日志里记一条 WARNING。
- 点「停止运行」:取消这次运行,回到界面修改。
用自定义定时触发时,建议把「周期类型」也设成实际会用到的周期(时间点都是整分钟就选 1m),这样回测前的数据检查会检查对的周期。
5 日线模式的「日内触发上限」
选中「日K线触发」后,下拉框下面会出现「日内触发上限」,范围 1~100,默认 1。其他触发方式下这一项隐藏、不生效。

默认值 1 表示每天只运行一次 khHandlebar。要在同一天运行多次,做两件事:
- 把「日内触发上限」设为需要的最大次数,例如 2。
- 在策略的
khHandlebar里调用khRequestNextDailyTrigger()。
规则:
khRequestNextDailyTrigger()返回True表示申请成功。框架先处理本轮返回的交易信号,再用同一天的行情数据立即再调用一次khHandlebar,这时账户资金和持仓已经是本轮成交后的状态。- 当天的总运行次数不会超过「日内触发上限」。已经到上限,或者当前不是日 K 线触发时,函数返回
False,不会再运行。 - 第二天重新计数。
- 同一天运行多轮时,回测报告的「日收益」和每日统计每天仍然只记一行,在当天最后一轮之后记录;当天收益相对上一个交易日收盘后的总资产计算。
典型用法是「先卖后买」:第 1 轮只处理卖出,释放资金;第 2 轮用卖出后的资金处理买入。下面是结构示意,交易条件需要自己补充:
from khQuantImport import *
STATE = {"date": None, "round": 0}
def khHandlebar(data):
signals = []
date_str = khGet(data, "date")
# 换了新的一天,轮次从 1 开始;同一天再次进入,轮次加 1
if STATE["date"] != date_str:
STATE["date"] = date_str
STATE["round"] = 1
else:
STATE["round"] += 1
if STATE["round"] == 1:
# 第 1 轮:检查持仓,生成卖出信号
# signals.extend(generate_signal(data, code, price, 1.0, "sell", "卖出原因"))
khRequestNextDailyTrigger() # 申请当天再运行一次
elif STATE["round"] == 2:
# 第 2 轮:用卖出后的可用资金生成买入信号
pass
return signals
「日内触发上限」保持 1 时,调用 khRequestNextDailyTrigger() 会返回 False,第 2 轮不会发生。写了多轮逻辑的策略,记得把上限调到对应的次数。
6 盘前、盘后回调
中间一栏的「盘前盘后触发设置」分组有两行:
- 「触发盘前回调」+「运行时间」,默认 08:30:00;
- 「触发盘后回调」+「运行时间」,默认 15:30:00。
两项默认都不勾选。勾选后:
- 每个交易日开始、当天第一次触发之前,框架调用策略里的
khPreMarket(data)。盘前回调里只能看到盘前已经知道的行情:每只股票上一个交易日最后一根 K 线的数据(日线模式就是上一天的日线),看不到当天开盘后的价格。回测第一天没有上一个交易日的数据,这天盘前回调里取不到个股行情,策略里要做好判断。 - 每个交易日最后一次触发之后,框架调用策略里的
khPostMarket(data)。回测最后一天也会调用。 - 「运行时间」里填的时间会作为这次调用的当前时间传给策略,用
khGet(data, "time")之类的函数取到的就是这个时间。 - 策略文件里要有同名函数。勾选了但策略里没有写,运行日志会给出警告,回调不执行。
回调里也可以返回交易信号,但不会立即成交,框架会把它们转成限价挂单:
- 盘前回调的信号:当日有效,当天行情满足限价时成交。
- 盘后回调的信号:一律转为下一个交易日的挂单,有效到下一个交易日收盘。回测最后一天的盘后信号没有后续行情可以成交,按未成交(过期)处理,不改变资金和持仓。
常见用途:
- 盘前:确定当天要关注的股票、重置当天的状态变量。
- 盘后:统计当天的交易、记录持仓和资产,为第二天准备数据。

7 账户信息
中间一栏的「账户信息」分组有两项:
- 初始资金:回测开始时账户里的现金,默认 1000000。回测报告里的「初始资金」、收益率都以它为基准。
- 最小交易量:默认 100,会随配置一起保存,并写进回测记录。
这两个输入框见上一节的截图。
策略里计算买入数量时,可以用 calculate_max_buy_volume 按可用资金算出最多能买多少股,结果按 A 股 100 股一手取整。
V3 的触发方式、日内触发上限、盘前盘后回调和账户信息与 V2 完全相同。不同的是 V3 自带相关案例可以直接照着学:「日内多次触发」案例演示了 khRequestNextDailyTrigger() 先卖后买的写法;T+0 ETF 网格案例演示了分钟级的日内交易。V3 的数据来源也更多(见 1.4 的 V3 亮点)。
※ 策略案例股票池只是示例(请换成你自己选的标的),关键参数含随机数,只用来演示写法,不构成任何策略或投资建议。
常见问题
问:选了 1 分钟 K 线触发,开始运行后提示周期不匹配,怎么办?
答:把左侧「数据设置」里的「周期类型」改成 1m,并确认本地已经有这些股票的 1 分钟线。V2 的 1 分钟线要用 Tushare 下载。
问:日线策略能不能改用 5 分钟触发,让结果更准?
答:不能提高准确性。策略按日线数据判断时,用日 K 线触发就够了。换成 5 分钟触发,策略每天会运行 48 次,还需要准备 5 分钟线,回测变慢,信号也可能因为日内价格变化而和原意不同。
问:自定义定时触发写了 09:30:15 这样的时间,回测报数据缺失?
答:只要有一个时间点不是整分钟,软件就改用 tick 数据。V2 里 tick 需要自行导入。把时间点都改成整分钟,就只需要 1 分钟线。
问:自定义定时触发用了 tick 数据,09:30:00 这个时间点有的股票没有数据?
答:tick 模式下,每个时间点只取前 5 秒内的最新一笔 tick。开盘第一笔 tick 可能在 09:30:03 之后才出现,这时 09:30:00 就取不到。把时间点往后挪几秒(例如 09:30:05)即可。
问:调用了 khRequestNextDailyTrigger(),但每天还是只运行一次?
答:检查两处:触发方式必须是「日K线触发」;「日内触发上限」要大于 1。
问:盘前回调里下的单为什么没有马上成交?
答:盘前、盘后回调返回的信号会转成限价挂单,要等后面的行情满足限价才成交。盘前单当日有效;盘后单转为下一个交易日的挂单,有效到下一个交易日收盘。回测最后一天的盘后单没有后续行情,不会成交。
- 「日内多次触发」案例:演示 khRequestNextDailyTrigger 的用法
- T+0 ETF 网格案例 4 个
- 数据库指标读写案例 4 个
※ 策略案例股票池只是示例(请换成你自己选的标的),关键参数含随机数,只用来演示写法,不构成任何策略或投资建议。
本篇基于开源 V2 和 V3.4.1.10 编写。