技术指标计算
技术指标是量化交易中最基础的分析工具,通过对价格和成交量数据的数学变换,揭示市场的趋势、动量和波动特征。本章将详细介绍常用技术指标的计算原理和Python实现。
移动平均线
移动平均线是最基础的技术指标,用于平滑价格波动、识别趋势方向。
简单移动平均线(SMA)
简单移动平均线计算一定周期内价格的算术平均值。
公式:
其中 是第 期的价格, 是周期长度。
import pandas as pd
import numpy as np
def calculate_sma(data, window):
"""
计算简单移动平均线
参数:
data: 价格序列(Series)
window: 移动窗口大小
返回:
SMA序列
"""
return data.rolling(window=window).mean()
# 使用示例
# 假设df是包含Close列的DataFrame
df['SMA_5'] = calculate_sma(df['Close'], 5) # 5日均线
df['SMA_20'] = calculate_sma(df['Close'], 20) # 20日均线
df['SMA_60'] = calculate_sma(df['Close'], 60) # 60日均线
SMA的特点是对所有历史价格赋予相同权重,反应相对滞后。周期越长,滞后性越明显,但也更能反映长期趋势。
指数移动平均线(EMA)
指数移动平均线对近期价格赋予更高权重,反应更灵敏。
公式:
其中 是平滑因子, 是周期长度。
def calculate_ema(data, window):
"""
计算指数移动平均线
参数:
data: 价格序列
window: 周期长度
返回:
EMA序列
"""
return data.ewm(span=window, adjust=False).mean()
# 使用示例
df['EMA_12'] = calculate_ema(df['Close'], 12) # 12日EMA
df['EMA_26'] = calculate_ema(df['Close'], 26) # 26日EMA
EMA相比SMA更快响应价格变化,适合追踪短期趋势。在趋势转折时,EMA会更快发出信号,但也可能产生更多假信号。
移动平均线的应用
趋势判断:价格在均线上方视为上升趋势,在均线下方视为下降趋势。
金叉死叉:短期均线上穿长期均线称为"金叉",是买入信号;短期均线下穿长期均线称为"死叉",是卖出信号。
def ma_crossover_strategy(df, short_window=5, long_window=20):
"""
均线交叉策略
参数:
df: 包含Close列的DataFrame
short_window: 短期均线周期
long_window: 长期均线周期
返回:
包含信号的DataFrame
"""
df = df.copy()
df['SMA_short'] = calculate_sma(df['Close'], short_window)
df['SMA_long'] = calculate_sma(df['Close'], long_window)
# 生成信号:1表示买入,-1表示卖出,0表示持有
df['signal'] = 0
df.loc[df['SMA_short'] > df['SMA_long'], 'signal'] = 1
df.loc[df['SMA_short'] < df['SMA_long'], 'signal'] = -1
# 检测交叉点
df['position'] = df['signal'].diff()
# position = 2: 金叉(从-1变为1)
# position = -2: 死叉(从1变为-1)
return df
MACD指标
MACD(Moving Average Convergence Divergence,指数平滑异同移动平均线)是趋势跟踪动量指标,由Gerald Appel于1970年代提出。
MACD的构成
MACD由三部分组成:
DIF(快线):短期EMA与长期EMA的差值
DEA(慢线/信号线):DIF的EMA
MACD柱:DIF与DEA的差值
def calculate_macd(df, fast=12, slow=26, signal=9):
"""
计算MACD指标
参数:
df: 包含Close列的DataFrame
fast: 快线周期,默认12
slow: 慢线周期,默认26
signal: 信号线周期,默认9
返回:
包含MACD指标的DataFrame
"""
df = df.copy()
# 计算快慢EMA
ema_fast = df['Close'].ewm(span=fast, adjust=False).mean()
ema_slow = df['Close'].ewm(span=slow, adjust=False).mean()
# 计算DIF
df['DIF'] = ema_fast - ema_slow
# 计算DEA(信号线)
df['DEA'] = df['DIF'].ewm(span=signal, adjust=False).mean()
# 计算MACD柱
df['MACD'] = (df['DIF'] - df['DEA']) * 2
return df
# 使用示例
df = calculate_macd(df)
MACD的应用
零轴分界:DIF和DEA在零轴上方表示多头市场,在零轴下方表示空头市场。
金叉死叉:DIF上穿DEA为买入信号,DIF下穿DEA为卖出信号。在零轴上方的金叉信号更可靠。
背离:价格创新高但MACD未创新高,称为顶背离,预示可能下跌;价格创新低但MACD未创新低,称为底背离,预示可能上涨。
def detect_macd_divergence(df, lookback=20):
"""
检测MACD背离
参数:
df: 包含Close和MACD指标的DataFrame
lookback: 回看周期
返回:
背离信号:1表示底背离,-1表示顶背离,0表示无背离
"""
signals = pd.Series(0, index=df.index)
for i in range(lookback, len(df)):
window = df.iloc[i-lookback:i+1]
# 检测底背离:价格新低但MACD未新低
price_low = window['Close'].iloc[-1] == window['Close'].min()
macd_low = window['MACD'].iloc[-1] > window['MACD'].min()
if price_low and macd_low:
signals.iloc[i] = 1
# 检测顶背离:价格新高但MACD未新高
price_high = window['Close'].iloc[-1] == window['Close'].max()
macd_high = window['MACD'].iloc[-1] < window['MACD'].max()
if price_high and macd_high:
signals.iloc[i] = -1
return signals
RSI指标
RSI(Relative Strength Index,相对强弱指数)是衡量超买超卖的震荡指标,由Welles Wilder于1978年提出。
RSI计算公式
其中
RSI的取值范围是0到100,通常使用14日RSI。
def calculate_rsi(df, window=14):
"""
计算RSI指标
参数:
df: 包含Close列的DataFrame
window: RSI周期,默认14
返回:
RSI序列
"""
# 计算价格变化
delta = df['Close'].diff()
# 分离上涨和下跌
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
# 计算平均上涨和下跌
avg_gain = gain.rolling(window=window).mean()
avg_loss = loss.rolling(window=window).mean()
# 计算RS和RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
# 使用示例
df['RSI_14'] = calculate_rsi(df, 14)
RSI的应用
超买超卖:RSI > 70视为超买,可能回调;RSI < 30视为超卖,可能反弹。
背离:与MACD类似,RSI也可以用来判断背离。
中轴线:RSI = 50是多空分界线,RSI > 50偏多,RSI < 50偏空。
def rsi_signal(rsi, oversold=30, overbought=70):
"""
RSI交易信号
参数:
rsi: RSI序列
oversold: 超卖阈值
overbought: 超买阈值
返回:
信号序列:1买入,-1卖出,0持有
"""
signal = pd.Series(0, index=rsi.index)
signal[rsi < oversold] = 1 # 超卖买入
signal[rsi > overbought] = -1 # 超买卖出
return signal
布林带
布林带(Bollinger Bands)是衡量价格波动范围的指标,由John Bollinger于1980年代提出。
布林带的构成
布林带由三条轨道组成:
中轨:n日移动平均线
上轨:中轨 + k倍标准差
下轨:中轨 - k倍标准差
通常使用n=20,k=2。
def calculate_bollinger_bands(df, window=20, num_std=2):
"""
计算布林带
参数:
df: 包含Close列的DataFrame
window: 移动窗口,默认20
num_std: 标准差倍数,默认2
返回:
包含布林带的DataFrame
"""
df = df.copy()
# 计算中轨(SMA)
df['BB_middle'] = df['Close'].rolling(window=window).mean()
# 计算标准差
rolling_std = df['Close'].rolling(window=window).std()
# 计算上下轨
df['BB_upper'] = df['BB_middle'] + num_std * rolling_std
df['BB_lower'] = df['BB_middle'] - num_std * rolling_std
# 计算带宽
df['BB_width'] = (df['BB_upper'] - df['BB_lower']) / df['BB_middle']
# 计算价格位置(%B)
df['BB_pct'] = (df['Close'] - df['BB_lower']) / (df['BB_upper'] - df['BB_lower'])
return df
# 使用示例
df = calculate_bollinger_bands(df)
布林带的应用
突破信号:价格触及上轨可能超买,触及下轨可能超卖。但需要注意,在强趋势中价格可能持续沿轨道运行。
带宽收缩:带宽收窄表示波动率降低,可能预示大行情即将来临。
回归中轨:价格倾向于回归中轨,可以在触及上下轨后反向操作。
def bollinger_signal(df):
"""
布林带交易信号
返回:
信号:1买入,-1卖出,0持有
"""
signal = pd.Series(0, index=df.index)
# 价格触及下轨买入
signal[df['Close'] <= df['BB_lower']] = 1
# 价格触及上轨卖出
signal[df['Close'] >= df['BB_upper']] = -1
return signal
其他常用指标
ATR(平均真实波幅)
ATR衡量市场波动性,常用于止损和仓位管理。
def calculate_atr(df, window=14):
"""
计算ATR(Average True Range)
参数:
df: 包含High, Low, Close的DataFrame
window: ATR周期
返回:
ATR序列
"""
high = df['High']
low = df['Low']
close = df['Close'].shift(1)
# 计算真实波幅
tr1 = high - low
tr2 = abs(high - close)
tr3 = abs(low - close)
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
atr = tr.rolling(window=window).mean()
return atr
KDJ指标
KDJ是超买超卖类指标,源自随机指标。
def calculate_kdj(df, n=9, m1=3, m2=3):
"""
计算KDJ指标
参数:
df: 包含High, Low, Close的DataFrame
n: RSV周期
m1: K值平滑周期
m2: D值平滑周期
返回:
包含K, D, J的DataFrame
"""
df = df.copy()
# 计算RSV
low_n = df['Low'].rolling(window=n).min()
high_n = df['High'].rolling(window=n).max()
df['RSV'] = (df['Close'] - low_n) / (high_n - low_n) * 100
# 计算K和D
df['K'] = df['RSV'].ewm(alpha=1/m1, adjust=False).mean()
df['D'] = df['K'].ewm(alpha=1/m2, adjust=False).mean()
# 计算J
df['J'] = 3 * df['K'] - 2 * df['D']
return df
使用TA-Lib计算指标
TA-Lib是专业的技术分析库,包含150多种技术指标,计算效率远高于纯Python实现。
import talib
# 移动平均线
df['SMA_20'] = talib.SMA(df['Close'], timeperiod=20)
df['EMA_20'] = talib.EMA(df['Close'], timeperiod=20)
# MACD
df['DIF'], df['DEA'], df['MACD'] = talib.MACD(df['Close'],
fastperiod=12,
slowperiod=26,
signalperiod=9)
# RSI
df['RSI_14'] = talib.RSI(df['Close'], timeperiod=14)
# 布林带
df['BB_upper'], df['BB_middle'], df['BB_lower'] = talib.BBANDS(
df['Close'], timeperiod=20, nbdevup=2, nbdevdn=2)
# ATR
df['ATR_14'] = talib.ATR(df['High'], df['Low'], df['Close'], timeperiod=14)
# KDJ
df['K'], df['D'] = talib.STOCH(df['High'], df['Low'], df['Close'],
fastk_period=9, slowk_period=3, slowd_period=3)
df['J'] = 3 * df['K'] - 2 * df['D']
# 成交量指标
df['OBV'] = talib.OBV(df['Close'], df['Volume'])
# 动量指标
df['MOM'] = talib.MOM(df['Close'], timeperiod=10)
# 波动率指标
df['NATR'] = talib.NATR(df['High'], df['Low'], df['Close'], timeperiod=14)
指标可视化
import matplotlib.pyplot as plt
def plot_indicators(df, start_date=None, end_date=None):
"""
绘制价格和技术指标
"""
if start_date:
df = df[df.index >= start_date]
if end_date:
df = df[df.index <= end_date]
fig, axes = plt.subplots(4, 1, figsize=(14, 12), sharex=True)
# 价格和均线
axes[0].plot(df.index, df['Close'], label='Close', linewidth=1)
axes[0].plot(df.index, df['SMA_20'], label='SMA 20', linewidth=1)
axes[0].plot(df.index, df['SMA_60'], label='SMA 60', linewidth=1)
axes[0].set_ylabel('Price')
axes[0].legend()
axes[0].set_title('Price and Moving Averages')
# MACD
axes[1].bar(df.index, df['MACD'], label='MACD', color=['g' if x >= 0 else 'r' for x in df['MACD']])
axes[1].plot(df.index, df['DIF'], label='DIF', linewidth=1)
axes[1].plot(df.index, df['DEA'], label='DEA', linewidth=1)
axes[1].axhline(y=0, color='black', linestyle='-', linewidth=0.5)
axes[1].set_ylabel('MACD')
axes[1].legend()
# RSI
axes[2].plot(df.index, df['RSI_14'], label='RSI 14', linewidth=1)
axes[2].axhline(y=70, color='r', linestyle='--', linewidth=0.5)
axes[2].axhline(y=30, color='g', linestyle='--', linewidth=0.5)
axes[2].axhline(y=50, color='black', linestyle='-', linewidth=0.5)
axes[2].set_ylabel('RSI')
axes[2].set_ylim(0, 100)
axes[2].legend()
# 布林带
axes[3].plot(df.index, df['Close'], label='Close', linewidth=1)
axes[3].plot(df.index, df['BB_upper'], label='Upper', linestyle='--', linewidth=1)
axes[3].plot(df.index, df['BB_middle'], label='Middle', linewidth=1)
axes[3].plot(df.index, df['BB_lower'], label='Lower', linestyle='--', linewidth=1)
axes[3].fill_between(df.index, df['BB_upper'], df['BB_lower'], alpha=0.1)
axes[3].set_ylabel('Price')
axes[3].legend()
plt.tight_layout()
plt.show()
# 使用示例
plot_indicators(df, '2023-01-01', '2023-12-31')
小结
本章详细介绍了量化交易中常用的技术指标,包括移动平均线、MACD、RSI、布林带等。这些指标各有特点:
- 移动平均线适合趋势跟踪
- MACD结合了趋势和动量
- RSI适合判断超买超卖
- 布林带反映价格波动范围
在实际应用中,建议结合多个指标综合判断,避免单一指标的局限性。同时要注意,技术指标都是基于历史数据计算的,存在一定滞后性,不能保证未来收益。下一章将学习如何使用Backtrader框架进行策略回测。