关闭
您正在使用的浏览器版本较低,无法支持聚宽的某些特性。
为了获得更好的体验,推荐使用:
Google Chrome
或者
Mozilla Firefox
或者
IE9以上
。
返回主题列表
策略代码中一个隐蔽却极具风险的问题
蚂蚁量化
发布于2025-09-21
回复 45
浏览 4429
77
listen
分享到:
微信
微博
雪球
近期在详细阅读部分策略组合代码时,发现一个隐蔽却极具风险的问题:多数策略组合采用基于类的框架实现,其中一些需维持持续状态的变量——例如记录持仓中发生涨停或止损的股票名单、股票持有天数字典、当日卖出失败待下一交易日再卖的股票列表、股票买入或卖出的天数等,都需要在多个交易日之间保持持久性。平台上流行的Class类框架的策略组合都把这变量存为以 `self.` 开头的类变量,在回测过程中,这一问题不会出现;但一旦投入模拟交易,隐患便会显现。 现实环境中,平台每日需执行多项后台操作(如云服务器数据备份,停止进程降低CPU占用率,等等),这些操作往往需要暂停程序,并在后续时段重新启动。 根据聚宽API说明: > 模拟盘在每日运行结束后会保存状态并结束进程(相当于进入休眠),次日再恢复运行。进程结束时会持久化以下内容:用户账户、持仓(通过 context 对象传递)以及需持久化的变量(即 g 对象)。这些状态将在第二天恢复。 详情见聚宽API [模拟盘注意事项](https://www.joinquant.com/help/api/help#api:模拟盘注意事项)原文。 因此,那些以 `self.` 开头的类变量,在程序停止时并不会被自动保存。一旦程序中止再重启,这些变量将被**重置为初始值**!!! 我查平台上有没有人注意到这个严重问题,看到一个月前就有网友已经发现并提出来,见帖子 [策略中使用类(Class)遇到的问题](https://www.joinquant.com/view/community/detail/91704ebbd87e55b91e992243bb76658e?type=1), 作者在帖子里展示了一个实例 “**回测,一切正常,没有任何问题;但在模拟策略实盘时,出现了值为空的情况**。” 但是这问题热度不高,没有引起大家足够的重视,我这里倡议,大家把自己用到Class类策略梳理一下,特别是那些在实盘的朋友,把需要需持久化的变量存为以g.开头的全局变量。 我自己的策略组合一直都是不用Class类的。但我看我去年我分享的 [国庆节献礼:实例说明“白马攻防”策略](https://www.joinquant.com/view/community/detail/51b35b6e7299bde1585129d413edf5ee), 被应用到一些策略组合之中,就出现了这个问题。 正好网友@Friday_然我帮他看看他分享的策略,让我提提建议,我就以他的这个策略组合为例: ##克隆自聚宽文章:https://www.joinquant.com/post/61069 ## 标题:多策略学习版2.3,19年至今年化55,回撤7.6 ## 作者:Friday_ “白马攻防”策略在其中的应用,它在模拟时有两个问题: 第一. 市场温度不但需要计算现在的值,还需要根据以前的值为条件来判断,所以会出现,回测启动时间不同时,得到的结果不同; 第二. 温度数值没做持到久性。 解决以上两个问题,写个函数,追溯历史数据,滚动得到最新的市场温度,并存为g.开头的全局变量: ``` # 数据回滚两年判断市场温度 def track_back_market_temp(self): long_index300 = list(attribute_history('000300.XSHG', 220*3, '1d', ('close'), df=False)['close']) g.market_temperature = 'cold' for back_day in range(220, len(long_index300)): index300 = long_index300[back_day-220:back_day] market_height = (mean(index300[-5:]) - min(index300)) / (max(index300) - min(index300)) if market_height < 0.28: g.market_temperature = "cold" elif market_height > 0.80: g.market_temperature = "hot" elif max(index300[-60:]) / min(index300) > 1.20: g.market_temperature = "warm"g.mark ``` 这个函数放在判断温度的函数中,只在初次运算时启动一次 ``` # 判断市场温度 def market_temperature_judge(self): if not hasattr(g, 'market_temperature'): self.track_back_market_temp() 。。。。。。 ``` 申明一下:1.本贴主要目的是提醒大家注意这个隐患,防止实盘吃亏,2. 引用的策略中,我只修正了“白马攻防”策略中市场温度变量的持久性,其它的子策略代码我没细看,没做改动。 欢迎大家批评指正!
77
listen
分享到:
微信
微博
雪球
评论
Friday_
蚂蚁大神发现的这个问题的确需要引起注意,看来以后都需要用全局变量更为稳妥了。
2025-09-21
Clarence.罗
是的。
2025-09-21
不断前行
请问是不是组合策略都要注意这类问题,那小白还是用单策略安全
2025-09-21
锦途
应该是都需要注意此类问题,@不断前行
2025-09-21
max2000
有的多策略中使用全局的字典来保存每个策略Class的实例是否就能够解决这个问题。 例如:g.strategys[策略名] = 策略Class实例变量
2025-09-21
wzg3768
感谢提醒
2025-09-21
JMoock
@max2000 这样看你的类在何处初始,initialize和process_initialize是完全不同的。他发现的问题是一个纯属编程语言类生命周期现象
2025-09-21
JMoock
这完全是一个编程语言类生命周期现象问题,属于类的属性就在这个类被回收之前使用,否则就在它生命之外,initialize和process_initialize初始化的对象生命完全不一样
2025-09-21
Gyro^.^
我不使用class
2025-09-21
无名之辈II
小市值和etf没有啥累计计算的变量,还好,都是每天重新计算
2025-09-21
无名之辈II
这个问题,可能就是很多同志提到的一个问题,就是回撤股票和实盘股票不一样
2025-09-21
九条命
感谢提醒,明天把我自己的策略检查一遍,捉臭虫!
2025-09-21
youngyunxing
还有个1月1日bug,如果1月1日刚好是个交易日,指数获取的成分股以及价格可能是错的,不知道有没有人遇到过?
2025-09-21
西花蓟马
学习
2025-09-21
17号
学习
2025-09-21
蚂蚁量化
@Friday_ 是,全局变量更为稳妥
2025-09-22
归零韭菜
还是不够保险, 聚宽过去有一次服务器故障全部代码都重启了, 于是状态丢失. 那次之后我所有 实盘 变量都落盘写csv. 因为聚宽也做不了高频, 日频策略写csv做持久化完全够用了
2025-09-22
dongli
建议自己落盘一下全局变量更保险
2025-09-22
蚂蚁量化
@JMoock 不错,点赞!
2025-09-22
QB1,
嘿嘿,还好我jq,qm t都在用,两边互为对照,验证策略正确性。
2025-09-22
首页
上一页
1
2
3
下一页
尾页
您尚未登录,请
登录
或者
注册
聚宽发表回复。
取 消
提 交