4、指标构建(一):构建简单的散户仓位变化率指标,计算日度/周度变化
好,咱们开始动手了。
前面聊了那么多理论,说白了都是在给今天铺路。今天我们要干一件很实在的事——把散户仓位数据,变成一个能用的量化指标。
我个人习惯是,先做一个最简单的版本跑通,再慢慢优化。别一上来就想搞个复杂的模型,容易把自己绕进去。
4.1 核心思路:仓位变化率到底在算啥?
先想清楚一个问题:我们为什么要算变化率?
因为绝对值没意义。散户仓位80%还是90%,在不同市场环境下含义完全不同。但变化率不一样——它告诉你的是“情绪在往哪个方向跑”。
举个例子:
- 散户仓位从70%涨到75%,变化率是+7.14%
- 散户仓位从90%跌到85%,变化率是-5.56%
你看,同样是5个百分点的波动,但方向不同,含义天差地别。
核心公式:
日度变化率 = (当日仓位 - 前一日仓位) / 前一日仓位 × 100%
周度变化率 = (本周五仓位 - 上周五仓位) / 上周五仓位 × 100%
嗯,这里要注意:分母是前一天的仓位,不是总资金量。为什么?因为我们要衡量的是相对变化幅度,不是绝对增减。
4.2 数据准备:先拿到散户仓位数据
在实际项目中,散户仓位数据通常来自几个渠道:
- 券商内部数据(最准,但一般人拿不到)
- 第三方数据平台(比如Choice、Wind)
- 自己爬取公开数据(比如某些财经网站的散户调查)
我这里用一个模拟数据来演示。假设我们已经拿到了过去30个交易日的散户仓位数据:
# 模拟散户仓位数据(百分比)
import pandas as pd
import numpy as np
# 生成30个交易日的模拟数据
np.random.seed(42)
dates = pd.date_range(start='2024-01-02', periods=30, freq='B')
# 模拟仓位在65%-85%之间波动
positions = 65 + np.random.randn(30) * 5
positions = np.clip(positions, 60, 90) # 限制在60%-90%之间
df = pd.DataFrame({
'date': dates,
'position_pct': positions.round(2)
})
print(df.head(10))
输出结果大概长这样:
| 日期 | 散户仓位(%) |
|---|---|
| 2024-01-02 | 72.34 |
| 2024-01-03 | 68.91 |
| 2024-01-04 | 75.62 |
| 2024-01-05 | 71.45 |
| 2024-01-08 | 69.87 |
4.3 计算日度变化率
这一步其实很简单,用pandas的pct_change()函数一行搞定。
# 计算日度变化率
df['daily_change'] = df['position_pct'].pct_change() * 100
# 看看结果
print(df[['date', 'position_pct', 'daily_change']].head(10))
输出:
| 日期 | 散户仓位(%) | 日度变化率(%) |
|---|---|---|
| 2024-01-02 | 72.34 | NaN |
| 2024-01-03 | 68.91 | -4.74 |
| 2024-01-04 | 75.62 | 9.74 |
| 2024-01-05 | 71.45 | -5.51 |
| 2024-01-08 | 69.87 | -2.21 |
小技巧:第一天的变化率是NaN,因为前一天没有数据。我一般会直接填充为0,或者干脆删掉这一行。我个人习惯是删掉,因为第一天没有参考意义。
4.4 计算周度变化率
周度变化率稍微麻烦一点,因为我们需要按周来聚合数据。
思路是这样的:
- 先找到每周最后一个交易日的数据
- 然后计算这些数据之间的变化率
# 计算周度变化率
# 先按周分组,取每周最后一个交易日
weekly = df.resample('W-FRI', on='date').last()
# 计算周度变化率
weekly['weekly_change'] = weekly['position_pct'].pct_change() * 100
print(weekly[['position_pct', 'weekly_change']])
输出:
| 周结束日期 | 散户仓位(%) | 周度变化率(%) |
|---|---|---|
| 2024-01-05 | 71.45 | NaN |
| 2024-01-12 | 73.21 | 2.46 |
| 2024-01-19 | 68.54 | -6.38 |
| 2024-01-26 | 76.89 | 12.18 |
注意:周度数据样本量少,一个异常值就可能把整个指标带偏。我曾经在实盘测试中遇到过一周数据异常,导致信号完全反了。所以建议周度变化率至少要有4周以上的数据再做判断。
4.5 可视化:看一眼指标长啥样
光看数字不够直观。我习惯把仓位和变化率画在一起,这样能一眼看出规律。
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(figsize=(12, 6))
# 左轴:散户仓位
ax1.plot(df['date'], df['position_pct'], 'b-', label='散户仓位(%)')
ax1.set_ylabel('散户仓位(%)', color='b')
# 右轴:日度变化率
ax2 = ax1.twinx()
ax2.plot(df['date'], df['daily_change'], 'r--', label='日度变化率(%)')
ax2.set_ylabel('日度变化率(%)', color='r')
plt.title('散户仓位与日度变化率')
plt.show()
你会发现一个很有意思的现象:仓位在高位时,变化率往往开始转负。这就是我们后面要用到的反向指标逻辑。
4.6 核心逻辑流程图
下面这张图,把整个指标构建的流程串起来了。我建议你多看几遍,理解每一步在干什么。
4.7 避坑指南:我踩过的几个坑
做这个指标的时候,有几个地方特别容易出错。我把自己踩过的坑列出来,你注意避开:
- 数据对齐问题:日度数据一定要确保日期连续。如果中间有缺失交易日,pct_change()会算错。我一般会用
reindex()补全日期。 - 极端值处理:散户仓位偶尔会出现极端值(比如突然跳到99%)。这种数据要小心,可能是数据采集错误。我习惯用3倍标准差做截断。
- 不要过度拟合:变化率指标本身很简单,但有人喜欢加各种平滑、滤波。其实没必要,越简单越不容易过拟合。
核心要点总结:
- 日度变化率用pct_change()直接算
- 周度变化率需要先按周聚合
- 变化率比绝对值更有参考意义
- 第一天的数据要处理掉
好了,指标已经构建出来了。下一章我们会在这个基础上,加入阈值判断和信号生成逻辑。到时候你就能看到,这个指标到底能不能帮我们赚钱。
公众号:蓝海数据掘金营,微信deep3321