3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 JoinQuant(聚宽)量化交易平台中,模拟盘进程会在每天收盘后休眠,并在下一个交易日重新启动恢复。为了保证模拟盘在重启后能维持原有的运行状态,平台会通过 pickle 序列化机制自动保存全局变量对象 g 和上下文对象 context。然而,涉及 IO、数据库连接以及 SQLAlchemy query 对象等无法被 pickle 序列化,直接赋值给 g 会导致重启失败或抛出 AttributeError 异常。
g 和 context 对象。after_code_changed:如果策略代码在重启前有修改,且定义了该函数,则会被执行。process_initialize:每次进程启动/重启时都会执行该函数。initialize:initialize 在模拟盘的整个生命周期中仅执行一次,重启时不会再次运行。g:默认会被 pickle 序列化保存。__ 开头的变量(如 g.__my_var)在序列化时会被系统忽略,不会被持久化。query(valuation) 等数据库连接/查询对象open("file_path") 文件打开句柄requests.get(...) 等网络连接对象如果将不可序列化的对象赋值给普通 g 变量(例如在 initialize 中设置 g.query = query(...)),重启时会因无法序列化或丢失连接而引发错误。
process_initialize 与私有变量正确的做法是将不可序列化的对象命名为以双下划线 __ 开头的变量,并在 process_initialize(context) 函数中进行初始化。
import jqdata
def initialize(context):
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设定基准
set_benchmark('000300.XSHG')
# 普通全局变量,会被 pickle 保存
g.security = '000001.XSHE'
# 定时运行策略
run_daily(market_open, time='09:30')
def process_initialize(context):
# 每次模拟盘进程启动/重启时都会运行此函数
# query 对象无法被 pickle 序列化,因此使用双下划线开头变量 g.__q 存储
# 这样系统在序列化 g 对象时会忽略该变量,避免重启报错
g.__q = query(valuation.code, valuation.market_cap, valuation.pe_ratio).filter(
valuation.pe_ratio < 15
)
def market_open(context):
# 在盘中调用 process_initialize 中初始化的 query 对象
df = get_fundamentals(g.__q)
log.info("获取到的低市盈率股票数量:%d" % len(df))
__(双下划线)开头,例如 g.__query。g 对象序列化后的总大小不能超过 30M。当超过 20M 时日志中会有警告提示。切勿将大型的 DataFrame 数据直接存储在 g 对象中。context.portfolio 或 position 等平台内置对象手动存入 g,因为账户信息是动态变化的,过度持久化容易导致状态混乱。process_initialize 来验证变量是否能够正确恢复。