chanlun/indicators/ta.py 接口兼容 talib.abstract,实现代码实际用到的 SMA/MA/EMA/RSI/ATR/MACD/BBANDS;chanlun/pipeline/resample.py 替代 technical.util.resample_to_interval。调用点只改 import,逻辑未动。 暖机长度与平滑种子按 TA-Lib 的约定实现,差一根 K 线就会让下游所有 笔/线段/中枢整体位移。其中 MACD 需特别处理:TA-Lib 让快慢两条 EMA 在同一根 K 线出首值,因而快线的种子取 x[slow-fast:slow] 的均值,而非 从 fastperiod-1 一路递推——两者在百元价位上相差约 0.17。 BBANDS 是有意的分歧:TA-Lib 用 sumsq/n - mean² 求方差,短窗口远离零 时灾难性抵消(timeperiod=2 误差 8.7e-7),本实现用 rolling std,对 50 位精度基准误差为 0。项目实际使用的周期两者一致到 1e-10。 顺带清理 12 个文件中 16 处从未调用的 talib/technical 导入。 验证:9440 组随机对拨;真实 K 线端到端比对 add_indicators 全部 33 个 指标列,NaN 模式一致、MACD 柱符号 100% 相同;屏蔽两个包后 60 个模块 均可导入。新增 test_ta_compat.py 将输出逐 bar 钉在 TA-Lib 上,但该文件 在 TA-Lib 缺失时静默跳过,改动 ta.py 需在装有 TA-Lib 的环境复跑。 Co-authored-by: Cursor <cursoragent@cursor.com>
104 lines
4.1 KiB
Python
104 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from chanlun.indicators import ta
|
|
from . import state
|
|
|
|
def add_indicators(df):
|
|
macd = ta.MACD(df, fastperiod=state.macd_fast_period, slowperiod=state.macd_slow_period, signalperiod=state.macd_signal_period)
|
|
|
|
df['macd'] = macd['macd']
|
|
df['macdsignal'] = macd['macdsignal']
|
|
df['macdhist'] = macd['macdhist']
|
|
df['ma5'] = (ta.MA(df, timeperiod=5)).fillna(0)
|
|
df['ma10'] = (ta.MA(df, timeperiod=10)).fillna(0)
|
|
df['ma30'] = (ta.EMA(df, timeperiod=30)).fillna(0)
|
|
df['ma250'] = (ta.MA(df, timeperiod=250)).fillna(0)
|
|
# 新增 EMA 指标
|
|
df['ema5'] = (ta.EMA(df, timeperiod=5)).fillna(0)
|
|
df['ema10'] = (ta.EMA(df, timeperiod=10)).fillna(0)
|
|
df['ema24'] = (ta.EMA(df, timeperiod=24)).fillna(0)
|
|
df['ema52'] = (ta.EMA(df, timeperiod=52)).fillna(0)
|
|
df['ema26'] = (ta.EMA(df, timeperiod=26)).fillna(0)
|
|
df['ema13'] = (ta.EMA(df, timeperiod=13)).fillna(0)
|
|
df['ema7'] = (ta.EMA(df, timeperiod=7)).fillna(0)
|
|
df['ema104'] = (ta.EMA(df, timeperiod=104)).fillna(0)
|
|
df['ema156'] = (ta.EMA(df, timeperiod=156)).fillna(0)
|
|
df['ema208'] = (ta.EMA(df, timeperiod=208)).fillna(0)
|
|
# 常用SMA 24/52
|
|
try:
|
|
df['sma24'] = (ta.SMA(df, timeperiod=24)).fillna(0)
|
|
df['sma52'] = (ta.SMA(df, timeperiod=52)).fillna(0)
|
|
except Exception:
|
|
df['sma24'] = 0
|
|
df['sma52'] = 0
|
|
df['rsi'] = ta.RSI(df, timeperiod=14)
|
|
|
|
# 计算布林带 (当前周期 - 20周期,2标准差)
|
|
bb = ta.BBANDS(df, timeperiod=365, nbdevup=3.0, nbdevdn=3.0, matype=0)
|
|
df['bb_upper'] = bb['upperband'].fillna(0)
|
|
df['bb_middle'] = bb['middleband'].fillna(0)
|
|
df['bb_lower'] = bb['lowerband'].fillna(0)
|
|
bb30 = ta.BBANDS(df, timeperiod=41, nbdevup=2.3, nbdevdn=2.3, matype=0)
|
|
#bb30 = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
|
df['bbup30'] = bb30['upperband'].fillna(0)
|
|
df['bblow30'] = bb30['lowerband'].fillna(0)
|
|
bb302 = ta.BBANDS(df, timeperiod=41, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
|
#bb302 = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
|
df['bbup302'] = bb302['upperband'].fillna(0)
|
|
df['bblow302'] = bb302['lowerband'].fillna(0)
|
|
# 计算次周期布林带 (14周期,2标准差)
|
|
bb_element = ta.BBANDS(df, timeperiod=14, nbdevup=2.0, nbdevdn=2.0, matype=0)
|
|
df['element_bb_upper'] = bb_element['upperband'].fillna(0)
|
|
df['element_bb_middle'] = bb_element['middleband'].fillna(0)
|
|
df['element_bb_lower'] = bb_element['lowerband'].fillna(0)
|
|
|
|
df['macd'] = df['macd'].fillna(0)
|
|
df['macdsignal'] = df['macdsignal'].fillna(0)
|
|
df['macdhist'] = df['macdhist'].fillna(0)
|
|
df['ma5'] = df['ma5'].fillna(0)
|
|
df['ma10'] = df['ma10'].fillna(0)
|
|
df['ma30'] = df['ma30'].fillna(0)
|
|
df['ma250'] = df['ma250'].fillna(0)
|
|
df['ema5'] = df['ema5'].fillna(0)
|
|
df['ema10'] = df['ema10'].fillna(0)
|
|
df['ema24'] = df['ema24'].fillna(0)
|
|
df['ema52'] = df['ema52'].fillna(0)
|
|
df['sma24'] = df['sma24'].fillna(0)
|
|
df['sma52'] = df['sma52'].fillna(0)
|
|
df['rsi'] = df['rsi'].fillna(0)
|
|
df['avg_volume'] = df['volume'].rolling(10).mean()
|
|
# 计算量比,避免产生Infinity值
|
|
df['volume_ratio'] = df['volume'] / df['avg_volume']
|
|
# 填充缺失值(前N根K线)
|
|
df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
|
|
df['avg_volume'] = df['avg_volume'].fillna(0)
|
|
|
|
# 处理Infinity和-Infinity值
|
|
df['volume_ratio'] = df['volume_ratio'].replace([float('inf'), float('-inf')], 1.0)
|
|
|
|
# 计算ATR (Average True Range) - 14周期
|
|
df['atr'] = ta.ATR(df, timeperiod=14)
|
|
df['atr'] = df['atr'].fillna(0)
|
|
bb2633 = ta.BBANDS(df, timeperiod=26, nbdevup=3.0, nbdevdn=3.0, matype=0)
|
|
bbp2633 = (df['close'] - bb2633['lowerband']) / (bb2633['upperband'] - bb2633['lowerband'])
|
|
df['bb2633upper'] = bb2633['upperband'].fillna(0)
|
|
df['bb2633lower'] = bb2633['lowerband'].fillna(0)
|
|
df['bbp2633'] = bbp2633.fillna(0)
|
|
df['bb2633middle'] = bb2633['middleband'].fillna(0)
|
|
return df
|
|
|
|
def calculate_macd(df):
|
|
"""计算MACD指标"""
|
|
exp1 = df['close'].ewm(span=state.macd_fast_period, adjust=False).mean()
|
|
exp2 = df['close'].ewm(span=state.macd_slow_period, adjust=False).mean()
|
|
macd = exp1 - exp2
|
|
signal = macd.ewm(span=state.macd_signal_period, adjust=False).mean()
|
|
histogram = macd - signal
|
|
|
|
return {
|
|
'macd': macd.tolist(),
|
|
'signal': signal.tolist(),
|
|
'histogram': histogram.tolist()
|
|
}
|
|
|