Overlap:KAMA(考夫曼自适应移动平均线)技术指标详解
一、KAMA的定义
KAMA(Kaufman’s Adaptive Moving Average,考夫曼自适应移动平均线) 是由知名量化投资专家佩里·考夫曼(Perry Kaufman)开发的一种创新移动平均线。它的核心特点是:根据市场噪音或波动率,自动调整自身的平滑速度。
核心设计理念
传统移动平均线的主要矛盾在于:趋势行情中需要快速响应(短周期),震荡行情中需要足够平滑(长周期),但单一参数无法兼顾两种场景。
考夫曼的解决方案是引入效率比率(Efficiency Ratio, ER)——衡量价格变化的“方向性”与“总波动性”之比:
- 当市场呈现强趋势时(ER趋近于1):KAMA变得灵敏,快速跟踪价格变化
- 当市场处于震荡时(ER趋近于0):KAMA变得平滑,有效过滤噪音
这种自适应机制使KAMA被评价为“智能”移动平均线,在趋势跟踪和噪音过滤之间取得了更好的平衡。
KAMA与传统移动平均线的对比
| 平滑速度 | 根据波动率自适应调整 | 固定 | 固定 |
| 噪音过滤能力 | 强(波动大时自动平滑) | 较弱 | 中等 |
| 趋势跟踪速度 | 快(趋势明确时快速响应) | 中等 | 慢 |
二、KAMA的计算方法
KAMA的计算主要分为三步:效率比率(ER)、平滑常数(SC)和递归计算。
1. 效率比率(Efficiency Ratio, ER)
ER衡量价格运动的“效率”——价格变化的方向性程度与总波动性的比值。考夫曼推荐使用10周期作为ER的计算周期。
价格变化(方向性):
Change=∣Closet−Closet−10∣
\\mathrm{Change} = |\\mathrm{Close}_t – \\mathrm{Close}_{t-10}|
Change=∣Closet−Closet−10∣
波动性(总移动距离):
Volatility=∑i=t−9t∣Closei−Closei−1∣
\\mathrm{Volatility} = \\sum_{i=t-9}^t|\\mathrm{Close}_i – \\mathrm{Close}_{i-1}|
Volatility=i=t−9∑t∣Closei−Closei−1∣
效率比率:
ER=ChangeVolatility
\\mathrm{ER} = \\frac{\\mathrm{Change}}{\\mathrm{Volatility}}
ER=VolatilityChange
ER的取值范围在0到1之间:
- ER=1:价格连续10个周期同向移动(极强的趋势)
- ER=0:价格在10个周期内没有净变化(横盘震荡)
2. 平滑常数(Smoothing Constant, SC)
SC将ER转化为KAMA的平滑系数。考夫曼推荐的最快周期为2,最慢周期为30。
首先计算最快和最慢EMA的权重系数:
fastest=2/(fast+1)=2/(2+1)≈0.6667slowest=2/(slow+1)=2/(30+1)≈0.0645
\\begin{aligned}
\\mathrm{fastest} &= 2 / (\\mathrm{fast} + 1) = 2 / (2 + 1) &\\approx 0.6667 \\\\[1.5ex]
\\mathrm{slowest} &= 2 / (\\mathrm{slow} + 1) = 2 / (30 + 1) &\\approx 0.0645
\\end{aligned}
fastestslowest=2/(fast+1)=2/(2+1)=2/(slow+1)=2/(30+1)≈0.6667≈0.0645
然后计算自适应平滑常数:
SC=[ER×(fastest−slowest)+slowest]2
\\mathrm{SC = [ER \\times (fastest – slowest) + slowest]^2}
SC=[ER×(fastest−slowest)+slowest]2
当ER高(趋势强)时,SC趋近于fastest(约0.6667),KAMA变得灵敏;当ER低(震荡市)时,SC趋近于slowest(约0.0645),KAMA变得平滑。
3. KAMA递归计算
第一个KAMA值使用简单移动平均作为初始值,后续按以下递推公式更新:
KAMAt=KAMAt−1+SCt×(Pricet−KAMAt−1)
\\mathrm{KAMA}_t = \\mathrm{KAMA}_{t-1} + \\mathrm{SC}_t × (\\mathrm{Price}_t – \\mathrm{KAMA}_{t-1})
KAMAt=KAMAt−1+SCt×(Pricet−KAMAt−1)
4. 参数说明
| length | 10 | ER计算周期,控制效率比率的敏感度 |
| fast | 2 | 最快EMA周期(趋势明确时使用) |
| slow | 30 | 最慢EMA周期(震荡时使用) |
三、KAMA的使用方法
1. 价格穿越信号——基础用法
价格与KAMA的穿越是最直观的交易信号:
| 买入信号 | 价格从下方向上穿越KAMA | 价格动能转强,可能进入上升趋势 |
| 卖出信号 | 价格从上方向下穿越KAMA | 价格动能转弱,可能进入下降趋势 |
实战提示:简单穿越系统可能产生较多假信号。考夫曼建议在KAMA周围设置一个小型带状区域来过滤噪音,或要求价格穿越后持有一定天数再确认信号。
2. KAMA方向判断趋势
KAMA自身的上升或下降方向是判断主趋势的有效工具:
| KAMA持续上升 | 上升趋势,寻求买入机会 |
| KAMA持续下降 | 下降趋势,寻求卖出机会 |
| KAMA走平 | 趋势可能减弱或进入盘整 |
3. 长短周期组合策略
使用长短两条KAMA配合可以提高信号质量:
- 长期KAMA(如参数10,5,30):判断主趋势方向
- 短期KAMA(如参数10,2,30):寻找具体入场点
当长期KAMA上升时,只关注价格上穿短期KAMA的买入信号;当长期KAMA下降时,只关注价格下穿短期KAMA的卖出信号。
四、使用pandas_ta计算KAMA
1. 函数参数
pandas_ta.overlap.kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs)
参数详解:
| close | pd.Series | 必需 | 收盘价序列 |
| length | int | 10 | ER计算周期 |
| fast | int | 2 | 最快EMA周期 |
| slow | int | 30 | 最慢EMA周期 |
| drift | int | 1 | 价格变化步长 |
| offset | int | 0 | 结果偏移周期数 |
2. 示例代码
import pandas as pd
import pandas_ta as ta
import numpy as np
import matplotlib.pyplot as plt
# ========== 第一步:准备数据 ==========
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', end='2024-12-31', freq='D')
n = len(dates)
# 生成带趋势和波动的价格序列
trend = np.linspace(0, 45, n)
cycle = np.sin(np.linspace(0, 6 * np.pi, n)) * 15
noise = np.random.randn(n) * 3
price_series = 100 + trend + cycle + noise
# 添加趋势变化区间
price_series = price_series.astype(float)
for i in range(300, 450):
price_series[i] = price_series[300] + (i–300) * 0.2
for i in range(450, 600):
price_series[i] = price_series[450] – (i–450) * 0.15
df = pd.DataFrame(index=dates[:n])
df['close'] = price_series[:n]
df['volume'] = np.random.randint(1000000, 25000000, n)
print("=" * 60)
print("数据预览:")
print(df.head())
print("\\n" + "=" * 60 + "\\n")
# ========== 第二步:计算KAMA ==========
# 使用默认参数 length=10, fast=2, slow=30
df['KAMA'] = ta.kama(df['close'])
print("KAMA计算结果(最近10行):")
print(df[['close', 'KAMA']].tail(10))
print("\\n" + "=" * 60 + "\\n")
# ========== 第三步:不同参数组合对比 ==========
# 标准参数 (10,2,30)
df['KAMA_std'] = ta.kama(df['close'], length=10, fast=2, slow=30)
# 更灵敏的参数 (10,2,20)
df['KAMA_fast'] = ta.kama(df['close'], length=10, fast=2, slow=20)
# 更平滑的参数 (10,5,30)
df['KAMA_smooth'] = ta.kama(df['close'], length=10, fast=5, slow=30)
print("不同参数KAMA对比(最近5行):")
print(df[['close', 'KAMA_std', 'KAMA_fast', 'KAMA_smooth']].tail())
print("\\n" + "=" * 60 + "\\n")
# ========== 第四步:计算传统均线进行对比 ==========
df['SMA_20'] = ta.sma(df['close'], length=20)
df['EMA_20'] = ta.ema(df['close'], length=20)
print("KAMA vs SMA vs EMA 对比(最近10行):")
print(df[['close', 'KAMA_std', 'SMA_20', 'EMA_20']].tail(10))
print("\\n" + "=" * 60 + "\\n")
# ========== 第五步:生成价格穿越信号 ==========
df['price_above_kama'] = df['close'] > df['KAMA_std']
df['cross_above'] = (df['price_above_kama'] == True) & (df['price_above_kama'].shift(1) == False)
df['cross_below'] = (df['price_above_kama'] == False) & (df['price_above_kama'].shift(1) == True)
df['signal'] = ''
df.loc[df['cross_above'], 'signal'] = '买入(价格上穿KAMA)'
df.loc[df['cross_below'], 'signal'] = '卖出(价格下穿KAMA)'
print("价格穿越信号统计:")
print(f"买入信号数量:{df['cross_above'].sum()}")
print(f"卖出信号数量:{df['cross_below'].sum()}")
print("\\n最近15个穿越信号:")
signals = df[df['signal'] != ''].tail(15)
if not signals.empty:
print(signals[['close', 'KAMA_std', 'signal']])
print("\\n" + "=" * 60 + "\\n")
# ========== 第六步:KAMA方向判断趋势 ==========
df['kama_slope'] = df['KAMA_std'].diff()
df['trend'] = ''
df.loc[df['kama_slope'] > 0, 'trend'] = '上升趋势'
df.loc[df['kama_slope'] < 0, 'trend'] = '下降趋势'
print("趋势分布统计:")
print(df['trend'].value_counts())
print("\\n" + "=" * 60 + "\\n")
# ========== 第七步:长短周期组合策略 ==========
# 长期KAMA(更平滑)和短期KAMA(更灵敏)
df['KAMA_long'] = ta.kama(df['close'], length=10, fast=5, slow=30)
df['KAMA_short'] = ta.kama(df['close'], length=10, fast=2, slow=30)
# 长期趋势向上时,关注短期上穿信号
df['long_up'] = df['KAMA_long'] > df['KAMA_long'].shift(5)
df['buy_filtered'] = df['long_up'] & df['cross_above']
print("长短周期组合信号统计:")
print(f"长期上升趋势中的买入信号数量:{df['buy_filtered'].sum()}")
print("\\n" + "=" * 60 + "\\n")
# ========== 第八步:策略回测 ==========
# 策略:KAMA上升时持仓多头
df['position'] = (df['kama_slope'] > 0).astype(int)
df['returns'] = df['close'].pct_change()
df['strategy_returns'] = df['position'].shift(1) * df['returns']
total_return_buyhold = (1 + df['returns']).prod() – 1
total_return_strategy = (1 + df['strategy_returns']).prod() – 1
print("=" * 60)
print("策略绩效统计(KAMA方向策略回测):")
print(f"买入持有策略总收益率:{total_return_buyhold:.2%}")
print(f"KAMA方向策略总收益率:{total_return_strategy:.2%}")
print("\\n注意:此为简化回测,仅供参考")
print("=" * 60 + "\\n")
# ========== 第九步:可视化 ==========
plt.figure(figsize=(14, 10))
plt.subplot(2, 1, 1)
plt.plot(df.index[–200:], df['close'][–200:], label='Close Price',
linewidth=1.5, color='black')
plt.plot(df.index[–200:], df['KAMA_std'][–200:], label='KAMA (10,2,30)',
linewidth=1.5, color='blue')
plt.plot(df.index[–200:], df['SMA_20'][–200:], label='SMA (20)',
linewidth=1, color='orange', linestyle='–')
plt.plot(df.index[–200:], df['EMA_20'][–200:], label='EMA (20)',
linewidth=1, color='green', linestyle=':')
plt.title('KAMA vs SMA vs EMA 对比 (Last 200 days)', fontsize=14)
plt.ylabel('Price')
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(2, 1, 2)
plt.plot(df.index[–200:], df['close'][–200:], label='Close Price',
linewidth=1, alpha=0.5, color='black')
plt.plot(df.index[–200:], df['KAMA_std'][–200:], label='KAMA (10,2,30) – 标准',
linewidth=1.5, color='blue')
plt.plot(df.index[–200:], df['KAMA_fast'][–200:], label='KAMA (10,2,20) – 灵敏',
linewidth=1, alpha=0.7)
plt.plot(df.index[–200:], df['KAMA_smooth'][–200:], label='KAMA (10,5,30) – 平滑',
linewidth=1.5, color='green')
# 标记穿越信号
buy_signals = df[df['cross_above']]
sell_signals = df[df['cross_below']]
plt.scatter(buy_signals.index[–25:], buy_signals['close'][–25:],
color='green', marker='^', s=60, label='买入信号(价格上穿)', alpha=0.8)
plt.scatter(sell_signals.index[–25:], sell_signals['close'][–25:],
color='red', marker='v', s=60, label='卖出信号(价格下穿)', alpha=0.8)
plt.title('KAMA:不同参数对比与穿越信号', fontsize=14)
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ========== 第十步:数据清洗提示 ==========
nan_count = df['KAMA_std'].isna().sum()
print(f"\\nKAMA初始NaN数量:{nan_count}")
print("原因:KAMA需要至少length个周期的数据才能计算效率比率")
print("处理建议:df_clean = df.iloc[10:].copy()")
print("\\n" + "=" * 60)
print("KAMA使用提示:")
print("1. KAMA根据市场波动自动调整灵敏度:波动大时平滑,趋势明确时灵敏")
print("2. 默认参数(10,2,30)是考夫曼推荐的标准配置")
print("3. 价格上穿KAMA是买入信号,下穿是卖出信号")
print("4. 使用长短周期KAMA组合(如长线KAMA判断趋势,短线KAMA找入场点)")
print("5. 建议在KAMA周围设置小型带状区域来过滤震荡市的假信号")
print("=" * 60)
五、总结
KAMA(考夫曼自适应移动平均线)是一种根据市场噪音水平自动调整平滑速度的智能均线,其核心价值与定位如下:
| 核心创新 | 效率比率(ER)+ 自适应平滑常数(SC),实现波动率自适应 |
| 核心公式 | KAMAt=KAMAt−1+SCt×(Pricet−KAMAt−1)\\mathrm{KAMA}_t = \\mathrm{KAMA}_{t-1} + \\mathrm{SC}_t × (\\mathrm{Price}_t – \\mathrm{KAMA}_{t-1})KAMAt=KAMAt−1+SCt×(Pricet−KAMAt−1) |
| 默认参数 | length=10, fast=2, slow=30 |
| 核心优势 | 震荡市过滤噪音、趋势市快速响应,动静皆宜 |
| 最佳应用场景 | 趋势跟踪、波动率自适应策略、多周期组合分析 |
| 主要局限 | 计算复杂度高于传统均线、参数需根据品种优化 |
实战使用三原则:


