问题描述
我的策略里有一些需要长期跟踪的变量,如果程序重启了这些变量就丢失了,有什么办法可以把它们保存下来,下次启动时自动加载吗?
解决方案
在PTrade中,确实存在程序重启导致内存中变量丢失的问题。为了解决这个问题,PTrade 提供了持久化机制。
最推荐且稳健的方法是利用 Python 的 pickle 模块,将需要长期跟踪的变量保存到研究目录(Research Path)下的文件中。
实现原理
- 保存(Dump): 在策略运行过程中(如
after_trading_end或handle_data),将关键变量写入文件。 - 加载(Load): 在策略初始化(
initialize)阶段,尝试读取该文件。如果文件存在,则恢复变量;如果不存在(第一次运行),则初始化为默认值。
代码实现
以下是一个完整的示例代码,展示了如何保存一个名为 g.my_data 的字典变量(例如记录股票的持仓天数或累计收益等):
import pickle
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 获取研究目录路径,用于存放持久化文件
# 注意:文件名建议加上策略特有的标识,避免不同策略混淆
g.file_path = get_research_path() + 'my_strategy_data.pkl'
# --- 关键步骤:尝试加载数据 ---
try:
with open(g.file_path, 'rb') as f:
# 如果文件存在,读取并赋值给全局变量
g.my_data = pickle.load(f)
log.info("成功加载持久化数据: %s" % g.my_data)
except:
# 如果文件不存在(首次运行)或读取出错,初始化默认值
log.info("未找到持久化文件或读取失败,初始化默认值")
g.my_data = {'count': 0, 'trade_records': []}
def handle_data(context, data):
# 示例:在盘中修改变量
g.my_data['count'] += 1
# 如果数据非常重要,可以在修改后立即保存(注意频繁IO可能会影响回测速度,实盘通常没问题)
# save_data()
def after_trading_end(context, data):
# 示例:每天收盘后保存一次数据
g.my_data['trade_records'].append(str(context.blotter.current_dt))
# 执行保存操作
save_data()
log.info("盘后数据已保存: %s" % g.my_data)
# 定义一个辅助函数用于保存数据
def save_data():
try:
with open(g.file_path, 'wb') as f:
# 将 g.my_data 写入文件
pickle.dump(g.my_data, f, -1)
except Exception as e:
log.error("数据保存失败: %s" % e)
注意事项
- 文件路径:必须使用
get_research_path()获取路径,不要使用绝对路径或import os操作文件系统,因为 PTrade 对文件权限有严格限制。 - 序列化限制:
pickle只能保存可序列化的 Python 对象(如字典、列表、字符串、数字等)。不要尝试保存 PTrade 的特殊对象(如context、Order对象、SecurityUnitData等),这会导致报错。如果需要保存这些对象的信息,请提取出其中的关键数据(如订单号字符串、价格数值)存入字典后再保存。 - 自动持久化机制:PTrade 框架本身也会尝试自动保存
g对象中的变量。但在实盘中,为了确保数据绝对安全且逻辑可控(例如明确知道何时读取、何时写入),使用上述手动pickle的方式是最保险的。 - 私有变量:如果你定义了以双下划线
__开头的变量(如g.__private_var),框架的自动持久化会忽略它,但使用上述手动pickle方法可以正常保存,只要它是可序列化的。