问题描述
利用create_backtest创建回测,原回测中有内置的g.security,我想通过create_backtest改变是否可能?我将新的代码放入extra_vars字典中,无法获得回测结果,gt.get_results()结果为空。
是否create_backtest必须与原代码中的g.security一致?
研究代码为:
设定初始仓位
InitialPositions = [
{
'security': '000009.XSHE',
'amount': '1000', # 100股
}
]
设定g.全局变量的值
extra_vars = {'security': '000009.XSHE','ma_long': 5, 'm': 1.01}
create_backtest('','2015-01-01', '2016-06-01', \
frequency="day",initial_cash=100000, initial_positions=InitialPositions, extras=extra_vars)
gt = get_backtest(out_algorithm_id)
gt.get_results()
解决方案
结论
可以改变。 通过 create_backtest 的 extras 参数,完全可以动态改变原策略代码中的 g.security 数值,不需要与原代码中的 g.security 保持一致。
根据 JoinQuant API 文档说明:
extras: 额外参数,一个 dict, 用于设置全局的 g 变量,如extras={'x':1, 'y':2},则回测中g.x = 1,g.y = 2。需要注意的是,该参数的值是在initialize函数执行之后才设置给 g 变量的,所以这会覆盖掉initialize函数中 g 变量同名属性的值。
为什么你的 gt.get_results() 结果为空?
你的思路是正确的,但代码实现上存在几个常见的错误,导致回测未能成功运行或未能正确获取结果。请排查以下几点:
1. create_backtest 的第一个参数 algorithm_id 为空
在你的代码中:create_backtest('','2015-01-01', ...),第一个参数传入了空字符串 ''。这是无效的。
- 如果你想运行已保存在“我的策略”中的代码,必须传入正确的
algorithm_id(从策略编辑页的 URL 中获取)。 - 如果你想直接在研究中以字符串形式传入策略代码,应该使用
code参数,例如:create_backtest(code=my_strategy_code, start_date=...)。
2. 获取回测对象的 ID 错误
create_backtest 函数执行后会返回一个 backtest_id(字符串类型),你需要用这个返回的 ID 去调用 get_backtest()。
你的代码中写的是 gt = get_backtest(out_algorithm_id),这里的变量名暗示你可能混淆了 algorithm_id(策略源码ID)和 backtest_id(本次回测运行的ID)。
3. 回测是异步执行的,未等待运行结束
create_backtest 提交回测任务后,后台需要时间运行。如果你紧接着立刻调用 gt.get_results(),此时回测大概率还在 running 状态,结果自然为空。
你需要通过 gt.get_status() 循环检查状态,直到状态变为 done 后,再去获取结果。
4. initialize 中的逻辑依赖问题(进阶排查)
由于 extras 的覆盖发生在 initialize 之后,如果你的原策略在 initialize 中使用了 g.security 进行了某些不可逆的初始化操作(例如:set_universe([g.security]),或者在 Tick 级回测中 subscribe(g.security, 'tick')),那么这些操作使用的依然是原代码里的旧值。只有在 handle_data 或定时运行函数中,g.security 才会表现为 extras 传入的新值。
正确的代码示例
以下是一个在研究环境中正确使用 create_backtest 修改 g.security 并获取结果的完整示例:
import time
from jqdata import *
# 1. 设定初始仓位和额外参数
InitialPositions = [
{
'security': '000009.XSHE',
'amount': '1000', # 1000股
}
]
extra_vars = {'security': '000009.XSHE', 'ma_long': 5, 'm': 1.01}
# 2. 假设你的策略 ID 是 'xxxxxx' (请替换为真实的 algorithm_id)
algorithm_id = 'xxxxxx'
# 3. 创建回测,注意接收返回的 backtest_id
backtest_id = create_backtest(
algorithm_id=algorithm_id,
start_date='2015-01-01',
end_date='2016-06-01',
frequency="day",
initial_cash=100000,
initial_positions=InitialPositions,
extras=extra_vars
)
print("回测已创建,ID为:", backtest_id)
# 4. 获取回测对象
gt = get_backtest(backtest_id)
# 5. 循环等待回测完成
while True:
status = gt.get_status()
print("当前回测状态:", status)
if status == 'done':
print("回测完成!")
break
elif status in ['failed', 'canceled', 'deleted']:
print("回测异常终止!")
break
time.sleep(5) # 每5秒检查一次
# 6. 获取并打印结果
if gt.get_status() == 'done':
results = gt.get_results()
if results:
print("获取到结果,共 %d 个交易日的数据" % len(results))
# 打印最后一天的数据示例
print("最后一天收益情况:", results[-1])
else:
print("回测已完成,但结果为空,请检查策略逻辑是否产生交易。")