问题描述
/
解决方案
在 ptrade 量化交易平台中,实盘或模拟盘运行过程中可能会遇到服务器重启、券商环境升级等情况。此时,策略进程会被重新拉起,保存在普通内存中的局部变量或未做特殊处理的全局变量将会全部丢失。为了保证交易逻辑的连贯性(例如记录持仓天数、特定状态标志等),必须进行持久化处理。
ptrade 提供了两种主要的持久化解决方案:
方法一:利用框架自带的全局对象 g 自动持久化
ptrade 框架内置了对全局对象 g 的自动持久化机制。框架会在特定的事件函数执行完毕后,自动将 g 中的变量序列化保存到磁盘中。
自动保存时机:
框架会在 before_trading_start(盘前)、handle_data(盘中)、after_trading_end(盘后)事件执行后触发持久化信息更新及保存操作。
恢复机制:
环境重启恢复交易时,框架会先执行策略的 initialize 函数,然后再执行持久化信息恢复操作。这意味着,如果持久化信息中保存了 g.flag,它会覆盖掉 initialize 中初始化的 g.flag,从而恢复到重启前的状态。
注意事项(非常重要):
- 不可序列化的对象:涉及到 IO(如打开的文件)、实例化的类对象等不能被序列化,强行保存会导致报错或持久化失败。
- 私有变量跳过保存:如果
g中有不需要或不能被序列化的变量,可以在initialize中以__(双下划线)开头命名(如g.__test_class),框架在持久化时会自动跳过这些私有变量。
方法二:使用 pickle 模块自定义文件持久化(推荐)
对于更复杂的数据结构,或者为了更精确地控制保存时机,建议使用 Python 标准库 pickle 结合 ptrade 的 get_research_path() 自行读写文件。
代码示例:记录股票持仓天数
import pickle
from collections import defaultdict
# 获取研究路径,用于存放持久化文件
NOTEBOOK_PATH = get_research_path()
def initialize(context):
# 尝试读取本地的 pickle 文件恢复数据
try:
with open(NOTEBOOK_PATH + 'hold_days.pkl', 'rb') as f:
g.hold_days = pickle.load(f)
log.info("成功恢复持仓天数数据")
except Exception as e:
# 如果文件不存在或读取失败,则初始化为空字典
g.hold_days = defaultdict(list)
log.info("初始化新的持仓天数数据")
g.security = '600570.SS'
set_universe(g.security)
# 每天盘前仓龄增加一天
def before_trading_start(context, data):
if g.hold_days:
g.hold_days[g.security] += 1
def handle_data(context, data):
# 买入逻辑
if g.security not in list(context.portfolio.positions.keys()) and g.security not in g.hold_days:
order(g.security, 100)
g.hold_days[g.security] = 1
# 卖出逻辑:持仓大于5天卖出
if g.hold_days:
if g.hold_days[g.security] > 5:
order(g.security, -100)
del g.hold_days[g.security]
# 每天/每分钟逻辑执行完后,将存储仓龄的字典对象进行 pickle 保存
with open(NOTEBOOK_PATH + 'hold_days.pkl', 'wb') as f:
pickle.dump(g.hold_days, f, -1)
总结
- 简单变量:直接挂载到
g对象上,依赖 ptrade 框架的自动持久化机制。 - 复杂对象/不可序列化对象:使用
g.__xxx命名避免被框架误处理。 - 高可靠性需求:使用
pickle模块手动将关键状态写入get_research_path()目录下的文件中,在initialize中通过try...except块进行读取恢复。