聚宽信号中转站
默认蓝
主题色
明暗
选择会记在本机浏览器,下次打开保持。
登录 免费注册
← 返回知识库
上手教程 2026-09-25 149 次阅读

上手 ②:聚宽侧配置及测试教程(含模拟位开通)

开通模拟位(含实时/延时这个坑)、粘贴接入代码、核对配置项,并用三段式自检加两次行为验证把链路测通。

这一篇解决什么

让聚宽上的策略在下单的那一刻,把「买什么、买多少、什么价」这套意图推给中转站。

聚宽侧只做一件事:说出来。它不关心 QMT 在不在线、也不等结果,推完就走。真正的下单在 QMT 那边(见第 ④ 篇)。

动手前先确认:你已经在中转站建好通道、并复制出了「聚宽接入代码」(第 ③ 篇)。 那段代码里已经写好了你的中转站地址、通道令牌和策略名,本文后面直接叫它接入代码。


第 1 步:开通模拟位(这一步决定你能不能正常联调)

为什么必须用模拟交易

接入代码会判断当前运行环境,只有 模拟交易 和 实盘 才推送信号:

运行环境会推信号吗原下单函数
回测(simple_backtest / full_backtest)不推照常执行
模拟交易(sim_trade)推照常执行
实盘(live_trade,如启用)推照常执行

回测故意不推:回测的时间戳是历史日期,推上去会被当成过期信号,而且会让你的历史回测凭空产生一笔笔无意义的信号记录。这正是我们想要的边界 —— 回测成交、净值、收益率与改造前完全一致。

所以联调要在模拟交易里做。

聚宽有多少个模拟位

聚宽官方口径:

  • 每个账号默认 3 个免费永久模拟位。
  • 会员用户的永久模拟位是实时运行;普通用户的永久模拟位是延时运行。
  • 需要更多,可以用积分兑换或购买限时模拟位;限时模拟位全部是实时运行。

⚠ 这是本链路最容易踩的坑之一。 本工具的策略面板里有一个 [风控] 信号时效(秒),默认 120 秒 —— 信号从生成到执行超过这个时间就会被拒。 如果你用的是普通用户的延时永久模拟位,模拟盘的行情和下单动作都带延迟,信号打到中转站时可能已经超出时效窗口,表现就是工作台里一堆 expired。

所以:联调阶段请用「实时运行」的模拟位 —— 也就是会员的永久位,或用积分兑换 / 购买的限时模拟位。 如果你只有免费永久位,先把 [风控] 信号时效(秒) 临时调大(例如 600)来跑通链路,但不要带着这个宽松值上传实盘。

开通步骤

方式 A:从已有策略直接开(推荐)

  1. 打开你的策略 → 点「回测」跑一次,拿到回测结果。
  2. 在回测结果界面右上方点 「模拟交易」 按钮。
  3. 弹出「新建模拟交易」对话框,填写:
字段建议值说明
交易名称例如 信号链路联调起个好认的名字,后面工作台信号列表里都靠它区分
初始资金例如 100000模拟资金,随便设
选择策略你的策略
数据频率每天与策略的 run_daily 对应;用分钟策略就选分钟
开始日期当天或近几天
时限永久 / 限时免费永久位选「永久」
  1. 点「确定」提交。

方式 B:从「我的交易」开

导航栏 → 「我的交易」 → 点 「新建模拟交易」。对话框字段与上面一致,可以选已有的策略或回测。

提交后不会立刻看到结果。 聚宽官方说明:模拟交易创建成功后,需要等待 A 股至少开盘一次才能查看运行结果。所以周末或盘后建的模拟盘,「我的交易」里是空的 —— 这不是没成功。

顺手把微信通知打开

「我的交易」列表里每条模拟交易右侧都有一个微信通知开关。打开 → 扫码绑定 → 之后策略每次买卖都会给你发一条微信。

联调阶段这个很有用:你能一眼看出「聚宽自己有没有在下单」,从而区分是策略没跑起来,还是只是中转站那一段没通。


第 2 步:准备策略

不需要为接入改写策略逻辑。唯一的要求是:

  • 策略里要有下单动作(order / order_value / order_target_value 等),否则没什么可推的。
  • 下单语句要写在带 context 的聚宽回调里(handle_data / run_daily 里调用的函数等)。这是聚宽的常规写法,正常写就满足。

接入代码靠从调用栈回溯拿到 context,再读 context.run_params.type 判断运行环境。 取不到 context 或判断不出类型时,它会保守跳过推送,同时照常执行你的原下单函数 —— 绝不干预策略。


