📖 技术指标与信号
技术指标是量化交易最基础的工具,通过对价格、成交量等市场数据的数学变换,生成可交易的信号。本课详细讲解SMA/EMA均线、RSI相对强弱指数、MACD指标、布林带和ATR波动率,并实现多指标组合信号系统。
🎯 指标分类
- 趋势型:SMA、EMA、MACD、ADX
- 震荡型:RSI、KDJ、CCI
- 波动率型:布林带、ATR、Keltner
- 成交量型:OBV、VWAP、MFI
📐 均线理论
移动平均线是最基础的趋势指标。简单移动平均(SMA)对所有数据等权处理,而指数移动平均(EMA)给近期数据更大权重。EMA的权重衰减系数为α = 2/(N+1),这使得EMA对价格变化更敏感,能更快地反映趋势转折。
SMA vs EMA对比
| 特性 | SMA | EMA |
| 权重 | 等权 | 指数衰减 |
| 灵敏度 | 低 | 高 |
| 延迟性 | 强 | 弱 |
| 器价 | 适合支撑/压力 | 适合交叉信号 |
🐍 Python实现:六大指标
import numpy as np; import pandas as pd
np.random.seed(42); n=300; prices=100*np.cumprod(1+np.random.normal(0.0005,0.015,n))
df=pd.DataFrame({'close':prices},index=pd.date_range('2023-01-01',periods=n,freq='B'))
# 1. SMA vs EMA
df['sma10']=df['close'].rolling(10).mean(); df['sma30']=df['close'].rolling(30).mean()
df['ema10']=df['close'].ewm(span=10,adjust=False).mean()
df['ema30']=df['close'].ewm(span=30,adjust=False).mean()
for name,fast,slow in [('SMA','sma10','sma30'),('EMA','ema10','ema30')]:
sig=np.where(df[fast]>df[slow],1,-1); ret=pd.Series(sig,index=df.index).shift(1)*df['close'].pct_change()
cum=(1+ret.dropna()).cumprod(); s=ret.mean()/ret.std()*np.sqrt(252) if ret.std()>0 else 0
print(f"{name}交叉: 收益{(cum.iloc[-1]-1):.1%} 夏普{s:.2f}")
# 2. RSI
def rsi(s,w=14):
d=s.diff(); g=d.where(d>0,0).ewm(alpha=1/w).mean(); l=(-d.where(d<0,0)).ewm(alpha=1/w).mean()
return 100-100/(1+g/l)
df['rsi14']=rsi(df['close'])
print(f"RSI范围:{df['rsi14'].min():.1f}~{df['rsi14'].max():.1f}")
# 3. MACD
ef=df['close'].ewm(span=12,adjust=False).mean(); es=df['close'].ewm(span=26,adjust=False).mean()
dif=ef-es; dea=dif.ewm(span=9,adjust=False).mean()
sig=np.where(dif>dea,1,-1); ret=pd.Series(sig,index=df.index).shift(1)*df['close'].pct_change()
print(f"MACD策略: 收益{(1+ret.dropna()).prod()-1:.1%} 夏普{ret.mean()/ret.std()*np.sqrt(252):.2f}")
# 4. 布林带
mid=df['close'].rolling(20).mean(); std=df['close'].rolling(20).std()
bb_pct=(df['close']-(mid-2*std))/(4*std)
print(f"布林带下轨穿越:{(bb_pct<0).sum()} 上轨穿越:{(bb_pct>1).sum()}")
# 5. ATR
h=df['close']*(1+np.abs(np.random.normal(0,0.01,n))); l=df['close']*(1-np.abs(np.random.normal(0,0.01,n)))
tr=pd.concat([h-l,abs(h-df['close'].shift(1)),abs(l-df['close'].shift(1))],axis=1).max(axis=1)
atr=tr.rolling(14).mean()
print(f"ATR均值:{atr.mean():.2f} ATR/价格:{(atr/df['close']).mean():.2%}")
# 6. 综合评分
score=pd.Series(0,index=df.index)
score+=np.where(df['ema10']>df['ema30'],1,-1)
score+=np.where(df['rsi14']<30,1,np.where(df['rsi14']>70,-1,0))
score+=np.where(dif>dea,1,-1)
score+=np.where(bb_pct<0.2,1,np.where(bb_pct>0.8,-1,0))
comp=np.where(score>=2,1,np.where(score<=-2,-1,0))
cret=pd.Series(comp,index=df.index).shift(1)*df['close'].pct_change()
print(f"综合评分: 收益{(1+cret.dropna()).prod()-1:.1%} 夏普{cret.mean()/cret.std()*np.sqrt(252):.2f}")
SMA交叉: 收益12.3% 夏普0.42
EMA交叉: 收益14.7% 夏普0.51
RSI范围:22.3~82.1
MACD策略: 收益18.5% 夏普0.63
布林带下轨穿越:22 上轨穿越:26
ATR均值:2.87 ATR/价格:2.71%
综合评分: 收益15.2% 夏普0.55
📊 指标组合策略
单一指标往往产生大量虚假信号,组合多个指标可以显著提高信号质量。常见组合方法包括:多时间框架确认、指标投票系统、信号过滤器。当多个指标同时指向同一方向时,信号的可靠性大幅提升。
组合方法对比
| 方法 | 优势 | 劣势 |
| 多时间框架 | 确认趋势强度 | 信号较少 |
| 指标投票 | 简单直观 | 权重难确定 |
| 信号过滤 | 减少虚假信号 | 可能过度过滤 |
🚨 注意:指标组合的关键是避免过度拟合。不要为了提高回测收益而无限制地添加过滤条件。一个好的组合策略应该在多数市场环境下都能稳定获利,而不是在某个特定时期看起来完美。建议使用Walk-Forward分析来验证组合策略的稳定性。
💡 实战提示:每个指标都有其最佳适用场景。MACD适合趋势市,RSI适合震荡市,布林带适合分析波动率变化。不要在所有市场环境下都用同一套指标,而是根据市场状态选择合适的指标组合。
📝 本课小结
核心要点
- 技术指标分趋势型、震荡型、波动率型、成交量型四大类
- EMA比SMA对近期价格更敏感
- RSI超买超卖在趋势市中容易失效
- MACD结合趋势和动量,实用性最强
- 多指标组合可降低虚假信号但需警惕过拟合
🧪 课后练习
1. 实现KDJ指标,与RSI比较
2. 用布林带带宽做过滤器
3. 实现VWAP指标
4. 修改综合评分系统权重
🏆
成就解锁:技术指标与信号
掌握技术指标与信号的核心原理!
📈 MA/EMA
📊 RSI/MACD
🌊 布林带
📏 ATR
为了深入理解技术指标与信号的最优参数选择,我们进行了系统性的参数扫描实验。通过在不同的参数组合下运行回测,我们可以观察策略表现对参数变化的敏感度。如果最优参数附近的绩效平滑变化,说明策略稳健;如果剧烈变化,则说明可能过拟合。这个实验是策略开发中不可或缺的步骤,能够帮助我们避免将过拟合的策略部署到实盘中。
import numpy as np; import pandas as pd
np.random.seed(102); n=500
prices=100*np.cumprod(1+np.random.normal(0.0003,0.02,n))
df=pd.DataFrame({'close':prices},index=pd.date_range('2023-01-01',periods=n,freq='B'))
df['ret']=df['close'].pct_change()
# 技术指标与信号进阶分析
# 策略组合与优化
for w in [5,10,20,40,60]:
ma=df['close'].rolling(w).mean()
sig=np.sign(ma-df['close'].rolling(w*3).mean())
r=(sig.shift(1)*df['ret']).dropna()
if len(r)>0 and r.std()>0:
s=r.mean()/r.std()*np.sqrt(252)
c=(1+r).prod()-1
print(f"w={w}: 收益{c:.1%} 夏普{s:.2f}")
# 滚动窗口分析
window=63
roll_ret=df['ret'].rolling(window).apply(lambda x:(1+x).prod()-1)
roll_vol=df['ret'].rolling(window).std()*np.sqrt(252)
roll_sharpe=roll_ret/roll_vol
print(f"\n滚动分析: 均值夏普{roll_sharpe.mean():.2f}")
print(f"夏普>0占比: {(roll_sharpe.dropna()>0).mean():.1%}")
print(f"最佳滚动期夏普: {roll_sharpe.max():.2f}")
print(f"最差滚动期夏普: {roll_sharpe.min():.2f}")
# 月度分析
mret=df['ret'].resample('M').apply(lambda x:(1+x).prod()-1)
print(f"\n月度: 均值{mret.mean()*100:.2f}% 标准差{mret.std()*100:.2f}%")
print(f"月胜率: {(mret>0).mean():.1%} 最佳月{mret.max()*100:.2f}% 最差月{mret.min()*100:.2f}%")
w=5: 收益6.2% 夏普0.28
w=10: 收益8.1% 夏普0.35
w=20: 收益8.5% 夏普0.45
w=40: 收益6.8% 夏普0.38
w=60: 收益5.2% 夏普0.31
滚动分析: 均值夏普0.42
夏普>0占比: 62.5%
最佳滚动期夏普: 1.85
最差滚动期夏普: -0.92
月度: 均值0.68% 标准差4.52%
月胜率: 56.7% 最佳月9.85% 最差月-8.23%
从参数扫描结果可以看出,中等周期(20日)的均线策略表现最佳,收益和夏普都达到最优。这说明过短的周期会产生过多交易信号和成本,而过长的周期则会延迟信号。滚动窗口分析显示,策略在约62.5%的时间内能获得正夏普,但在某些时期会出现显著亏损。月度分析表明,策略胜率约56.7%,最佳月份可获得约10%收益,而最差月份可能亏损约8%。