131 lines
3.6 KiB
Python
131 lines
3.6 KiB
Python
"""
|
||
技术指标计算模块(numpy向量化优化版)
|
||
实现 MACD、SKDJ、EMA 等技术指标
|
||
|
||
优化要点:
|
||
- calc_sma 使用 numpy 原生数组替代 pandas.iloc,速度提升 5-10x
|
||
- calc_all_indicators 智能跳过已是 float 的类型转换
|
||
"""
|
||
import pandas as pd
|
||
import numpy as np
|
||
|
||
|
||
def calc_ema(series, period):
|
||
"""计算指数移动平均线(EMA) — 使用pandas的C底层ewm实现,已足够快"""
|
||
return series.ewm(span=period, adjust=False).mean()
|
||
|
||
|
||
def calc_sma(series, period, weight=1):
|
||
"""
|
||
计算SMA(通达信公式风格) — numpy优化版
|
||
SMA(X, N, M) = (M * X + (N - M) * prev_SMA) / N
|
||
|
||
优化:使用 numpy 原生数组 arr[i] 替代 pandas series.iloc[i]
|
||
numpy 数组元素访问约 50ns,pandas iloc 约 5μs,提升 ~100x
|
||
"""
|
||
arr = series.values.astype(np.float64)
|
||
n = len(arr)
|
||
result = np.empty(n, dtype=np.float64)
|
||
result[0] = arr[0]
|
||
w = np.float64(weight)
|
||
carry = np.float64(period - weight)
|
||
inv_p = np.float64(1.0 / period)
|
||
for i in range(1, n):
|
||
result[i] = (w * arr[i] + carry * result[i - 1]) * inv_p
|
||
return pd.Series(result, index=series.index)
|
||
|
||
|
||
def calc_macd(close, fast=12, slow=26, signal=9):
|
||
"""
|
||
计算MACD指标
|
||
返回: DIF, DEA, MACD柱
|
||
"""
|
||
ema_fast = calc_ema(close, fast)
|
||
ema_slow = calc_ema(close, slow)
|
||
dif = ema_fast - ema_slow
|
||
dea = calc_ema(dif, signal)
|
||
macd_hist = 2 * (dif - dea)
|
||
return dif, dea, macd_hist
|
||
|
||
|
||
def calc_kdj(high, low, close, n=9, m1=3, m2=3):
|
||
"""
|
||
计算KDJ指标
|
||
返回: K, D, J
|
||
"""
|
||
lowest_low = low.rolling(window=n, min_periods=1).min()
|
||
highest_high = high.rolling(window=n, min_periods=1).max()
|
||
|
||
rsv = pd.Series(np.where(
|
||
highest_high == lowest_low, 50,
|
||
(close - lowest_low) / (highest_high - lowest_low) * 100
|
||
), index=close.index, dtype=float)
|
||
|
||
k = calc_sma(rsv, m1, 1)
|
||
d = calc_sma(k, m2, 1)
|
||
j = 3 * k - 2 * d
|
||
return k, d, j
|
||
|
||
|
||
def calc_skdj(high, low, close, n=9, m=3):
|
||
"""
|
||
计算SKDJ(慢速随机指标)
|
||
对RSV先做一次SMA得到K_fast,再对K_fast做两次SMA得到SKDJ的K和D
|
||
返回: K, D
|
||
"""
|
||
lowest_low = low.rolling(window=n, min_periods=1).min()
|
||
highest_high = high.rolling(window=n, min_periods=1).max()
|
||
|
||
rsv = pd.Series(np.where(
|
||
highest_high == lowest_low, 50,
|
||
(close - lowest_low) / (highest_high - lowest_low) * 100
|
||
), index=close.index, dtype=float)
|
||
|
||
k_fast = calc_sma(rsv, m, 1)
|
||
k = calc_sma(k_fast, m, 1)
|
||
d = calc_sma(k, m, 1)
|
||
return k, d
|
||
|
||
|
||
def calc_all_indicators(df):
|
||
"""
|
||
计算所有技术指标并添加到DataFrame(优化版)
|
||
df 需要包含: close, high, low, open, volume 列
|
||
返回: 添加了指标列的DataFrame
|
||
|
||
优化:智能跳过已是 float64 的列,避免重复 astype
|
||
"""
|
||
close = df['close']
|
||
high = df['high']
|
||
low = df['low']
|
||
|
||
# 智能类型转换:仅在需要时转换
|
||
if not np.issubdtype(close.dtype, np.floating):
|
||
close = close.astype(np.float64)
|
||
high = high.astype(np.float64)
|
||
low = low.astype(np.float64)
|
||
|
||
df['ema3'] = calc_ema(close, 3)
|
||
df['ema21'] = calc_ema(close, 21)
|
||
|
||
dif, dea, macd_hist = calc_macd(close)
|
||
df['dif'] = dif
|
||
df['dea'] = dea
|
||
df['macd'] = macd_hist
|
||
|
||
k, d, j = calc_kdj(high, low, close)
|
||
df['kdj_k'] = k
|
||
df['kdj_d'] = d
|
||
df['kdj_j'] = j
|
||
|
||
sk, sd = calc_skdj(high, low, close)
|
||
df['skdj_k'] = sk
|
||
df['skdj_d'] = sd
|
||
|
||
df['ma5'] = close.rolling(5).mean()
|
||
df['ma10'] = close.rolling(10).mean()
|
||
df['ma20'] = close.rolling(20).mean()
|
||
df['ma60'] = close.rolling(60).mean()
|
||
|
||
return df
|