3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
针对您在 JoinQuant 模拟交易中遇到的内存溢出、进程被杀以及 get_bars 内存泄漏问题,以下是详细的解答和优化方案:
原因分析:模拟盘的状态保存与序列化机制
在 JoinQuant 的模拟交易中,每天的交易逻辑运行结束后,进程并不会立即退出,而是会进入状态保存阶段(相当于休眠)。系统会使用 pickle 将您的用户账户、持仓信息以及全局变量 g 对象序列化并保存到磁盘,以便第二天恢复。
g 对象中存储了大量的数据(例如缓存了大量的 DataFrame、历史行情数据等),在执行 pickle.dumps 序列化时,会瞬间消耗大量的内存。解决方案:
after_trading_end 中,将 g 中不需要跨日保存的大型数据清理掉(如 g.history_data = None)。__ 开头(例如 g.__temp_data),系统在序列化时会自动忽略这些变量。原因分析:系统的容错与恢复机制
当模拟盘进程因为内存超限或其他异常被系统强制杀掉后,JoinQuant 的底层调度系统会检测到任务失败,并尝试进行自动重试/恢复。
context.current_dt)会回退到崩溃前的时间点(例如 9:49:33),重新执行未完成的逻辑。get_bars 内存释放不掉(内存泄漏)怎么办?原因分析:底层缓存机制与循环调用
get_bars、get_price 等 API 获取的数据会被缓存在内存中,因此使用 del 和 gc.collect() 是无法释放这部分内存的。for 循环中对 2400 只股票逐一调用 get_bars,这不仅会产生大量的缓存对象,还会带来极大的网络和函数调用开销,导致内存迅速膨胀和运行缓慢。解决方案:
方案 A:关闭系统缓存(治标)
如果您确实不需要缓存,可以在 initialize 函数中调用 disable_cache() 来关闭缓存机制。这样获取的数据在使用完毕后就可以被正常回收。
def initialize(context):
disable_cache() # 关闭缓存机制,防止内存占用过大
注意:关闭缓存会导致策略运行速度明显下降。
方案 B:批量获取数据(治本,强烈推荐)
get_bars 和 get_price 等 API 都是支持传入股票列表进行批量获取的。您完全不需要使用 for 循环单只获取,一次性获取 2400 只股票的数据不仅内存占用更集中、更易管理,而且运行速度会提升数十倍。
优化后的代码示例:
# security 是包含 2400 只股票的 list
# 直接传入 list,df=False 返回 dict (key为股票代码,value为 numpy.ndarray)
# df=True 返回 MultiIndex 的 DataFrame
today_data = get_bars(security, count=229, unit='1d',
fields=['open','close','high','low','volume','money'],
include_now=True, df=False)
# 随后您可以直接从字典中提取单只股票的数据进行处理
for stock in security:
stock_data = today_data.get(stock)
if stock_data is not None:
# 进行您的逻辑计算
pass
# 处理完毕后,清理大对象
today_data = None
总结建议:
g 对象中的庞大缓存数据,避免序列化时爆内存。for 循环中单只股票调用数据 API,改用传入 list 批量获取。initialize 中加入 disable_cache()。