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>
84 lines
3.0 KiB
Python
84 lines
3.0 KiB
Python
from datetime import timedelta
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
from pandas import DataFrame
|
|
from chanlun.pipeline.resample import resample_to_interval
|
|
|
|
from chanlun.core.ChanBI import ChanBI
|
|
from chanlun.core.ChanBIZS import ChanBIZS
|
|
from chanlun.core.ChanBSP import ChanBSP
|
|
from chanlun.core.ChanEnum import (
|
|
Chan_BI_DIR,
|
|
Chan_BSP_DIR,
|
|
Chan_BSP_TYPE,
|
|
Chan_FX_TYPE,
|
|
Chan_K_DIR,
|
|
Chan_KLC_FX,
|
|
Chan_KLC_STATE,
|
|
Chan_KLINE_DIR,
|
|
Chan_KLU_PATTERN,
|
|
Chan_PRICE_TREND,
|
|
Chan_SEG_DIR,
|
|
Chan_ZS_DIR,
|
|
)
|
|
from chanlun.core.ChanKLC import ChanKLC
|
|
from chanlun.core.ChanKLU import ChanKLU
|
|
from chanlun.core.ChanSBI import ChanSBI
|
|
from chanlun.core.ChanSEG import ChanSEG
|
|
from chanlun.core.ChanZS import ChanZS, ChanZS_Big
|
|
from chanlun.indicators.ChanMACD import ChanMACD
|
|
from chanlun.pipeline.builders.bi import BiBuilderMixin
|
|
from chanlun.pipeline.builders.bsp import BspBuilderMixin
|
|
from chanlun.pipeline.builders.incremental import IncrementalBuilderMixin
|
|
from chanlun.pipeline.builders.indicators import IndicatorsBuilderMixin
|
|
from chanlun.pipeline.builders.kline import KlineBuilderMixin
|
|
from chanlun.pipeline.builders.seg import SegBuilderMixin
|
|
from chanlun.pipeline.builders.zs import ZsBuilderMixin
|
|
|
|
class TF_DF(IndicatorsBuilderMixin, KlineBuilderMixin, BiBuilderMixin, SegBuilderMixin, ZsBuilderMixin, BspBuilderMixin, IncrementalBuilderMixin):
|
|
def __init__(self, df=None, interval=0, timeframe=None):
|
|
if df is not None:
|
|
self.init_TF_DF(df, interval, timeframe)
|
|
def init_TF_DF(self, df, interval, timeframe):
|
|
self.timeframe = timeframe
|
|
self.interval = interval
|
|
# 检查 DataFrame 是否为空或没有 date 列
|
|
if df is None or df.empty:
|
|
raise ValueError(f"DataFrame for {timeframe} is empty. Please download data first.")
|
|
if 'date' not in df.columns:
|
|
raise ValueError(f"DataFrame for {timeframe} missing 'date' column. Columns: {df.columns.tolist()}")
|
|
# interval=1 时不需要重采样
|
|
if interval == 1:
|
|
self.dataframe = df.copy()
|
|
else:
|
|
self.dataframe = resample_to_interval(df, interval)
|
|
#print(self.timeframe, len(self.dataframe))
|
|
self.dataframe = self.add_indicators(self.dataframe)
|
|
self.klu_list = []
|
|
self.klc_list = []
|
|
self.bi_list = []
|
|
self.zs_list = []
|
|
self.bi_zs_list = []
|
|
self.bsp_list = []
|
|
self.seg_list = []
|
|
self.klc_fx_list = []
|
|
self.klu_list = self.cal_kl_data(self.dataframe)
|
|
self.klc_list = self.get_klc_list(self.klu_list)
|
|
self.bi_list = self.cal_bi_list(self.klc_list)
|
|
self.bi_zs_list = self.cal_bi_zs_list_pure(self.bi_list)
|
|
self.seg_list = self.get_seg_list(self.bi_list)
|
|
self.zs_list = self.get_zs_list(self.bi_list, self.seg_list)
|
|
self.big_zs_list = self.get_big_zs_list(self.zs_list)
|
|
# get_klc_list 内已算过 ChanMACD,直接复用
|
|
self.chanmacd = getattr(self, '_last_chan_macd', None)
|
|
if self.chanmacd is None:
|
|
self.chanmacd = ChanMACD(self.klu_list)
|
|
self.klu_list = self.chanmacd.klu_list
|
|
|
|
|
|
def get_current_klc(self):
|
|
if len(self.klc_list) > 0:
|
|
return self.klc_list[-2]
|
|
return None
|