问题描述
解决方案
在 PTrade 策略开发中,在不同函数(如 initialize、handle_data、before_trading_start 等)之间共享和传递变量,主要通过 全局对象 g 来实现。
核心机制:全局对象 g
g 是 PTrade 策略引擎提供的一个特殊的全局容器对象。它的主要特点如下:
- 全局可访问:在策略的任何函数中都可以访问和修改
g中的属性。 - 自动持久化:
g对象中的变量(除非以__开头)会被系统自动保存(Pickle序列化)。这意味着即使策略暂停、服务器重启或隔日运行,g中的数据依然会被保留,保证策略逻辑的连续性。
使用方法
通常的流程是:
- 在
initialize函数中初始化变量。 - 在
handle_data或其他函数中读取或修改这些变量。
代码示例
以下是一个完整的策略示例,展示了如何使用 g 记录交易天数和控制买卖状态:
def initialize(context):
"""
初始化函数,设置全局变量
"""
# 1. 初始化股票池
g.security = '600570.SS'
set_universe(g.security)
# 2. 定义全局变量 g.count,用于记录运行次数
g.count = 0
# 3. 定义全局变量 g.has_bought,用于记录是否已买入
g.has_bought = False
log.info("策略初始化完成,全局变量已设置")
def before_trading_start(context, data):
"""
盘前处理函数
"""
# 读取全局变量
log.info("盘前检查:当前运行次数为 %s" % g.count)
def handle_data(context, data):
"""
盘中运行函数
"""
# 修改全局变量:计数器加1
g.count += 1
# 读取并使用全局变量进行逻辑判断
if not g.has_bought:
log.info("第 %s 次运行,执行买入操作" % g.count)
order(g.security, 100)
# 修改状态标记
g.has_bought = True
else:
log.info("第 %s 次运行,已持仓,跳过买入" % g.count)
def after_trading_end(context, data):
"""
盘后处理函数
"""
log.info("盘后总结:今日共运行了 handle_data %s 次" % g.count)
关键注意事项
-
持久化限制:
g中的变量会被系统使用pickle模块序列化保存。因此,不能将无法序列化的对象(如打开的文件句柄、数据库连接对象、套接字等)赋值给g的普通属性,否则会导致策略保存失败或重启报错。- 如果必须使用无法序列化的对象(例如在
initialize中实例化的某个复杂类),可以将变量名命名为以 双下划线开头(如g.__my_class)。以__开头的变量被视为私有变量,不会被持久化保存,重启后需要重新初始化。
-
命名冲突:
- 建议不要使用过于通用的名称(如
g.data),以免与系统未来可能保留的关键字冲突。建议使用具有业务含义的名称,如g.buy_signal_date。
- 建议不要使用过于通用的名称(如
-
重启后的行为:
- 当实盘或模拟盘服务器重启恢复交易时,框架会先执行
initialize,然后恢复持久化数据。如果持久化数据中已经存在g.xxx,它会覆盖initialize中重新赋值的g.xxx,从而保证策略记忆不丢失。
- 当实盘或模拟盘服务器重启恢复交易时,框架会先执行
Q&A
Q: 为什么不能直接使用 Python 的 global 关键字定义全局变量?
A: 虽然在 Python 脚本中可以使用 global 关键字,但在量化交易平台中,普通的 Python 全局变量无法在服务器重启或策略暂停恢复后自动保存(持久化)。一旦策略进程重启,普通全局变量会重置,导致策略逻辑(如持仓天数、止损标记)丢失。使用 PTrade 提供的 g 对象可以确保数据安全地跨日、跨重启保存。
Q: g 对象能存储 Pandas 的 DataFrame 吗?
A: 可以。Pandas 的 DataFrame 和 Series 是可以被序列化(Pickle)的,因此可以安全地存储在 g 对象中。这在需要记录历史计算结果或自定义因子的场景中非常有用。
Q: 如果我在 initialize 中设置了 g.a = 1,策略运行几天后 g.a 变成了 10,此时重启策略,g.a 是多少?
A: 是 10。PTrade 的机制是:重启时先运行 initialize(将 g.a 设为 1),随后系统会立即加载之前保存的持久化文件,用保存的值(10)覆盖掉 initialize 中的值。因此,最终 g.a 会恢复为 10,保证策略逻辑连贯。