问题描述
解决方案
在聚宽(JoinQuant)平台中,确实存在一种方法可以让限价单跳过常规的价格和数量检查直接成交。这通常用于特殊的策略测试或信号验证。
您可以使用 set_option("match_by_signal", True) 来开启强制撮合模式。
功能说明
开启 set_option("match_by_signal", True) 后,回测引擎将执行以下逻辑:
- 强制成交:仅支持限价单。系统不对委托价格(如是否超过涨跌停)和成交数量(如是否超过盘口量)进行任何检查,直接以委托价成交。
- 忽略滑点:在此设置下,市价单的成交价也不会受滑点影响(虽然您主要关注限价单,但这是该选项的附带效果)。
- 适用场景:主要用于验证策略逻辑信号的生成,或者需要强制以特定价格成交的测试场景,不建议用于模拟真实交易环境。
策略代码示例
以下是一个完整的策略示例,展示了如何开启该选项并发送一个可能偏离市场价的限价单进行强制撮合。
# -*- coding: utf-8 -*-
import jqdata
def initialize(context):
# 设定要操作的股票
g.security = '000001.XSHE'
set_benchmark('000300.XSHG')
# 开启强制撮合模式 (关键代码)
# 开启后,限价单将不检查价格和数量,直接成交
set_option("match_by_signal", True)
# 每天开盘时运行
run_daily(market_open, time='09:30')
def market_open(context):
security = g.security
# 获取当前价格,仅为了对比日志
current_data = get_current_data()
current_price = current_data[security].last_price
log.info("当前市场价格: %.2f" % current_price)
# 构造一个限价单
# 假设我们故意挂一个非常低的价格买入(在正常模式下这很难立即成交),
# 或者挂一个涨停价之外的价格。
# 在 match_by_signal=True 模式下,这笔单子会以 1.00 元直接成交。
target_price = 1.00
log.info("尝试以 %.2f 的价格强制买入 100 股" % target_price)
# 下限价单
order(security, 100, style=LimitOrderStyle(target_price))
def handle_data(context, data):
pass
def after_trading_end(context):
# 打印当日成交记录,验证成交价格
trades = get_trades()
for trade in trades.values():
log.info("成交记录 - 时间: %s, 标的: %s, 价格: %.2f, 数量: %s" % (
trade.time, trade.security, trade.price, trade.amount
))
注意事项
- 仅限回测:此功能属于实验性设置项,主要用于回测环境下的逻辑验证。
- 必须使用限价单:该选项明确指出仅支持限价单(
LimitOrderStyle)进行强制撮合。 - 资金检查:虽然它跳过了价格和盘口数量检查,但通常仍然受限于账户的可用资金(Cash)。如果资金不足以支付
价格 * 数量,订单仍可能失败。
Q&A
Q: set_option("match_by_signal", True) 会影响市价单吗?
A: 会。根据文档,当开启此设置项时,市价单的成交价将不会受滑点(Slippage)的影响,通常按当时获取到的最新价成交。
Q: 这种模式下,如果股票停牌了还能成交吗?
A: 理论上 match_by_signal 主要是跳过价格和盘口量的撮合逻辑。对于停牌股票,聚宽底层通常会拦截交易(返回 None),但具体取决于回测引擎对“停牌”状态的优先级判断。通常建议在代码中加入 if not current_data[security].paused: 的判断来保持逻辑严谨性。
Q: 为什么我的限价单在开启此选项后没有成交?
A: 请检查以下两点:1. 账户是否有足够的可用资金(Available Cash);2. 确保您使用的是 LimitOrderStyle(限价单)而不是默认的市价单。