🚀 AI 一键生成 ptrade 策略代码
立即体验
👉 AI 生成代码 👈

ptrade 策略重启导致重复建仓怎么办?(附持久化处理源码)

ptrade | 发布时间: 2026/5/29
以下内容由 EasyQuant 生成。

问题描述

策略重启后"失忆"般重新初始化,导致重复建仓或错误平仓怎么办?

/

解决方案

问题分析

在 ptrade 实盘或模拟盘运行中,如果遇到券商服务器升级或环境重启,系统会重新拉起交易并再次执行 initialize 函数。如果策略的状态(如是否已建仓的标志位、持仓天数等)仅保存在内存中的全局变量 g 里,重启后这些变量会被重置,从而导致策略“失忆”,引发重复建仓或错误的平仓逻辑。

解决方案

要解决这个问题,需要从数据持久化平台参数配置两个方面入手:

1. 使用 pickle 进行变量持久化

ptrade 提供了 get_research_path() 接口,可以将需要记忆的变量通过 Python 的 pickle 模块序列化保存到本地文件中。每次 initialize 时先尝试读取该文件,如果读取失败再进行初始化;在状态发生改变时(如 handle_dataafter_trading_end 中)将最新状态写回文件。

2. 配置 set_parameters 防止重复执行

initialize 中使用 set_parameters 函数,设置 not_restart_trade="1"server_restart_not_do_before="1",可以有效防止交易时间段服务器重启导致的重复拉起和 before_trading_start 的重复执行。

3. 增加持仓与订单校验

在执行买卖操作前,务必通过 get_position()get_open_orders() 检查当前真实的账户持仓和未成交订单,不要仅依赖自定义的标志位。

完整代码示例

以下是一个结合了持久化和防重启配置的完整策略模板:

import pickle
import os

def initialize(context):
    g.security = '600570.SS'
    set_universe(g.security)
    
    # 1. 设置防重启参数,防止盘中重启导致重复执行
    set_parameters(not_restart_trade="1", server_restart_not_do_before="1")
    
    # 2. 定义持久化文件路径
    g.save_path = get_research_path() + 'strategy_state.pkl'
    
    # 3. 尝试加载历史状态
    if os.path.exists(g.save_path):
        try:
            with open(g.save_path, 'rb') as f:
                g.state = pickle.load(f)
                log.info("成功加载持久化状态: %s" % g.state)
        except Exception as e:
            log.error("加载持久化文件失败: %s" % e)
            g.state = {'has_bought': False, 'hold_days': 0}
    else:
        # 如果没有文件,说明是首次运行
        g.state = {'has_bought': False, 'hold_days': 0}

def handle_data(context, data):
    security = g.security
    current_price = data[security]['close']
    
    # 获取真实持仓,双重校验
    pos = get_position(security)
    
    # 建仓逻辑:如果没有买过,且满足条件
    if not g.state['has_bought'] and pos.amount == 0:
        order(security, 100)
        g.state['has_bought'] = True
        g.state['hold_days'] = 1
        save_state() # 状态改变,立即落地保存
        log.info("建仓成功,状态已保存")
        
    # 平仓逻辑:如果持仓天数大于5天
    elif pos.amount > 0 and g.state['hold_days'] > 5:
        order_target(security, 0)
        g.state['has_bought'] = False
        g.state['hold_days'] = 0
        save_state() # 状态改变,立即落地保存
        log.info("平仓成功,状态已重置")

def before_trading_start(context, data):
    # 每天更新持仓天数
    if g.state['has_bought']:
        g.state['hold_days'] += 1
        save_state()

def save_state():
    # 封装保存状态的函数
    try:
        with open(g.save_path, 'wb') as f:
            pickle.dump(g.state, f, -1)
    except Exception as e:
        log.error("保存持久化文件失败: %s" % e)

注意事项

  1. 不可序列化的对象:涉及到 IO(如打开的文件、数据库连接)或某些实例化的类对象是不能被 pickle 序列化的。如果 g 中有这些变量,请在变量名前加双下划线(如 g.__db_conn),这样框架在默认持久化时会跳过它们。
  2. 真实数据优先:无论持久化做得多好,实盘中永远应该以 get_position()get_trades() 返回的真实账户数据为准,持久化变量仅作为辅助逻辑判断。