Skip to content

如何用 Python 计算量化技术指标

Published: at 00:00

背景

在量化交易程序的开发过程中,技术指标的计算是一个绕不开的环节。常见的指标如 MA(移动平均线)KDJ(随机指标)RSI(相对强弱指数) 等,几乎是量化策略的“基础工具箱”。

很早之前,我在网上学习过这些指标的原理和实现方法。本文旨在对这些概念和计算方法做一个整理和记录:一方面是工作中的实际需求,另一方面也是作为再次学习时的备忘。

需要特别说明的是,本文 不涉及指标的具体应用场景和使用策略。原因有二:其一,每个人对指标的理解和使用方法可能不同;其二,如果展开讲述,篇幅会非常长。此外,文中可能存在不完善或不严谨的地方,还请多多包涵。

说明

在 Python 中,计算大部分量化指标并不需要从零实现。我们通常会借助 TA-Lib(全称 Technical Analysis Library)这个功能强大的库。它几乎涵盖了所有常用技术指标,如 MA、KDJ、RSI、MACD 等,只需几行代码即可直接得到计算结果,非常适合量化交易的快速开发。

在实际使用中,需要注意的是,有些指标的计算结果可能与行情软件上显示的略有差异,这时可能需要调整相关参数,或者自行进行一些处理以保证一致性。

数据准备

技术指标的计算需要有一份基础行情数据。数据的获取方式因人而异,可以来自交易所、券商 API、第三方数据平台,或者网络上的公开数据。我这里使用的是 螺纹钢(RB) 的日线行情,时间区间为 2023-03-01 至 2025-08-15

在后续的示例中,我主要会用到 Pandas(用于数据处理)和 TA-Lib(用于指标计算)。这两个库我是用 uv add pandas Ta-Lib 来安装,如果没有使用 uv,可以直接通过 pip install pandas Ta-Lib 来安装试试。

代码

import pandas as pd
import talib

rb_df = pd.read_csv('SHFE.RB_1d.csv', index_col=0, parse_dates=True)
rb_df.index = rb_df.index.strftime('%Y-%m-%d')
rb_df.sort_index(ascending=True, inplace=True)
rb_df.tail()

图示

[Pasted image 20250821011046.png]

技术指标

MA

说明
公式
周期为N的移动平均线=N根K线收价盘之和N周期为N的移动平均线 = \frac{\text{N根K线收价盘之和}}{N}
代码
# MA
ma = talib.MA(rb_df.close, timeperiod=30)
ma.tail()

# EMA
from talib import MA_Type
ema = talib.MA(rb_df.close, timeperiod=30, matype=MA_Type.EMA)
ema.tail()
例子

[Pasted image 20250821012300.png]

MACD

说明
公式
  1. 快线DIF 快线DIF=12EMA26EMA快线DIF = \text{12EMA} - \text{26EMA}
  2. 慢线DEA = 快线DIF的9EMA 慢线DEA=快线DIF的9EMA慢线DEA = \text{快线DIF的9EMA}
  3. 能量柱 能量柱=(快线DIF慢线DEA)×n能量柱 = (\text{快线DIF} - \text{慢线DEA}) \times {\text{n}}
代码
# MACD
diff, dea, macd = talib.MACD(rb_df.close, fastperiod=12, slowperiod=26, signalperiod=9)
macd_df = pd.DataFrame({
    'diff': diff,
    'dea': dea,
    'macd': macd * 2
}, index=diff.index)

macd_df.tail()
例子

[Pasted image 20250821013001.png]

KDJ

说明
公式
  1. RSV,首先要计算 RSV未成熟随机值 RSV=当前收盘价近9根K线最低价近9根K线最高价近9根K线最低价×100RSV = \frac{\text{当前收盘价} - \text{近9根K线最低价}}{\text{近9根K线最高价} - \text{近9根K线最低价}} \times 100 即: RSV=涨幅振幅×100RSV = \frac{\text{涨幅}}{\text{振幅}} \times 100
  2. 计算 K 值 k=前一天K值(没有则为50)×23+当前RSV×13k = \text{前一天K值(没有则为50)} \times \frac{2}{3} + \text{当前RSV} \times \frac{1}{3}
  3. 计算 D 值 d=前一天D值(没有则为50)×23+当前K值×13d = \text{前一天D值(没有则为50)} \times \frac{2}{3} + \text{当前K值} \times \frac{1}{3}
  4. 计算 J 值 J=3×K2×DJ = 3 \times K - 2 \times D
代码
k, d = talib.STOCH(rb_df.high, rb_df.low, rb_df.close, fastk_period=9, slowk_period=3, slowd_period=3)
j = 3 * k - 2 * d
kdj_df = pd.DataFrame({
    'K': k,
    'D': d,
    'J': j,
})

kdj_df.tail(10)
例子

[Pasted image 20250821015705.png]

RSI

说明
公式
RSI=近14根K线阳线涨幅之和近14根K线阳线涨幅之和+近14根K线阴线跌幅之和的绝对值×100RSI = \frac{\text{近14根K线阳线涨幅之和}}{\text{近14根K线阳线涨幅之和}+\text{近14根K线阴线跌幅之和的绝对值}} \times 100

即:

RSI=上涨的总波动总波动RSI = \frac{上涨的总波动}{总波动}
代码
rsi = talib.RSI(rb_df.close, timeperiod=14)
rsi.tail()
例子

[Pasted image 20250821020323.png]

ATR

说明
公式
  1. 计算TR TR=max(最高价最低价,最高价前收盘价,前收盘价最低价)TR = \max(\text{最高价} - \text{最低价}, \text{最高价} - \text{前收盘价}, \text{前收盘价} - \text{最低价})
  2. 计算ATR ATR=近期N根K线TR值的求和平均ATR = \text{近期N根K线TR值的求和平均}
代码
atr = talib.ATR(rb_df.high, rb_df.low, rb_df.close, timeperiod=14)
atr.tail()
例子

[Pasted image 20250821020751.png]

BOLL

说明
公式
  1. 中轨 中轨=N日的移动平均线中轨 = N日的移动平均线
  2. 上轨 上轨=中轨+2倍标准差上轨 = 中轨 + 2倍标准差
  3. 下轨 下轨=中轨2倍标准差下轨 = 中轨 - 2倍标准差
代码
# BOLL
upper, middle, lower = talib.BBANDS(rb_df.close, timeperiod=14)
boll_df = pd.DataFrame({
    'upper': upper,
    'middle': middle,
    'lower': lower,
}, index=upper.index)

boll_df.tail()
例子

[Pasted image 20250821021117.png]

OBV

说明
公式
OBVt=OBVt1+{Volumet,如果 Closet>Closet1Volumet,如果 Closet<Closet10,如果 Closet=Closet1OBV_t = OBV_{t-1} + \begin{cases} \text{Volume}_t, & \text{如果 } \text{Close}_t > \text{Close}_{t-1} \\ -\text{Volume}_t, & \text{如果 } \text{Close}_t < \text{Close}_{t-1} \\ 0, & \text{如果 } \text{Close}_t = \text{Close}_{t-1} \end{cases}
代码
# OBV
obv = talib.OBV(rb_df.close, rb_df.volume)
obv.tail()
例子

[Pasted image 20250821021419.png]