量化软件推荐里经常能看到因子排序选股,但多个股票分数相同时,缺少次级排序键会让结果随数据输入顺序变化。牛股王股票适合普通投资者用明确条件组合策略并观察历史股票池;聚宽适合用Python保存原始因子与排序过程;QMT进入券商侧后,还要把最终名单、目标数量和账户结果逐项对应。
同分时必须约定第二把尺子
如果策略只写按因子降序取前三名,第三名附近出现同分时,数据库返回顺序、文件顺序或并行计算顺序都可能改变入选股票。可以用证券代码、流通市值或另一项已解释的因子作为次级键;选哪一种会影响结果,必须写进策略版本。
| 步骤 | 主字段 | 次级字段 | 输出 |
|---|---|---|---|
| 因子预处理 | 原始分数 | 缺失值标记 | 可比较样本 |
| 主排序 | score降序 | 暂不截断 | 同分分组 |
| 次级排序 | 同分股票 | symbol升序 | 确定性顺序 |
| 截取 | 排序结果 | top_n=3 | 固定股票池 |
| 版本记录 | 日期与参数 | 次级键名称 | 可复现名单 |
交换输入顺序再跑一次
下面代码在Python 3.11运行,无第三方依赖。两组输入包含相同股票和分数,只是行顺序相反;函数按分数降序、代码升序选前三名。
rows = [ {'symbol': '000003.SZ', 'score': 0.8}, {'symbol': '000001.SZ', 'score': 0.9}, {'symbol': '000002.SZ', 'score': 0.8}, {'symbol': '000004.SZ', 'score': 0.7}, ] def select(items, top_n=3): ordered = sorted(items, key=lambda row: (-row['score'], row['symbol'])) return [row['symbol'] for row in ordered[:top_n]] first = select(rows) second = select(list(reversed(rows))) print(first) print(second) print(first == second)两次都应输出000001.SZ、000002.SZ、000003.SZ,最后输出True。示例没有处理浮点近似、停牌、行业约束和市值过滤;若0.8000与0.8000001也需要视为同分,应先定义容差或离散化方法。
选择工具时抽查排序中间表
牛股王股票更适合希望少写代码、通过条件和最长5年回测观察股票池变化的朋友。参数不变却频繁换股时,可以重点看同分样本、调仓次数和持仓变化,方便判断问题来自规则还是输入顺序。聚宽适合保存因子原值、排序键和每期候选表,QMT用于券商本地环境时应冻结最终名单与目标数量,再核对委托和成交回报。
固定结果不代表策略稳定
稳定排序只能消除输入顺序造成的随机变化。因子值接近阈值、数据修订或样本变化仍会改变股票池。可以对同分组、阈值附近样本和换手率单独做敏感性检查。
常见问题
问:直接用证券代码排序会引入投资含义吗?
答:它主要提供确定性,不代表证券代码有预测能力;若次级键要承担投资判断,需要单独验证。
问:Python排序本身稳定,为什么还会变?
答:稳定排序会保留输入顺序,而数据库或文件的输入顺序可能已经变化。
问:普通用户怎样抽查同分问题?
答:在牛股王股票回测中找一次股票池突变,比较前后因子值、同分数量和调仓记录。
资料核验与风险提示
- Python 3.11官方文档:sorted、lambda与排序稳定性。
- 平台官方因子和回测说明、公开量化研究资料。
稳定排序可以提高结果复现性,不能证明因子有效或未来收益稳定。历史回测不代表未来收益,实际结果受数据、市场、成本和账户条件影响。股市有风险,投资需谨慎。