
有小伙伴问,看最近的小市值策略,为什么总有一、四月份空仓过滤?
我说,这个所谓的“日历效应”有其背后的金融逻辑,并且确实能有效降低回撤,所以作为一个可选功能提供给有需要的人。
他接着问,这样会不会太机械了?有没有更灵活一点的择时方法?
我说,当然有,就看你能不能接受它的逻辑。于是便有了今天要探讨的这个动态择时方法——“四大搅屎棍”。
众所周知,小市值策略收益高,但回撤也大,动辄30%~40%+的回撤让持有体验非常不佳。因此,大家一直在孜孜不倦地寻找各种择时方法来降低回撤。“一四月份空仓”算是一个简单粗暴的日历效应策略,但随着知道的人越来越多,部分“鸡贼”的资金开始抢跑,导致这个效应的有效性开始出现漂移。今天,我们就来介绍一种在坊间流传较广的另一种动态择时方法。
从公开资料来看,这个名称非常“接地气”的小市值择时方法,最初是由聚宽社区用户ID为“MarioC”的网友提出的。其核心思想直白而犀利:当银行、有色金属、钢铁和煤炭这四大“搅屎棍”行业中的任意一个,其市场宽度在全市场所有行业中排名第一时,小市值策略就应该立即清仓跑路。

聚宽社区的神贴往往字越少事越大,该贴全文仅百余字,并未详述分析和推理过程。那我们不妨先“大胆假设”,接受这个结论,再“小心求证”地进行回测验证。
MarioC大神给出的样例策略可以拆解为“选股”和“择时”两部分。按照老规矩,我们使用QMT平台,分别对这两个部分进行复现和验证。
选股部分复现与优化
这个选股策略是基于之前一个经典的小市值策略改进而来。原版策略逻辑是“每日在中小综指成分股中选取流通市值最小的5支股票”。新版相较于原版主要有5处改动:
- 调仓频率:从日频调整为周频。
- 新股过滤:增加了上市时间需超过1年的条件。
- 市值指标:从“流通市值”最小改为“总市值”最小。
- 选股数量:从5支增加到10支。
- 基本面过滤:新增了使用净资产收益率(ROE)和总资产收益率(ROA)进行过滤的条件。
但在复现时,我们发现原作者在使用ROE和ROA过滤时,设定的阈值(大于0.15和0.10)单位疑似为“百分比(%)”,这个阈值在金融意义上并不显著。如果我们将阈值修改为更常见的15%和10%,会发现很多时间段内根本没有股票能满足条件。因此,为了尊重原策略逻辑并简化处理,在复现时我们直接使用“每股收益(EPS)大于0”作为替代过滤条件。
BIG_stock_list = get_fundamentals(query(valuation.code, ).filter(valuation.code.in_(choice), indicator.roe > 0.15, indicator.roa > 0.10, ).order_by(valuation.market_cap.asc()).limit(g.stock_num)).set_index('code').index.tolist()

为了验证策略逻辑并为后续魔改打下基础,我们使用QMT结合Tushare数据源复现了这个优化后的小市值策略。为了尽力避免未来函数,在回测设定中:今日选股,所使用的市值、每股收益等因子数据均取自昨日;并且在每个历史时点,都剔除了当时的涨跌停股和ST股(根据当时的股票名称判断,而非现在),以尽力减少幸存者偏差。
该选股策略的回测绩效如下:


该策略年化收益达55.54%,夏普比率为1.82,但最大回撤也高达33.64%,收益回撤比为1.65。这是一个不错的基础策略,但回撤依然是明显的痛点。接下来,我们就看看动态择时部分能否有效“治疗”这个痛点。
动态择时:“四大搅屎棍”逻辑验证
首先明确“行业”的定义,这里指的是申万一级行业分类,共31个行业。
择时逻辑非常简单:在调仓日,根据前一天及之前的数据,分别计算这31个行业的“市场宽度”。如果市场宽度最高的行业恰好是 银行、有色金属、钢铁、煤炭 中的任意一个,那么本次调仓就不开新仓,直接保持空仓。
那么,行业市场宽度 如何计算呢?
计算逻辑很直观:用每个行业内,股价站在20日均线之上的股票数量,除以该行业的总股票数。这个比值就是该行业的市场宽度,数值越大,表明该行业整体趋势越好。
在赌场里,如果你发现某人手气特别背,一直输钱,那么反着他的方向下注往往能赢,这种人被称为“明灯”。同理,在量化领域,这种根据特定行业表现进行反向择时的方法,也被戏称为“行业冥灯”策略。上述四个行业,就被视作需要避开的“冥灯”。
现在,让我们回测一下,当“搅屎棍”行业出现时立即跑路的效果。