第 3 步:粘贴接入代码

  1. 聚宽 → 「我的策略」 → 选中你的策略 → 进入代码编辑。
  2. 把接入代码整段粘到策略代码的最前面(第 1 行之前)。
┌────────────────────────────────────────────┐
│ # ===== 聚宽跟单接入代码 · BEGIN =====     │ ← 粘贴在这一段(在你自己代码之前)
│ ...(约 400 行,自包含,不需要改)         │
│ # ===== 聚宽跟单接入代码 · END =======     │
├────────────────────────────────────────────┤
│ import jqdata                              │ ← 你原来的代码,一行不动
│ def initialize(context):                   │
│     ...                                    │
│ def handle_data(context, data):            │
│     order_target_value('510300.XSHG', 1)   │
└────────────────────────────────────────────┘
  1. 点「编译」保存。

⚠ 必须是「最前面」,这是硬性要求。 接入代码要在模块加载阶段完成对聚宽下单函数的接管,必须跑在你的策略定义之前。贴在中间或末尾,接管就没装上去。

粘贴时的两个常见事故

现象原因处理
编译报 SyntaxError: future feature annotations is not defined编辑器给代码加了额外的头用中转站里复制的原文,不要手工改
编译报 invalid character in identifier粘贴时带进了中文全角标点(中文引号、中文逗号)重新复制一次原文,整段替换

第 4 步:核对配置项

接入代码顶部有一个 _JQR 字典,前三项已经按你的通道填好了,其余按需调整。

键默认作用
base_url已填中转站地址。不要改
token已填通道令牌,等同于钥匙。不要改,也不要截图外发
strategy已填策略名,显示在中转站工作台的信号列表里
enabledTrue改成 False 可临时关闭推送,策略照常运行
takeoverFalse改成 True 则「推送后不再下原单」,让 QMT 独占下单
debugFalse改成 True 打开 [jqr] 前缀的日志
price_codecounterparty报价方式:counterparty 对手价 / last 最新价 / b1~b5 / s1~s5 / limit
timeout5单次推送超时(秒)
size_on_joinquantTrue在聚宽侧就把金额折算成股数,两边下的才是同一个数(强烈建议保持 True)
lot_size100一手股数,科创板会自动上调为 200
allow_slippageTrue允许 QMT 在参考价基础上让价成交
slippage_ticks2允许让价几个最小变动价位(1 档 = 0.01 元)

关于 size_on_joinquant:为什么默认在聚宽侧折算

order_value('510300.XSHG', 2500) 只表达「大约 2500 元」这个意图。真正买多少股,是聚宽按它自己那一刻的成交价折算出来的。

如果把这个折算留给 QMT 做,QMT 会拿它的价格再算一遍 —— 两边价格只要差一点,整手数就可能差一手;QMT 拿不到价时更是直接归零。

所以接入代码默认在聚宽侧就把股数算死,只把确定的股数发出去。两边下的才是同一个数,这笔账才对得上。

关于 takeover:先用 False

takeover = False(默认)时,聚宽照常下它自己的模拟单,同时把信号推给中转站。这是联调阶段最安全的状态:你能直观看到「聚宽想下什么」,再拿它跟 QMT 的实际动作对照。

等你确认链路上每个环节都对了,再考虑改成 True。


第 5 步:三段式测试(从松到紧,别跳)

打开聚宽左侧的 「研究环境」(Jupyter),依次执行下面三段。

第 1 段:看配置对不对

_jqr_status()

正常输出类似:

[jqr] base_url=https://你的域名 strategy=双均线ETF enabled=True takeover=False 已接管=7 暂存=0

要确认三件事:base_url 是你的中转站、已接管=7(7 个下单/撤单函数都被接管了)、暂存=0(没有积压待补发的信号)。

第 2 段:验网络可达

_jqr_selfcheck()

它会依次打印中转站地址、令牌是否填入、策略名、已接管几个函数,以及中转站 /api/health 的返回。

返回 200 就说明网通、配置都在。 这一步只验「能连通」,不验整条链路。

如果这一步就失败了,先别往下走:检查 base_url 是否公网可达、令牌是否为空。 常见原因是公司网络 / 杀毒软件 / 防火墙拦了这台机器上的聚宽出口请求 —— 注意聚宽的代码是在聚宽的云服务器上跑的,不是在你本机跑,所以拦的不会是你的本地防火墙。

第 3 段:验整条链路(三跳)

_jqr_e2e_test()

