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.fast_bsp import FastBspBuilderMixin 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, FastBspBuilderMixin, IncrementalBuilderMixin): def __init__(self, df=None, interval=0, timeframe=None, lean=False): """lean=True 只构建到中枢,跳过线段/走势中枢/MACD 状态机。 研究与实盘只吃 bi_list → 中枢 → fast_bsp 这条链;线段、zs、big_zs 和整套 MACD 背驰状态机是 web 展示与 bsp_list 才用的。实测这些占全量构建的约四成。 注意 lean 下 bsp_list/seg_list/chanmacd 均为空,**不要给 web 用**。 """ self.lean = lean if df is not None: self.init_TF_DF(df, interval, timeframe, lean=lean) def init_TF_DF(self, df, interval, timeframe, lean=False): self.lean = lean 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.fast_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) if self.lean: self.big_zs_list = [] self.chanmacd = None return 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