第十六章:技术因子——均线系统、布林带、ATR、ADX与基本面因子的融合
各位同学,欢迎来到技术因子专场。
说实话,很多做量化的人一上来就搞深度学习、搞高频,结果连最基础的均线都没吃透。我个人习惯是,先把传统技术指标玩明白,再谈别的。因为技术因子是市场情绪的"心电图",你连心电图都看不懂,怎么去诊断市场?
16.1 均线系统:MA与EMA
均线,说白了就是过去 N 天的平均价格。MA 是简单平均,EMA 是指数加权平均——越近的数据权重越大。
核心区别: MA 反应慢,但信号稳定;EMA 反应快,但容易假突破。
我在项目中遇到过一个问题:用 MA(5,10,20) 做金叉死叉策略,回测收益很漂亮,一上实盘就亏。后来发现,MA 在震荡市里频繁交叉,全是假信号。怎么解决?加一个"过滤条件"——只有价格同时站上60日均线,才执行金叉信号。
import pandas as pd
import numpy as np
def calc_ma(close, window=5):
return close.rolling(window=window).mean()
def calc_ema(close, window=5):
return close.ewm(span=window, adjust=False).mean()
# 实战用法:MA多头排列
df['ma5'] = calc_ma(df['close'], 5)
df['ma10'] = calc_ma(df['close'], 10)
df['ma20'] = calc_ma(df['close'], 20)
df['ma60'] = calc_ma(df['close'], 60)
# 多头排列条件:5>10>20>60
df['bullish'] = (df['ma5'] > df['ma10']) & (df['ma10'] > df['ma20']) & (df['ma20'] > df['ma60'])
我的小技巧: 不要只用一组均线。试试 (5,13,34) 这种斐波那契数列,或者 (8,21,55),有时候效果出奇的好。
16.2 布林带:波动率的可视化
布林带由三根线组成:中轨(MA)、上轨(中轨+2倍标准差)、下轨(中轨-2倍标准差)。
你想想看,当价格碰到上轨,是不是该卖了?不一定。在强趋势行情里,价格会沿着上轨"爬行",这时候做空就是找死。
def calc_bollinger(close, window=20, num_std=2):
ma = close.rolling(window=window).mean()
std = close.rolling(window=window).std()
upper = ma + num_std * std
lower = ma - num_std * std
return ma, upper, lower
# 布林带宽度因子:衡量波动率变化
df['boll_width'] = (df['upper'] - df['lower']) / df['ma']
# 布林带位置因子:价格在带内的相对位置
df['boll_pos'] = (df['close'] - df['lower']) / (df['upper'] - df['lower'])
避坑指南: 我曾经用布林带做"突破上轨买入"的策略,结果在2015年股灾里亏得底裤都不剩。为什么?因为极端行情下,布林带会迅速扩张,上轨追高就是接盘侠。记住:布林带更适合震荡市,趋势市里要配合其他指标。
16.3 ATR:真实波动幅度
ATR(Average True Range)衡量的是市场的真实波动幅度。它不告诉你方向,只告诉你"今天波动有多大"。
ATR 的计算有点绕,但核心就三个值:
- 今日最高 - 今日最低
- 今日最高 - 昨日收盘
- 昨日收盘 - 今日最低
取这三个值的最大值,就是 True Range。然后对 TR 做14天平均,就是 ATR。
def calc_atr(df, window=14):
high, low, close = df['high'], df['low'], df['close']
tr1 = high - low
tr2 = abs(high - close.shift(1))
tr3 = abs(low - close.shift(1))
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
atr = tr.rolling(window=window).mean()
return atr
# ATR实战:动态止损
df['atr'] = calc_atr(df)
df['stop_loss'] = df['close'] - 2 * df['atr'] # 2倍ATR止损
个人经验: ATR 是我最常用的风控因子。我习惯用 ATR 来设置止盈止损——不是固定百分比,而是动态的。比如买入后,止损设在"入场价 - 1.5倍 ATR"。这样波动大的股票止损宽一点,波动小的窄一点,很合理。
16.4 ADX:趋势强度指标
ADX(Average Directional Index)告诉你"现在有没有趋势",以及"趋势有多强"。它不告诉你方向,只告诉你强度。
ADX 的计算分三步:
- 计算 +DI 和 -DI(正向/负向方向指标)
- 计算 DX(方向指标差值)
- 对 DX 做平滑,得到 ADX
def calc_adx(df, window=14):
high, low, close = df['high'], df['low'], df['close']
# 计算方向变动
up_move = high - high.shift(1)
down_move = low.shift(1) - low
# +DM和-DM
plus_dm = np.where((up_move > down_move) & (up_move > 0), up_move, 0)
minus_dm = np.where((down_move > up_move) & (down_move > 0), down_move, 0)
# TR和ATR
tr = pd.concat([high-low, abs(high-close.shift(1)), abs(low-close.shift(1))], axis=1).max(axis=1)
atr = tr.rolling(window=window).mean()
# 平滑+DI和-DI
plus_di = 100 * pd.Series(plus_dm).rolling(window=window).mean() / atr
minus_di = 100 * pd.Series(minus_dm).rolling(window=window).mean() / atr
# DX和ADX
dx = 100 * abs(plus_di - minus_di) / (plus_di + minus_di)
adx = dx.rolling(window=window).mean()
return adx, plus_di, minus_di
# 实战用法:ADX > 25 表示强趋势
df['strong_trend'] = df['adx'] > 25
我的用法: ADX 低于20时,市场在震荡,这时候用布林带做高抛低吸。ADX 高于30时,市场在趋势中,这时候用均线系统做趋势跟踪。说白了,ADX 就是"市场状态切换器"。
16.5 技术因子与基本面因子结合
这才是今天的重头戏。纯技术因子有个致命缺陷——它只看价格,不看公司基本面。你想想看,一个垃圾股突然放量突破,技术指标全走好了,你敢追吗?
我建议的做法是:用基本面因子做"筛选",用技术因子做"择时"。
| 因子类型 | 作用 | 具体因子 |
|---|---|---|
| 基本面筛选 | 排除垃圾股 | PE、PB、ROE、营收增速 |
| 技术择时 | 选择入场点 | MA 金叉、布林带突破、ADX > 25 |
| 风控管理 | 控制回撤 | ATR 动态止损、波动率过滤 |
# 技术+基本面结合示例
def combined_factor(df):
# 基本面筛选:ROE > 15% 且 PE < 30
fundamental_filter = (df['roe'] > 15) & (df['pe'] < 30)
# 技术择时:MA5上穿MA20 且 ADX > 25
technical_signal = (df['ma5'] > df['ma20']) & (df['adx'] > 25)
# 风控:ATR < 历史80%分位数(排除异常波动)
atr_threshold = df['atr'].quantile(0.8)
risk_filter = df['atr'] < atr_threshold
# 综合信号
df['combined_signal'] = fundamental_filter & technical_signal & risk_filter
return df
曾经踩过的坑: 我试过把技术因子和基本面因子直接加权求和,结果回测一塌糊涂。为什么?因为两个因子的量纲不同,PE 是几十倍,ATR 是几块钱,直接相加毫无意义。正确的做法是:先分别做标准化(z-score 或分位数),再组合。
16.6 知识体系总览
下面这张图,是我自己总结的技术因子知识体系。你可以把它当作"技术因子地图"来用。
flowchart TD
Root[技术因子] --> A[均线系统<br/>MA 简单平均<br/>EMA 指数加权<br/>金叉/死叉<br/>多头/空头排列]
Root --> B[布林带<br/>中轨 MA<br/>上轨/下轨<br/>带宽 波动率<br/>位置因子]
Root --> C[ATR<br/>真实波幅 TR<br/>动态止损<br/>仓位管理]
Root --> D[ADX<br/>+DI / -DI<br/>趋势强度<br/>震荡/趋势切换]
A --> Out[技术因子 + 基本面因子 = 完整策略]
B --> Out
C --> Out
D --> Out
嗯,以上就是技术因子的核心内容。记住一句话:技术因子是工具,基本面因子是锚。没有锚的船,风一吹就翻了。
最后分享一个心得: 我做了这么多年量化,发现最赚钱的策略往往不是最复杂的。一个"基本面选股 + 均线择时 + ATR 风控"的简单组合,跑赢了很多花里胡哨的机器学习模型。别把简单的事情搞复杂了。