它会发一条 100 股的探针信号,把整条链路走一整圈,然后逐跳打印:

 1 聚宽 → 中转站          [OK]   已入库 23:45:01
 2 中转站 → QMT           [OK]   (+3.1s)
 3 QMT 回报               [OK]   (+3.2s)
 结论:全链路通,三跳全部走通。

断在哪一跳会直说,并告诉你该去查什么。

想换标的或数量:

_jqr_e2e_test("600000.XSHG", 200)

探针不取价、不报单,所以收盘后 / 周末 / 节假日跑都有效,不用等开盘。 但第 2 跳要过,前提是 QMT 那边的策略正在【运行】 —— 否则探针会卡在中转站里「待领取」。所以顺序上,第 ④ 篇的 QMT 侧要先跑起来。


第 6 步:两次「真实」验证(这一步很多人跳过,但它最关键)

上面三段测的都是「链路通不通」。下面两件事测的是「行为对不对」。

验证一:回测不应该推信号

  1. 回到策略,点「回测」跑一段。
  2. 去中转站工作台看 「最近策略信号」。

期待结果:没有新增记录。

如果这里出现了记录,说明接入代码没能正确判断运行环境,或者被谁改动了。必须停下来查清楚再往下 —— 带着这个状态上实盘,你会把一堆历史信号打进真实账户。

验证二:模拟盘应该推信号

  1. 「我的交易」→ 确认模拟交易在运行中。
  2. 等策略产生一次下单动作。
  3. 回中转站工作台看「最近策略信号」,应能看到新记录,状态会从 待领取 → 已领取 → 已完成 依次推进。

到这一步,聚宽侧就完成了。


常见问题

Q:日志里没有 [jqr] 前缀的输出? A:先确认 _JQR["debug"] 是不是 True;再确认不是在回测模式 —— 回测下既不打日志也不推送,这是设计如此。

Q:推送失败 HTTP 401? A:通道令牌不对或已被更换。回中转站工作台重新复制一次接入代码,整段替换。

Q:推送失败 HTTP 402? A:权益已到期。去中转站的「积分与钱包 / 权益兑换」续费,续费后通道自动恢复。

Q:信号返回 expired? A:信号生成时间比执行时间早超了 [风控] 信号时效(秒)(默认 120 秒)。两个常见原因:① 上面说的延时模拟位;② 服务器时间不准。先排查这两条。

Q:信号返回 rejected? A:被风控拦了。中转站工作台的「回报 / 原因」列会写明具体是哪条规则。

Q:_jqr_e2e_test() 卡在第 2 跳? A:探针进了中转站但没人领 —— 也就是 QMT 侧的跟单策略没在【运行】。这不是聚宽的问题。

Q:推送成功但 QMT 没动作? A:去查第 ④ 篇。最常见的两个原因:QMT 策略只点了「编译」没点【运行】;或者参数面板里 [测试] 空跑模式 开着。

Q:能同时接多个策略吗? A:能。每个策略对应中转站上的一个通道,各自复制各自的接入代码。不要两个策略共用同一个通道令牌 —— 那会让工作台分不清信号是谁发的(还会触发「N 个客户端」的黄牌告警)。

Q:回测里的成交和净值会变吗? A:不会。接入代码在回测下不推送,回测成交、净值、收益率与改造前完全一致。

Q:聚宽的 Python 版本有什么限制? A:聚宽云端是 Python 3.6。你自己改接入代码时不要引入 3.7+ 特性:from __future__ import annotations、list[int]、X | None、海象运算符 := 都会直接报错。


本篇检查单

  • [ ] 已开通实时运行的模拟位(会员永久位 / 限时模拟位 / 积分兑换位)
  • [ ] 模拟交易已创建且在「运行中」
  • [ ] (可选)微信通知已打开,能收到聚宽自己的成交提醒
  • [ ] 接入代码已粘在策略代码最前面,编译通过
  • [ ] _jqr_status() 显示 已接管=7、暂存=0
  • [ ] _jqr_selfcheck() 里 /api/health 返回 200
  • [ ] _jqr_e2e_test() 三跳全 [OK]
  • [ ] 回测跑一遍,工作台「最近策略信号」没有新增记录
  • [ ] 模拟盘产生信号,工作台状态推进到「已完成」
  • [ ] 重复推送同一条信号只产生一条记录(幂等生效)

下一篇:③ 信号中转站配置及测试教程(如果还没做,建议现在先去补上,因为接入代码要从那里复制)。

想直接看策略?

官网策略的手动版与 QMT 自动版,都可以先了解逻辑与回测再决定。

浏览官网策略
?帮助 ◎知识库
帮助