问题描述
解决方案
在聚宽(JoinQuant)回测环境中,默认遵循中国 A 股市场的 T+1 交易制度(即当日买入的股票次日才能卖出)。
若需要在回测中强制实现股票的 T+0 交易(即当日买入后可立即卖出),可以通过调用实验性设置接口 set_option 来开启 T+0 模式。
以下是具体的实现方法和代码示例。
实现方法
在策略的初始化函数 initialize(context) 中,添加以下代码即可开启 T+0 模式:
set_option("t0_mode", True)
功能说明:
- 开启该选项后,回测引擎将允许对股票进行当日买入、当日卖出的操作。
- 该设置仅在回测和模拟交易的逻辑层面生效,主要用于验证高频策略或特定算法交易,请注意这与 A 股实际交易规则(除科创板/创业板ETF、可转债等特定品种外)不符。
策略代码示例
以下是一个完整的策略示例。该策略演示了开启 T+0 模式后,在同一天内对同一只股票进行买入和卖出操作。
# -*- coding: utf-8 -*-
import jqdata
def initialize(context):
# 开启 T+0 模式,允许当日买入当日卖出
set_option("t0_mode", True)
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设置手续费(股票类)
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 定义要操作的股票,例如:平安银行
g.security = '000001.XSHE'
# 每天开盘时运行
run_daily(market_open, time='09:30')
# 每天收盘前运行
run_daily(market_close, time='14:55')
def market_open(context):
# 获取当前可用资金
cash = context.portfolio.available_cash
# 如果有资金,全仓买入
if cash > 0:
log.info("早盘买入: %s" % g.security)
order_value(g.security, cash)
def market_close(context):
# 获取当前持仓
position = context.portfolio.positions[g.security]
# 如果有持仓(包括今日买入的),全部卖出
# 在默认 T+1 模式下,今日买入的股票 closeable_amount 为 0,无法卖出
# 开启 T+0 模式后,total_amount 即为可卖出数量
if position.total_amount > 0:
log.info("尾盘卖出(T+0操作): %s" % g.security)
order_target(g.security, 0)
注意事项
- 真实性风险:A 股主板股票实行 T+1 制度。如果在回测中开启
t0_mode,回测结果可能无法在实盘中复现,除非您交易的是 ETF、可转债等本身支持 T+0 的品种,或者您是在进行“底仓 T+0”策略(即利用已有持仓进行变相 T+0)。 - 底仓 T+0:如果是为了模拟“底仓 T+0”(即持有昨仓,今日先买入再卖出昨仓,或先卖出昨仓再买回),不需要开启
set_option("t0_mode", True)。系统默认的 T+1 规则允许卖出昨仓,只要保证卖出的数量不超过昨仓数量即可。 - 撮合逻辑:开启 T+0 后,回测引擎在处理卖单时,不会检查持仓的可用数量(
closeable_amount),而是直接检查总持仓量(total_amount)。
Q&A
Q: 开启 t0_mode 后,对可转债或 ETF 有影响吗?
A: 可转债和部分 ETF 本身在交易所规则下就是 T+0 的。在聚宽回测中,即使不开启此选项,系统通常也会根据标的类型自动适配其交易规则。但开启 t0_mode 会强制所有标的(包括普通股票)都支持 T+0。
Q: 我想做“底仓 T+0”策略,需要开启这个选项吗?
A: 不需要。底仓 T+0 是利用昨日持有的股票(昨仓)进行卖出,这符合 T+1 规则。只要您的策略逻辑是“卖出昨仓,买入新仓”或者“买入新仓,卖出昨仓(前提是账户里有昨仓)”,默认设置即可支持。
Q: 为什么我在 initialize 中设置了 T+0,但回测还是提示可用持仓不足?
A: 请检查是否正确调用了 set_option("t0_mode", True)。另外,确保您卖出的数量没有超过当日买入的总数量。如果卖出时确实持有股票但仍报错,请检查是否在其他地方(如 before_trading_start)重置了配置或代码逻辑有误。