与之前永远满仓的纯选股策略相比,最大回撤从 33.64% 显著降低到了 20.78%。当然,代价是年化收益也从 55.54% 下降到了 41.16%。回撤降低了12.86个百分点,收益降低了14.38个百分点,收益的牺牲略大于回撤的改善。
好的方面是,夏普比率基本持平,而收益回撤比从1.65提升到了接近2.0,持有体验会更好一些。这证明,这种基于行业宽度判别的动态择时方法,确实有助于降低小市值策略的最大回撤,但需要投资者在收益与风险之间做出自己的权衡。
强强联合:动态择时 + 日历效应
这时可能有读者会想:小孩子才做选择,成年人当然是全都要。如果把固定的“日历效应”择时(一、四月空仓)和动态的“行业冥灯”择时结合起来使用,效果会怎样?


结果显示,与之前两个版本相比,年化收益和最大回撤都进一步下降了。年化收益为40.05%,最大回撤为19.30%。策略的夏普比率提升到了 1.92,收益回撤比也提高到了 2.08。这意味着持有体验的“舒适度”又往前迈进了一小步。这种多维度、多因子的风控思路,在数据挖掘和策略组合中很常见,旨在更平滑地控制净值曲线。
实盘参数设置要点
策略逻辑验证完毕后,以下是为想要实战或魔改的小伙伴提供的实盘参数设置核心要点,这份配置文件是策略能否稳健运行的关键。

ACCOUNT_ID:你的股票资金账号。回测时可随意填写,实盘时必须填写正确。
ACCOUNT_TYPE:交易账户类型,股票交易固定为 ‘STOCK’。
ACCOUNT_MODE:资金管理模式。MONEY 表示使用固定金额(由 ACCOUNT_MONEY 设定),RATIO 表示使用账户总资金的一定比例(由 ACCOUNT_RATIO 设定,范围0~1.0)。
STRATEGY_TRADETIME:策略触发交易的具体时间。对于日线/周线策略,必须指定一个确定的时间点。
ORDER_TIMEOUT:订单超时时间(秒)。委托下单后,若超过此时间未完全成交,策略程序会自动撤单并重新下单。
STRATEGY_PATH:策略文件存储路径。策略运行日志、持仓文件等都会保存在此路径下,是实现仓位隔离和交易回溯的关键。
STRATEGY_NAME:策略名称。一旦开始实盘,切勿随意修改,否则程序将无法识别历史持仓文件,导致仓位混乱。名称中请勿使用下划线、空格等特殊字符。
INDEX_CODE:基准指数代码,用于确定选股股票池。默认为中小综指(399101.SZ)。
SELECT_NUM:每次调仓选股的数量,默认为10支。
WEEK_DAY:每周第几个交易日调仓,1 代表每周一(遇节假日顺延)。
JINX_INDU_LIST:“行业冥灯”列表。默认为 [‘801780.SI’, ‘801050.SI’, ‘801040.SI’, ‘801950.SI’](分别对应银行、有色金属、钢铁、煤炭的申万行业代码)。空列表 [] 表示关闭此过滤条件。
FILTER_MONTH_LIST:需过滤(空仓)的月份列表。[1,4] 表示1月和4月空仓,[] 表示不对月份进行过滤。
TOKEN:你的Tushare Pro接口Token,用于获取基本面数据。
本次介绍的“小市值优化策略行业冥灯版”已包含回测版(V1)和回测实盘一体版(V2)的源代码及相关文件。对于量化新手,强烈建议通过导入 .rzrk 策略备份文件的方式使用,该文件包含了完整的策略源码及回测参数,使用起来更加省心。

总结:本文通过复现与测试,验证了基于“行业市场宽度”的动态择时方法对于控制小市值策略回撤的有效性。将“四大搅屎棍”择时与传统的日历效应择时相结合,可以构建一个多维度风控体系,在牺牲部分收益的前提下,显著改善策略的夏普比率和收益回撤比,提升投资体验。这正体现了量化交易中通过算法和规则来系统性管理风险的思路。所有策略思路和代码均供学习和交流之用,不构成任何投资建议。市场有风险,投资需谨慎。欢迎在云栈社区交流更多关于策略优化与人工智能在金融中的应用的想法。