🚀 AI 一键生成 ptrade 策略代码

PTrade 策略中断重启后,如何恢复 g 变量中的数据?

ptrade | 发布时间: 2025/11/25
以下内容由 EasyQuant 生成。

问题描述

我的策略里有一些需要长期跟踪的变量,如果程序重启了这些变量就丢失了,有什么办法可以把它们保存下来,下次启动时自动加载吗?

解决方案

在PTrade中,确实存在程序重启导致内存中变量丢失的问题。为了解决这个问题,PTrade 提供了持久化机制

最推荐且稳健的方法是利用 Python 的 pickle 模块,将需要长期跟踪的变量保存到研究目录(Research Path)下的文件中。

实现原理

  1. 保存(Dump): 在策略运行过程中(如 after_trading_endhandle_data),将关键变量写入文件。
  2. 加载(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)

注意事项

  1. 文件路径:必须使用 get_research_path() 获取路径,不要使用绝对路径或 import os 操作文件系统,因为 PTrade 对文件权限有严格限制。
  2. 序列化限制pickle 只能保存可序列化的 Python 对象(如字典、列表、字符串、数字等)。不要尝试保存 PTrade 的特殊对象(如 contextOrder 对象、SecurityUnitData 等),这会导致报错。如果需要保存这些对象的信息,请提取出其中的关键数据(如订单号字符串、价格数值)存入字典后再保存。
  3. 自动持久化机制:PTrade 框架本身也会尝试自动保存 g 对象中的变量。但在实盘中,为了确保数据绝对安全且逻辑可控(例如明确知道何时读取、何时写入),使用上述手动 pickle 的方式是最保险的。
  4. 私有变量:如果你定义了以双下划线 __ 开头的变量(如 g.__private_var),框架的自动持久化会忽略它,但使用上述手动 pickle 方法可以正常保存,只要它是可序列化的。