问题描述
g只能在初始化下面定义吗
解决方案
1. 盘前函数(before_trading_start)下面定义的变量是全局变量吗?
不是的。
在 before_trading_start(或其他任何函数如 handle_data)中直接定义的普通变量(例如 a = 1 或 my_list = []),属于局部变量。它们的作用域仅限于该函数内部,函数执行完毕后就会被销毁,无法在 handle_data 等其他函数中被调用。
如果你希望在盘前函数中定义的变量能够在盘中(handle_data)被访问,你必须将它挂载到全局对象 g 上,例如:g.my_list = []。
2. 全局对象 g 只能在初始化(initialize)下面定义吗?
不是的。
全局对象 g 的属性可以在策略的任何生命周期函数中(包括 initialize、before_trading_start、handle_data、tick_data 等)进行定义、修改或删除。
例如,在官方文档的示例中,经常在 handle_data 中动态修改 g 的属性:
def initialize(context):
g.security = '600570.SS'
g.flag = False # 在初始化中定义
def handle_data(context, data):
if not g.flag:
order(g.security, 1000)
g.flag = True # 在盘中函数中修改
⚠️ 核心注意事项(关于持久化与重启)
虽然 g 可以在任何地方定义,但在实际编写 ptrade 策略时,强烈建议将基础的全局变量初始化放在 initialize 中,原因如下:
- 持久化机制:ptrade 框架会在
before_trading_start、handle_data、after_trading_end事件后自动将g对象中的变量进行持久化保存(序列化)。 - 重启恢复逻辑:当券商服务器升级或环境重启拉起交易时,框架会先执行
initialize函数,然后再执行持久化信息恢复操作。这意味着持久化数据会覆盖initialize中的初始值,从而保证策略状态的连贯性。 - 避免在盘前函数中误覆盖:如果你在
before_trading_start中无条件地写了g.my_status = 0,那么一旦服务器在盘中重启(重启时默认会再次调用before_trading_start),你之前在盘中辛苦计算并持久化保存的g.my_status就会被无情地重置为 0,导致策略逻辑彻底错乱。
总结:
- 普通变量在函数内是局部的。
- 跨函数传值必须用
g.xxx。 g.xxx可以在任何地方赋值,但为了防止服务器重启导致状态丢失,初始赋值请尽量放在initialize中,并在其他函数中按需修改。