问题描述
各位前辈们双节快乐~我是一名刚接触量化的新人。
最近写了一个商品期货的策略,打算在30分钟周期进行日内交易,
我遇到的问题是:行情数据获取、运行频率,都写了every_bar,但回测时依旧是:只在每个交易日的9:30进行买卖。
想请问:如何在盘中实时更新并获取30分钟的数据?
谢谢!
解决方案
你好!欢迎来到量化交易的世界。针对你在JoinQuant(聚宽)平台上写商品期货30分钟周期策略遇到的问题,主要原因通常出在回测频率设置和期货参考标的设置上。下面为你详细解答如何解决这个问题并获取30分钟数据。
问题诊断:为什么 every_bar 只在9:30交易?
- 回测频率选错了:
run_daily(func, time='every_bar')的执行频率取决于你在回测界面右上角选择的“运行频率”。如果你选择了“天”,那么它每天只会在开盘(通常是9:30)执行一次。必须在回测界面将频率选择为“分钟”。 - 期货的参考标的(reference_security)未设置:默认情况下,
run_daily的时间参照是A股(000001.XSHG),交易时间是9:30-15:00。商品期货有夜盘(如21:00开盘),如果不修改参考标的,引擎会按照A股的时间来跑,导致时间错乱。对于期货策略,必须将reference_security设置为对应的期货主力合约。
解决方案:如何实时获取30分钟数据并进行日内交易
要实现30分钟周期的日内交易,推荐的做法是:按分钟频率回测,并在代码中通过时间判断或直接使用 get_bars 获取30分钟K线数据。
1. 正确的初始化与频率设置
在 initialize 中,设置期货账户,并正确注册定时运行函数。
# 导入聚宽函数库
import jqdata
def initialize(context):
# 设定基准(期货策略可以不设或设为0)
set_benchmark({'000001.XSHG': 0})
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设置期货账户
init_cash = context.portfolio.starting_cash
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
# 定义要交易的期货品种主力合约,例如螺纹钢
g.security = 'RB9999.XSGE'
# 注册运行函数,注意 reference_security 必须设置为期货合约!
# 这样才能兼容期货的夜盘时间
run_daily(market_open, time='every_bar', reference_security=g.security)
2. 获取30分钟数据
在 market_open(每分钟执行一次)中,你可以使用 get_bars 函数直接获取30分钟级别的K线数据。为了确保只在每30分钟的节点触发交易逻辑,可以通过判断当前分钟数来实现。
def market_open(context):
# 获取当前时间
current_dt = context.current_dt
# 控制交易频率:每30分钟执行一次逻辑(例如 00分 和 30分)
# 注意:期货开盘时间可能是 09:00 或 21:00,具体视品种而定
if current_dt.minute % 30 != 0:
return
# 获取具体的交易合约(将主力合约映射为实际合约,如 RB1910.XSGE)
real_contract = get_dominant_future(g.security, current_dt)
if not real_contract:
return
# 获取过去5根30分钟K线数据
# unit='30m' 表示30分钟周期,include_now=False 表示不包含当前未走完的这根Bar
bars = get_bars(real_contract, count=5, unit='30m',
fields=['date', 'open', 'close', 'high', 'low', 'volume'],
include_now=False, df=True)
if len(bars) < 5:
return
# 计算指标,例如简单的均线
close_prices = bars['close']
ma5 = close_prices.mean()
current_price = close_prices.iloc[-1]
# 获取当前持仓
long_position = context.portfolio.long_positions.get(real_contract)
short_position = context.portfolio.short_positions.get(real_contract)
# 简单的交易逻辑示例:价格突破均线做多
if current_price > ma5 and not long_position:
# 如果有空单,先平空
if short_position:
order_target(real_contract, 0, side='short')
# 开多单 1 手
order(real_contract, 1, side='long')
log.info(f"买入开多 {real_contract}")
elif current_price < ma5 and not short_position:
# 如果有多单,先平多
if long_position:
order_target(real_contract, 0, side='long')
# 开空单 1 手
order(real_contract, 1, side='short')
log.info(f"卖出开空 {real_contract}")
总结与注意事项
- 回测界面设置:一定要在网页右上角把“运行频率”选为分钟。
- 参考标的(reference_security):期货策略的
run_daily必须带上reference_security='你的期货代码',否则夜盘不会执行。 - 数据获取:使用
get_bars(..., unit='30m')是获取分钟以上级别(如30m, 60m)最标准的方法,它会自动按照主流软件的切分方式为你合成30分钟K线。 - 主力合约映射:下单和获取数据时,尽量使用
get_dominant_future将8888或9999映射为真实的合约代码(如RB2310.XSGE),因为直接对9999下单会报错。
祝你在量化交易的道路上越走越远,双节快乐!