3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在聚宽(JoinQuant)平台上,策略因内存占用过大而失败通常是因为回测过程中缓存了过多的历史数据、全局变量(g对象)存储了过大的DataFrame,或者未及时释放不再使用的对象。
以下是针对聚宽平台的具体优化方法和建议:
聚宽系统默认会开启缓存以加快回测速度,但这会消耗大量内存。如果你的策略逻辑复杂或涉及大量标的,建议在 initialize 中显式关闭缓存。
disable_cache()g 的使用g 对象中的变量会被持久化(序列化),且在模拟盘中每次重启都会恢复。
g 中存储巨大的 DataFrame 或 List:例如,不要把几千只股票过去一年的行情数据存到 g.history_data 中。handle_data 或定时函数中即取即用,用完即弃。g 中某些数据只在盘前使用,用完后可以使用 del g.variable 手动删除。df=False:在调用 history 或 attribute_history 时,如果不需要 pandas DataFrame 的高级功能,可以将参数设置为 df=False。返回的 dict 或 numpy.ndarray 比 DataFrame 占用内存小得多。initialize 里一次性取全市场股票的行情,而是在需要计算信号时,分批次或只针对特定股票池获取。Python 的垃圾回收机制有时会有延迟。对于内存敏感的策略,可以在每天收盘后手动强制回收内存。
list.append() 或 dict 赋值操作在不断增加长度而从未清理(例如记录每一笔订单详情到全局列表中,回测时间一长就会爆内存)。record:不要在 record 中传入过大的数据结构,只记录必要的数值。下面是一个应用了上述优化技巧的代码框架:
# -*- coding: utf-8 -*-
import gc
def initialize(context):
# 1. 【关键】关闭缓存,牺牲速度换取内存空间
disable_cache()
# 设定基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 初始化全局变量,只存必要的小数据
g.security_pool = []
def before_trading_start(context):
# 每日更新股票池,避免长期存储大列表
g.security_pool = get_index_stocks('000300.XSHG')
def handle_data(context, data):
# 2. 【关键】数据即取即用,不要存入全局变量 g
# 3. 【关键】如果不需要DataFrame特性,使用 df=False 节省内存
# 获取过去5天的收盘价,返回的是 dict (key为股票代码, value为numpy数组)
hist_data = history(5, unit='1d', field='close', security_list=g.security_pool, df=False)
for stock in g.security_pool:
# 使用 numpy 数组进行计算,内存占用更低
prices = hist_data[stock]
if len(prices) > 0:
ma5 = prices.mean()
current_price = prices[-1]
# 简单的交易逻辑示例
if current_price > ma5:
order_target_value(stock, 10000)
elif current_price < ma5:
order_target(stock, 0)
def after_trading_end(context):
# 4. 【关键】每日收盘后手动强制垃圾回收
gc.collect()
print("今日交易结束,已执行内存回收")
如果遇到内存溢出(OOM),首先尝试在 initialize 中添加 disable_cache()。如果问题依旧,请检查代码逻辑,确保没有在 g 对象中通过循环不断累积数据(如 g.data_list.append(...)),并尝试在 after_trading_end 中加入 gc.collect()。
Q: disable_cache() 会让回测慢多少?
A: 这取决于策略获取数据的频率。如果策略频繁调用 history 或 get_price,关闭缓存后,每次调用都会重新从磁盘或数据库读取数据,速度可能会下降 30% 到 50% 甚至更多,但能有效避免内存崩溃。
Q: 为什么不能在 g 变量里存大的 DataFrame?
A: g 变量是为了持久化设计的,聚宽平台会定期将 g 序列化保存到磁盘。如果 g 过大(超过 30MB),不仅序列化会失败,而且在内存中长期驻留会导致可用内存迅速耗尽。
Q: df=False 返回的是什么数据类型?
A: 当设置 df=False 时,history 和 attribute_history 返回的是一个字典(Dict),Key 是股票代码,Value 是 numpy.ndarray。Numpy 数组比 Pandas DataFrame 更加轻量,内存效率更高。