查看全课大纲(第 22 / 38 节)
- 1.课程介绍与学习目标
- 2.量化交易的发展
- 3.主观投资与量化投资的关系
- 4.认识一个量化策略(1)
- 5.认识一个量化策略(2)
- 6.理工生做量化的优势
- 7.量化交易系统的基本架构
- 8.必要的交易基础知识及参考资料
- 9.上节课思考题及本节课内容介绍
- 10.技术指标简介
- 11.基于MACD的交易信号开发(1)
- 12.基于MACD的交易信号开发(2)
- 13.基于RSI的交易信号开发
- 14.基于BOLL的交易信号开发
- 15.基于分形的交易信号开发
- 16.总结及下节课预告
- 17.开发环境安装
- 18.获取指数和个股历史行情数据
- 19.修复行情数据中的问题
- 20.抓取财报数据、数据定时更新
- 21.实现低PE股票池(1)
- 22.实现低PE股票池(2)
- 23.实现低PE策略的回测(1)
- 24.实现低PE策略的回测(2)
- 25.风险控制综述
- 26.风险控制中的止盈止损
- 27.仓位管理的工程实现
- 28.完整策略介绍-基础策略
- 29.策略的分步优化
- 30.策略评价指标(1)
- 31.策略评价指标(2)
- 32.如何评价策略
- 33.如何优化策略
- 34.tick数据的意义
- 35.tick数据的介绍及使用
- 36.Hans123策略
- 37.经典买入三法策略
- 38.量化系统的完整研发和系统搭建
实现低PE股票池(2)
约 12 分钟
实现低PE股票池(二):调仓周期设计与集合变动追踪
小象实战讲义 · 初阶量化交易:策略编写及系统搭建 本讲义仅用于编程与量化方法教学,不构成任何投资建议。
在量化投资中,选股模型不仅需要在静态截面上挑选优质标的,更必须在动态时间序列上制定科学的定期调仓机制(Rebalancing Frequency)。股票的市盈率估值随着每日收盘价波动而实时微调,若每日都根据全市场最新 PE 重新洗牌股票池,不仅会引发高额的印花税、佣金与冲击成本摩擦,更会破坏持仓的稳定性。
本讲深入剖析调仓周期设为 7 个交易日的工程权衡哲学;详细讲解新调入(Incoming)、被调出(Outgoing)与留存(Retained)三大股票集合的动态运算与持久化方案;并建立股票池等权持有基准收益率的追踪流水线。
💡 核心导读
- 为什么选择 7 个交易日作为调仓周期?
- 高频调仓的摩擦弊端:每日调仓会导致股票池频繁微调,持股周期极短,产生的印花税(单边万分之五)与交易佣金会迅速蚕食掉策略全部 Alpha 超额收益;
- 低频调仓的滞后弊端:若按季度(60 交易日)调仓,标的股价大幅上涨导致估值严重偏离时无法及时止盈退出;
- 7 日平衡点:约 1.5 周的调仓周期,既给予低估值因子充分的价值回归时间窗口,又将换手率与交易成本控制在极低水平。
- 股票池定期调仓的三大集合变动运算:
- 设上一期股票池标的集合为 ,当期最新筛选出的股票池标的集合为 :
- 新调入集合():新进入估值优势区间的标的,进入择时买入监控队列;
- 被调出集合():估值过高或基本面劣化的标的,若当前持有则触发无条件清仓卖出(强制离场);
- 留存集合():估值依然具备优势的标的,维持现有持仓状态,继续受均线择时规则保护。
- 股票池持久化与基准收益率基准:
- 将每期调仓结果按
{'date': date, 'codes': [code1, code2, ...]}格式落库至 MongoDBstock_pool集合; - 计算每期股票池等权平均收益率,作为衡量后续择时策略能否击败纯选股基准的对比基准。
- 将每期调仓结果按
┌─────────────────────────────────────────────────────────────┐
│ 股票池定期调仓集合变动模型 │
└──────────────────────────────┬──────────────────────────────┘
│
上期股票池 (S_t-1) 当期股票池 (S_t)
┌──────────────────┐ ┌──────────────────┐
│ 被调出 Outgoing│ 交集 │ 新调入 Incoming│
│ (S_t-1 - S_t) │ Retained │ (S_t - S_t-1) │
│ ► 触发清仓卖出 │ (S_t-1∩S)│ ► 触发择时监控 │
└──────────────────┴──────────┴──────────────────┘一、动态股票池状态转移与交易路由
在量化交易引擎中,股票池不仅是一个静态名单,更是驱动交易路由状态机的核心动力:
┌────────────────────────────────────────────────────────────────┐
│ 调仓日状态转移与执行规则 │
├────────────────────────────────────────────────────────────────┤
│ 1. 扫描 Outgoing 集合: 若账户持有该标的,立即发出 Sell 订单清仓│
│ 2. 扫描 Incoming 集合: 将标的加入候选监控列表,等待均线金叉触发│
│ 3. 扫描 Retained 集合: 标的保留在持仓中,若均线死叉则执行止损 │
└────────────────────────────────────────────────────────────────┘二、MongoDB stock_pool 数据集合结构设计
在数据库中,每期调仓记录作为独立文档存储:
{
"date": "2023-01-16",
"codes": ["600000", "600002", "600005", "..."],
"count": 100
}通过在 date 字段建立唯一索引,回测引擎可秒级查询任意回测交易日所属的当期有效股票池。
⚠️ 调仓回测的偏差与成本:本讲名单为内置合成数据。真实回测中每次调仓都会产生佣金、印花税与冲击成本,名单越大、换手越快,摩擦对收益的侵蚀越重;名单只能用当时实际在市的股票计算(幸存者偏差),调入调出依据的财务数据必须已经披露(前视偏差),7 日调仓周期同样是可调参数、存在过拟合风险。本演示不构成任何收益承诺。
📝 动手练一练
下面我们用 Python 编写一段 股票池定期调仓与集合变动动态追踪脚本,模拟连续多个调仓周期中新调入与被调出标的的自动识别:
import pandas as pd
# 保证宽表在任意终端宽度下都完整打印(不折叠中间列),使输出确定、可复现
pd.set_option("display.width", 250)
pd.set_option("display.max_columns", None)
pd.set_option("display.max_rows", None)
import numpy as np
def track_stock_pool_rebalance(pool_history_dict, rebalance_dates):
"""
股票池定期调仓与集合动态追踪引擎
计算各个调仓周期: 新进集合 (Incoming)、调出集合 (Outgoing)、留存集合 (Retained)
"""
records = []
prev_set = set()
for r_date in rebalance_dates:
curr_list = pool_history_dict[r_date]
curr_set = set(curr_list)
# 集合运算
incoming = curr_set - prev_set
outgoing = prev_set - curr_set
retained = curr_set & prev_set
# 注意:不能直接 list(set)——Python 字符串的集合迭代顺序受 PYTHONHASHSEED
# 影响,跨进程不稳定,会让同一份代码每次打印的名单顺序都不同。
# 真实交易系统同样必须显式排序,保证候选名单可复现、可对账。
records.append({
'rebalance_date': r_date,
'pool_size': len(curr_list),
'incoming_count': len(incoming),
'outgoing_count': len(outgoing),
'retained_count': len(retained),
'incoming_codes': sorted(incoming),
'outgoing_codes': sorted(outgoing)
})
prev_set = curr_set
return pd.DataFrame(records)
def test_rebalance_run():
dates = ["2023-01-05", "2023-01-16", "2023-01-27"]
# 模拟 3 期各 4 只股票的低 PE 股票池变动
pool_data = {
"2023-01-05": ['600000', '600001', '600002', '600003'],
"2023-01-16": ['600000', '600002', '600004', '600005'], # 600001/600003 调出, 600004/600005 调入
"2023-01-27": ['600000', '600004', '600005', '600006'] # 600002 调出, 600006 调入
}
res = track_stock_pool_rebalance(pool_data, dates)
print("================ 股票池定期调仓集合追踪报告 ================")
print(res[['rebalance_date', 'pool_size', 'incoming_count', 'outgoing_count', 'retained_count']])
print("------------------------------------------------------------")
for _, row in res.iterrows():
print(f"[{row['rebalance_date']}] 新调入买入候选: {row['incoming_codes']} | 调出强平清仓: {row['outgoing_codes']}")
print("============================================================")
test_rebalance_run()
运行结果输出:
================ 股票池定期调仓集合追踪报告 ================
rebalance_date pool_size incoming_count outgoing_count retained_count
0 2023-01-05 4 4 0 0
1 2023-01-16 4 2 2 2
2 2023-01-27 4 1 1 3
------------------------------------------------------------
[2023-01-05] 新调入买入候选: ['600000', '600001', '600002', '600003'] | 调出强平清仓: []
[2023-01-16] 新调入买入候选: ['600004', '600005'] | 调出强平清仓: ['600001', '600003']
[2023-01-27] 新调入买入候选: ['600006'] | 调出强平清仓: ['600002']
============================================================👉 点击查看解析
本练习的核心是设计固定的调仓周期(如月度或季度),并在每次调仓时对比前后低PE股票池的集合差异,利用集合运算识别新增与剔除的股票,从而实现成分股变动的持续追踪。
本章小结
- 确立 7 日调仓纪律:兼顾价值因子的动态有效性与交易摩擦成本的最优控制。
- 掌握三元集合状态机:新调入标的纳入监控、被调出标的强制离场、留存标的继续持有并由均线择时护航。
- 完成选股层与执行层的解耦:股票池提供候选资产集,择时模块负责买卖触发,回测引擎负责订单撮合。
📋 行动清单 (Action Checklist)
- 运行本讲调仓追踪代码,观察多期交集与差集的运算结果;
- 验证调出标的清仓逻辑:确保持仓股一旦跌出前 100 名能在调仓日被准确卖出;
- 预习下一讲,将 10 日均线择时信号接入股票池,开始搭建完整的回测撮合引擎。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。