跳到主要内容

技术指标计算

技术指标是量化交易中最基础的分析工具,通过对价格和成交量数据的数学变换,揭示市场的趋势、动量和波动特征。本章将详细介绍常用技术指标的计算原理和Python实现。

移动平均线

移动平均线是最基础的技术指标,用于平滑价格波动、识别趋势方向。

简单移动平均线(SMA)

简单移动平均线计算一定周期内价格的算术平均值。

公式:SMAn=P1+P2+...+PnnSMA_n = \frac{P_1 + P_2 + ... + P_n}{n}

其中 PiP_i 是第 ii 期的价格,nn 是周期长度。

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)

指数移动平均线对近期价格赋予更高权重,反应更灵敏。

公式:EMAt=α×Pt+(1α)×EMAt1EMA_t = \alpha \times P_t + (1-\alpha) \times EMA_{t-1}

其中 α=2n+1\alpha = \frac{2}{n+1} 是平滑因子,nn 是周期长度。

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的差值 DIF=EMA12EMA26DIF = EMA_{12} - EMA_{26}

DEA(慢线/信号线):DIF的EMA DEA=EMA9(DIF)DEA = EMA_9(DIF)

MACD柱:DIF与DEA的差值 MACD=(DIFDEA)×2MACD = (DIF - DEA) \times 2

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=1001001+RSRSI = 100 - \frac{100}{1 + RS}

其中 RS=Avg GainAvg LossRS = \frac{\text{Avg Gain}}{\text{Avg Loss}}

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日移动平均线 Middle=SMAnMiddle = SMA_n

上轨:中轨 + k倍标准差 Upper=Middle+k×σnUpper = Middle + k \times \sigma_n

下轨:中轨 - k倍标准差 Lower=Middlek×σnLower = Middle - k \times \sigma_n

通常使用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框架进行策略回测。