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

JoinQuant聚宽模拟盘/实盘中g.__双下划线变量丢失问题解析与修复

joinquant | 发布时间: 2026/6/1
以下内容由 EasyQuant 生成。

问题描述

实盘不支持g.__这种变量吗?

回测没问题的。

def initialize(context):
--set_params()
--run_daily(sell, time='09:20')
--run_daily(trade, time='every_bar')

def set_params():
--g.__stock_ls = []

def sell(context):
--sell_list = list(context.portfolio.positions.keys())
--for stock_sell in sell_list:
----price = get_price(stock_sell, end_date=context.previous_date, fields=['close'], count=1)
----price = list(price['close'])[0]*0.91
----order_target_value(stock_sell, 0, LimitOrderStyle(price))
----g.__stock_ls = []

def trade(context):
---if len(g.__stock_ls) >= 3:
----return

解决方案

在 JoinQuant(聚宽)平台中,实盘(模拟交易)是支持 g.__ 这种以双下划线开头的变量的,但是它的运行机制与回测环境有所不同,这就是导致您在回测中正常,但在模拟盘中报错的原因。

问题原因分析

根据聚宽 API 文档的规定:

  1. 模拟盘的休眠与重启机制:模拟盘在每天运行结束后会保存状态并结束进程(相当于休眠),第二天开盘前会恢复状态。恢复时,系统会使用 pickle 序列化保存 g 对象和 context 对象。
  2. initialize 函数只执行一次:在模拟盘的整个生命周期中,initialize 函数只在创建模拟盘时执行一次,每天重启时不会再次执行。
  3. 双下划线变量被忽略:文档明确指出,g 中以 __ 开头的变量在序列化时将被忽略,不会被保存

您的代码发生的问题在于:
您在 initialize 中调用 set_params 初始化了 g.__stock_ls = []。在模拟盘第一天运行是正常的。但是第一天结束后,系统保存状态时忽略了 g.__stock_ls。第二天模拟盘重启时,initialize 不再执行,而 g.__stock_ls 又没有被保存下来,因此当代码执行到 tradesell 函数时,就会报 AttributeError,提示找不到 g.__stock_ls

解决方案

针对您的情况,有两种解决方案:

方案一:去掉双下划线(推荐)

如果您的变量只是一个普通的列表(如 []),它是完全可以被序列化保存的。您不需要使用双下划线。直接使用普通的 g 变量即可,这样模拟盘每天会自动帮您保存和恢复它的状态。

def initialize(context):
    set_params()
    run_daily(sell, time='09:20')
    run_daily(trade, time='every_bar')

def set_params():
    # 去掉双下划线,使用普通的全局变量
    g.stock_ls = []

def sell(context):
    sell_list = list(context.portfolio.positions.keys())
    for stock_sell in sell_list:
        price = get_price(stock_sell, end_date=context.previous_date, fields=['close'], count=1)
        price = list(price['close'])[0]*0.91
        order_target_value(stock_sell, 0, LimitOrderStyle(price))
        # 同步修改
        g.stock_ls = []

def trade(context):
    # 同步修改
    if len(g.stock_ls) >= 3:
        return

方案二:使用 process_initialize 函数

如果您确实需要使用双下划线变量(通常用于存放不能被序列化的对象,如数据库连接 query 对象、网络请求对象等),或者您希望这个变量每天重启时都被强制清空重置,您必须在 process_initialize(context) 函数中进行初始化。

process_initialize 函数在模拟盘每次重启时(即每天)都会被执行一次。

def initialize(context):
    # initialize 中可以保留其他只需执行一次的初始化逻辑
    run_daily(sell, time='09:20')
    run_daily(trade, time='every_bar')

# 添加 process_initialize 函数
def process_initialize(context):
    # 每次模拟盘重启时都会执行,重新初始化双下划线变量
    g.__stock_ls = []

def sell(context):
    sell_list = list(context.portfolio.positions.keys())
    for stock_sell in sell_list:
        price = get_price(stock_sell, end_date=context.previous_date, fields=['close'], count=1)
        price = list(price['close'])[0]*0.91
        order_target_value(stock_sell, 0, LimitOrderStyle(price))
        g.__stock_ls = []

def trade(context):
    if len(g.__stock_ls) >= 3:
        return

总结

  • 普通数据(列表、字典、数字等):直接用 g.变量名,在 initialize 中初始化即可,系统会自动保存。
  • 不可序列化数据或需每日重置的数据:用 g.__变量名,并且必须process_initialize 中初始化。