问题描述
/
解决方案
在ptrade量化交易平台中,如果遇到突然断电、服务器重启或券商环境升级等意外情况,可能会导致策略运行中断,内存中的变量(如持仓天数、自定义状态标记等)丢失。为了解决这个问题,ptrade提供了完善的持久化机制。以下是具体的解决步骤和代码示例:
1. 利用框架自带的全局变量 g 持久化
ptrade框架会自动使用 pickle 模块保存全局变量 g 中定义的变量。框架会在 before_trading_start、handle_data、after_trading_end 事件后触发持久化信息更新及保存操作。
当环境重启恢复交易时,框架会先执行策略的 initialize 函数,然后再执行持久化信息恢复操作。注意:持久化信息中的变量会覆盖掉 initialize 函数中初始化的同名变量。
2. 自定义 Pickle 文件进行持久化(推荐)
对于复杂的策略状态(如字典、列表等),建议在策略中显式地使用 pickle 模块将状态保存到本地文件中。这样即使重启,也能在 initialize 中安全地读取恢复。
代码示例:
import pickle
from collections import defaultdict
# 获取研究路径作为保存目录
NOTEBOOK_PATH = get_research_path()
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 尝试读取本地的 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("未找到历史状态,初始化新状态。")
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
# 每天将状态对象进行 pickle 保存,防止盘中断电丢失
with open(NOTEBOOK_PATH + 'hold_days.pkl', 'wb') as f:
pickle.dump(g.hold_days, f, -1)
3. 处理无法序列化的对象
全局变量 g 中不能被序列化的变量(如涉及到IO的打开文件、实例化的类对象等)将不会被保存,这会导致持久化失败。如果您必须在 g 中保存这些对象,请在变量名前加上双下划线 __,将其声明为私有变量,框架在持久化时会跳过它们。
class Test(object):
pass
def initialize(context):
# 初始化无法被序列化的类对象,并赋值为私有变量,落地持久化信息时跳过保存该变量
g.__test_class = Test()
4. 配置重启参数避免重复执行
服务器重启拉起交易时,initialize 和 before_trading_start 函数可能会被重复调用。为了避免重复委托或变量被错误重置,可以在 initialize 中使用 set_parameters 进行安全配置:
def initialize(context):
# not_restart_trade="1": 交易时间段若服务器重启,不自动执行重新拉起本交易
# server_restart_not_do_before="1": 若服务器重启导致重拉交易,不重复执行 before_trading_start 函数
set_parameters(not_restart_trade="1", server_restart_not_do_before="1")
通过以上方法,您可以有效避免因断电或重启导致的策略状态丢失,确保实盘交易的稳定性和连续性。