diff --git a/.DS_Store b/.DS_Store index 1cf9306..5b7d94d 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/ChanBI.py b/ChanBI.py index aaafaa3..c2fe292 100644 --- a/ChanBI.py +++ b/ChanBI.py @@ -37,7 +37,7 @@ class ChanBI(): def cal_macdhist(self): self.macd_hist = 0 for klc in self.klc_list: - for klu in klc.klus: + for klu in klc.klu_list: if self.dir == Chan_BI_DIR.UP and klu.macdhist > 0: self.macd_hist += klu.macdhist if self.dir == Chan_BI_DIR.DOWN and klu.macdhist < 0: diff --git a/ChanKLC.py b/ChanKLC.py index 8e8bc7d..ea82943 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -14,7 +14,7 @@ class ChanKLC(): self.low = klu.low self.dir = ddir self.index = index - self.klus = [] + self.klu_list = [] self.add_klu(klu) self.fx = Chan_FX_TYPE.UNKNOWN self.next = None @@ -49,6 +49,7 @@ class ChanKLC(): self.ema24 = klu.ema24 self.trend = Chan_PRICE_TREND.UNKNOWN self.exception = klu.exception + self.klc_dir = Chan_KLINE_DIR.UP if klu.close > klu.open else Chan_KLINE_DIR.DOWN def set_trend(self, trend): self.trend = trend def to_string(self): @@ -64,22 +65,23 @@ class ChanKLC(): #self.cal_fx() self.cal_bb_out() def add_klu(self, klu): - self.klus.append(klu) + self.klu_list.append(klu) def set_end_klu(self, klu): self.end_klu = klu self.end_time = klu.time self.close = klu.close - for klu in self.klus: + for klu in self.klu_list: if klu.separate_div > 0: self.separate_div = True if klu.continue_div: self.continue_div = klu.continue_div if klu.macd_state != Chan_MACD_STATE.UNKNOWN: self.state = klu.macd_state + self.klc_dir = Chan_KLINE_DIR.UP if self.close > self.open else Chan_KLINE_DIR.DOWN self.cal_indicators() def cal_fx(self): if self.klc_fx_type == Chan_KLC_FX.TOP1 or self.klc_fx_type == Chan_KLC_FX.TOP2: - #print(self.end_time, self.fx, self.macd, self.macdhist, len(self.klus)) + #print(self.end_time, self.fx, self.macd, self.macdhist, len(self.klu_list)) if self.state == Chan_MACD_STATE.HIGH_EMPTY and self.macd > 0: #print(self.end_time, self.state, self.macd, self.klc_fx_type) self.klc_fx_type = Chan_KLC_FX.TOP6 @@ -100,7 +102,7 @@ class ChanKLC(): if self.signal < 0 and self.macd < self.signal: self.klc_fx_type = Chan_KLC_FX.BOTTOM8 def cal_bb_out(self): - for klu in self.klus: + for klu in self.klu_list: if self.klc_fx_type == Chan_KLC_FX.TOP1 or self.klc_fx_type == Chan_KLC_FX.TOP2: #print(self.start_time, self.klc_fx_type, klu.high, klu.bb52upper, self.macd, self.next.macd, klu.time) if self.high >= klu.bb52upper and klu.bb52upper > 0 and self.next and self.high > self.next.high: @@ -112,22 +114,22 @@ class ChanKLC(): self.klc_fx_type = Chan_KLC_FX.BOTTOM4 print(self.end_time, self.klc_fx_type) def cal_indicators(self): - for index in range(1, len(self.klus)): - self.volume += self.klus[index].volume - self.rsi += self.klus[index].rsi - self.volume_ratio += self.klus[index].volume_ratio - self.macdhist += self.klus[index].macdhist - self.ema52 += self.klus[index].ema52 - self.ema24 += self.klus[index].ema24 - self.rsi = self.rsi / len(self.klus) - self.volume_ratio = self.volume_ratio / len(self.klus) - self.volume = self.volume / len(self.klus) - self.macdhist = self.macdhist / len(self.klus) - self.ema52 = self.ema52 / len(self.klus) - self.ema24 = self.ema24 / len(self.klus) - if len(self.klus) > 0: - self.macd = self.klus[-1].macd - self.signal = self.klus[-1].signal + for index in range(1, len(self.klu_list)): + self.volume += self.klu_list[index].volume + self.rsi += self.klu_list[index].rsi + self.volume_ratio += self.klu_list[index].volume_ratio + self.macdhist += self.klu_list[index].macdhist + self.ema52 += self.klu_list[index].ema52 + self.ema24 += self.klu_list[index].ema24 + self.rsi = self.rsi / len(self.klu_list) + self.volume_ratio = self.volume_ratio / len(self.klu_list) + self.volume = self.volume / len(self.klu_list) + self.macdhist = self.macdhist / len(self.klu_list) + self.ema52 = self.ema52 / len(self.klu_list) + self.ema24 = self.ema24 / len(self.klu_list) + if len(self.klu_list) > 0: + self.macd = self.klu_list[-1].macd + self.signal = self.klu_list[-1].signal self.body = abs(self.close - self.open) self.upper_shadow = self.high - max(self.close, self.open) self.lower_shadow = min(self.close, self.open) - self.low diff --git a/ChanKLU.py b/ChanKLU.py index aa5d1a5..78a2fca 100644 --- a/ChanKLU.py +++ b/ChanKLU.py @@ -35,8 +35,8 @@ class ChanKLU: self.upper_shadow = self.high - max(self.close, self.open) self.lower_shadow = min(self.close, self.open) - self.low self.body_ratio = self.body / self.range - self.upper_shadow_ratio = self.upper_shadow / self.body - self.lower_shadow_ratio = self.lower_shadow / self.body + self.upper_shadow_ratio = self.upper_shadow / self.range + self.lower_shadow_ratio = self.lower_shadow / self.range self.exception = False self.cal_exception() self.candle_dir = Chan_K_DIR.CROSS if self.close == self.open else Chan_K_DIR.BULL if self.close > self.open else Chan_K_DIR.BEAR @@ -70,6 +70,8 @@ class ChanKLU: self.macd_state = state def set_pattern(self, pattern): self.pattern = pattern + def to_string(self): + return f"{self.time} {self.candle_dir} {self.pattern}" def cal_exception(self): if self.upper_shadow_ratio > 5 or self.lower_shadow_ratio > 5: self.exception = True diff --git a/TF_DF.py b/TF_DF.py index 1a98ca0..1ce24d5 100644 --- a/TF_DF.py +++ b/TF_DF.py @@ -123,17 +123,25 @@ class TF_DF(): return klu_state_list def check_fx(self, klc): if klc.pre and klc.next: - if klc.high > klc.pre.high and klc.high > klc.next.high and klc.low > klc.pre.low and klc.low > klc.next.low: + if klc.high > klc.pre.high and klc.high > klc.next.high and klc.low > klc.pre.low and klc.low > klc.next.low and klc.next.klc_dir == Chan_KLINE_DIR.DOWN: #if (klc.close > klc.ema52 or klc.next.close > klc.next.ema52) and klc.macd > 0 and klc.macd > klc.macdhist: klc.set_fx(Chan_FX_TYPE.TOP) #print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time, klc.macd, klc.state, klc.fx, "TOP") return Chan_FX_TYPE.TOP - elif klc.low < klc.pre.low and klc.low < klc.next.low and klc.high < klc.pre.high and klc.high < klc.next.high: + elif klc.low < klc.pre.low and klc.low < klc.next.low and klc.high < klc.pre.high and klc.high < klc.next.high and klc.next.klc_dir == Chan_KLINE_DIR.UP: #if (klc.close < klc.ema52 or klc.next.close < klc.next.ema52) and klc.macd < 0 and klc.macd < klc.macdhist: klc.set_fx(Chan_FX_TYPE.BOTTOM) #print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time, klc.macd, klc.state, klc.fx, "BOTTOM") return Chan_FX_TYPE.BOTTOM return Chan_FX_TYPE.UNKNOWN + def check_fx_pattern(self, klc): + klu_list = klc.pre.klu_list + klc.klu_list + klc.next.klu_list + + self.cal_klu_pattern(klu_list) + p = "" + for klu in klu_list: + p += klu.to_string() + #print(p) def cal_volume_ratio(self, dataframe, window=10): df = dataframe.copy() # 计算过去N根K线的平均成交量 @@ -914,6 +922,7 @@ class TF_DF(): last_top = klc #print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 1") klc.set_klc_fx_type(Chan_KLC_FX.TOP1) + self.check_fx_pattern(klc) #print(klc.end_time, klc.fx, "一类卖点Sell 1") #klc.set_fx(fx) #klc.set_state("10") @@ -968,6 +977,7 @@ class TF_DF(): last_top = klc #print(klc.end_time, klc.fx, bi_list[-1].dir, "Last Top Change 2") klc.set_klc_fx_type(Chan_KLC_FX.TOP2) + self.check_fx_pattern(klc) #klc.set_state('30') bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) @@ -1040,6 +1050,7 @@ class TF_DF(): last_bottom = klc #print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 1") klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM1) + self.check_fx_pattern(klc) #print(klc.start_time, klc.fx, "一类买点Buy 1") #klc.set_state("-10") bi_list[-1].add_klc(klc) @@ -1095,6 +1106,7 @@ class TF_DF(): last_bottom = klc #print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 2") klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2) + self.check_fx_pattern(klc) #klc.set_state('-30') bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) @@ -1354,10 +1366,11 @@ class TF_DF(): def get_klu_list(self, dataframe): klu_list = self.get_kl_data(dataframe) - return self.cal_klu_pattern(klu_list) + #klu_list = self.cal_klu_pattern(klu_list) + return klu_list def cal_klu_pattern(self, klu_list): """ - 计算裸K的pattern - 只识别反转形态 + 计算裸K的pattern - 识别反转形态 """ if not klu_list or len(klu_list) < 3: return klu_list @@ -1365,8 +1378,17 @@ class TF_DF(): for i, klu in enumerate(klu_list): # 单根K线反转模式识别 self._detect_single_reversal_pattern(klu) + + # 双根K线形态识别 + if i >= 1: + self._detect_double_pattern(klu_list[i-1], klu) + + # 三根K线形态识别 + if i >= 2: + self._detect_triple_pattern(klu_list[i-2], klu_list[i-1], klu) + if klu.pattern != Chan_KLU_PATTERN.UNKNOWN: - print(klu.time, klu.pattern) + print(klu.time, klu.pattern, klu.lower_shadow_ratio, klu.upper_shadow_ratio, klu.body_ratio, klu.lower_shadow_ratio/klu.body_ratio, klu.upper_shadow_ratio/klu.body_ratio) return klu_list def _detect_single_reversal_pattern(self, klu): @@ -1383,23 +1405,23 @@ class TF_DF(): body_ratio = body / total_range upper_ratio = upper_shadow / total_range lower_ratio = lower_shadow / total_range - + #print(klu.time, upper_ratio, lower_ratio, body_ratio, upper_ratio/body_ratio, lower_ratio/body_ratio) # 锤子线/上吊线 - 反转信号 if lower_ratio / body_ratio >= 2: # 锤子线:底部反转,需要前面一段 - if klu.close > klu.open and klu.pre and klu.pre.close < klu.pre.open: + if klu.close > klu.open and klu.pre: klu.set_pattern(Chan_KLU_PATTERN.HAMMER) # 底部反转 # 上吊线:顶部反转,需要前一根是上涨趋势 - elif klu.close < klu.open and klu.pre and klu.pre.close > klu.pre.open: + elif klu.close < klu.open and klu.pre: klu.set_pattern(Chan_KLU_PATTERN.HANGING_MAN) # 顶部反转 # 倒锤子线/射击之星 - 反转信号 elif upper_ratio / body_ratio >= 2: # 倒锤子线:底部反转,需要前一根是下跌趋势 - if klu.close > klu.open and klu.pre and klu.pre.close < klu.pre.open: + if klu.close > klu.open and klu.pre: klu.set_pattern(Chan_KLU_PATTERN.INVERTED_HAMMER) # 底部反转 # 射击之星:顶部反转,需要前一根是上涨趋势 - elif klu.close < klu.open and klu.pre and klu.pre.close > klu.pre.open: + elif klu.close < klu.open and klu.pre: klu.set_pattern(Chan_KLU_PATTERN.SHOOTING_STAR) # 顶部反转 # 十字星 - 反转信号 @@ -1417,5 +1439,231 @@ class TF_DF(): else: klu.set_pattern(Chan_KLU_PATTERN.DOJI) # 一般反转信号 + def _detect_double_pattern(self, prev_klu, curr_klu): + """检测两根K线形成的形态 + 包括:吞没形态(看涨/看跌)、乌云盖顶、曙光初现 + """ + # 如果前一根K线已经有形态,不再识别双K线形态 + if prev_klu.pattern != Chan_KLU_PATTERN.UNKNOWN: + return + + # 计算K线实体 + prev_body = abs(prev_klu.close - prev_klu.open) + curr_body = abs(curr_klu.close - curr_klu.open) + + # 判断K线颜色(阴阳) + prev_bullish = prev_klu.close > prev_klu.open + curr_bullish = curr_klu.close > curr_klu.open + + # 检查是否存在长期趋势(至少需要5根K线的趋势) + def check_long_trend(klu, bullish_trend=True, min_bars=5): + """检查是否存在长期趋势 + bullish_trend=True: 检查上涨趋势 + bullish_trend=False: 检查下跌趋势 + min_bars: 最少需要多少根K线形成趋势 + """ + if not klu or not klu.pre: + return False + return True + + # 使用EMA指标判断长期趋势 + if klu.ema52 > 0: + if bullish_trend and klu.close < klu.ema52: + return False + if not bullish_trend and klu.close > klu.ema52: + return False + + # 检查连续的K线方向 + count = 0 + current = klu.pre + + while current and count < min_bars: + if not current.pre: + break + + if bullish_trend: + # 上涨趋势:当前收盘价高于前一根收盘价 + if current.close <= current.pre.close: + break + else: + # 下跌趋势:当前收盘价低于前一根收盘价 + if current.close >= current.pre.close: + break + + count += 1 + current = current.pre + + return count >= min_bars + + # 1. 看涨吞没形态:前阴后阳,后者完全吞没前者 + # 要求前面有明显的下跌趋势 + if not prev_bullish and curr_bullish and \ + abs(curr_klu.open - prev_klu.close) < 10 and \ + curr_klu.close > prev_klu.open and \ + check_long_trend(prev_klu, bullish_trend=False, min_bars=5): + curr_klu.set_pattern(Chan_KLU_PATTERN.BULLISH_ENGULFING) + return + + # 2. 看跌吞没形态:前阳后阴,后者完全吞没前者 + # 要求前面有明显的上涨趋势 + if prev_bullish and not curr_bullish and \ + abs(curr_klu.open - prev_klu.close) < 10 and \ + curr_klu.close < prev_klu.open and \ + check_long_trend(prev_klu, bullish_trend=True, min_bars=5): + curr_klu.set_pattern(Chan_KLU_PATTERN.BEARISH_ENGULFING) + return + + # 3. 乌云盖顶:前阳后阴,后者开盘价高于前者最高价,收盘价在前者实体中部以下 + # 要求前面有明显的上涨趋势 + if prev_bullish and not curr_bullish and \ + curr_klu.open > prev_klu.high and \ + curr_klu.close < (prev_klu.open + prev_klu.close) / 2 and \ + curr_klu.close > prev_klu.open and \ + check_long_trend(prev_klu, bullish_trend=True, min_bars=5): + curr_klu.set_pattern(Chan_KLU_PATTERN.DARK_CLOUD_COVER) + return + + # 4. 曙光初现:前阴后阳,后者开盘价低于前者最低价,收盘价在前者实体中部以上 + # 要求前面有明显的下跌趋势 + if not prev_bullish and curr_bullish and \ + curr_klu.open < prev_klu.low and \ + curr_klu.close > (prev_klu.open + prev_klu.close) / 2 and \ + curr_klu.close < prev_klu.open and \ + check_long_trend(prev_klu, bullish_trend=False, min_bars=5): + curr_klu.set_pattern(Chan_KLU_PATTERN.PIERCING_LINE) + return + + # 平顶和平底移至三根K线形态中判断 + + def _detect_triple_pattern(self, first_klu, second_klu, third_klu): + """检测三根K线形成的形态 + 包括:早晨之星、黄昏之星、平顶、平底 + """ + # 如果前两根K线已经有形态,不再识别三K线形态 + if first_klu.pattern != Chan_KLU_PATTERN.UNKNOWN or \ + second_klu.pattern != Chan_KLU_PATTERN.UNKNOWN: + return + + # 判断K线颜色(阴阳) + first_bullish = first_klu.close > first_klu.open + second_bullish = second_klu.close > second_klu.open + third_bullish = third_klu.close > third_klu.open + + # 计算实体大小 + first_body = abs(first_klu.close - first_klu.open) + second_body = abs(second_klu.close - second_klu.open) + third_body = abs(third_klu.close - third_klu.open) + + # 检查是否存在长期趋势(至少需要5根K线的趋势) + def check_long_trend(klu, bullish_trend=True, min_bars=5): + """检查是否存在长期趋势 + bullish_trend=True: 检查上涨趋势 + bullish_trend=False: 检查下跌趋势 + min_bars: 最少需要多少根K线形成趋势 + """ + if not klu or not klu.pre: + return False + + # 使用EMA指标判断长期趋势 + if klu.ema52 > 0: + if bullish_trend and klu.close < klu.ema52: + return False + if not bullish_trend and klu.close > klu.ema52: + return False + + # 检查连续的K线方向 + count = 0 + current = klu.pre + + while current and count < min_bars: + if not current.pre: + break + + if bullish_trend: + # 上涨趋势:当前收盘价高于前一根收盘价 + if current.close <= current.pre.close: + break + else: + # 下跌趋势:当前收盘价低于前一根收盘价 + if current.close >= current.pre.close: + break + + count += 1 + current = current.pre + + return count >= min_bars + + # 1. 早晨之星:第一根阴线,第二根十字星或小实体,第三根阳线 + # 要求前面有明显的下跌趋势 + if not first_bullish and third_bullish and \ + second_body < first_body * 0.3 and \ + third_body > first_body * 0.5 and \ + max(second_klu.open, second_klu.close) < first_klu.close and \ + min(second_klu.open, second_klu.close) < third_klu.open and \ + third_klu.close > (first_klu.open + first_klu.close) / 2 and \ + check_long_trend(first_klu, bullish_trend=False, min_bars=7): + third_klu.set_pattern(Chan_KLU_PATTERN.MORNING_STAR) + return + + # 2. 黄昏之星:第一根阳线,第二根十字星或小实体,第三根阴线 + # 要求前面有明显的上涨趋势 + if first_bullish and not third_bullish and \ + second_body < first_body * 0.3 and \ + third_body > first_body * 0.5 and \ + min(second_klu.open, second_klu.close) > first_klu.close and \ + max(second_klu.open, second_klu.close) > third_klu.open and \ + third_klu.close < (first_klu.open + first_klu.close) / 2 and \ + check_long_trend(first_klu, bullish_trend=True, min_bars=7): + third_klu.set_pattern(Chan_KLU_PATTERN.EVENING_STAR) + return + + # 3. 平顶:三根K线的最高点几乎相同(上升趋势中更有意义) + # 要求前面有明显的上涨趋势 + if (abs(first_klu.high - second_klu.high) / first_klu.high < 0.0002 and + abs(second_klu.high - third_klu.high) / second_klu.high < 0.0002 and + check_long_trend(first_klu, bullish_trend=True, min_bars=7)): + # 额外确认:价格接近阻力位或关键技术指标 + is_near_resistance = False + + # 检查是否接近EMA52阻力位 + if first_klu.ema52 > 0: + resistance_level = first_klu.ema52 + if abs(first_klu.high - resistance_level) / resistance_level < 0.01: + is_near_resistance = True + + # 检查是否有成交量确认(成交量减少表示上涨动能减弱) + volume_confirmation = False + if (first_klu.volume > 0 and second_klu.volume > 0 and third_klu.volume > 0 and + third_klu.volume < second_klu.volume and second_klu.volume < first_klu.volume): + volume_confirmation = True + + if is_near_resistance or volume_confirmation: + third_klu.set_pattern(Chan_KLU_PATTERN.TWEEZER_TOP) + return + + # 4. 平底:三根K线的最低点几乎相同(下降趋势中更有意义) + # 要求前面有明显的下跌趋势 + if (abs(first_klu.low - second_klu.low) / first_klu.low < 0.0002 and + abs(second_klu.low - third_klu.low) / second_klu.low < 0.0002 and + check_long_trend(first_klu, bullish_trend=False, min_bars=7)): + # 额外确认:价格接近支撑位或关键技术指标 + is_near_support = False + + # 检查是否接近EMA52支撑位 + if first_klu.ema52 > 0: + support_level = first_klu.ema52 + if abs(first_klu.low - support_level) / support_level < 0.01: + is_near_support = True + + # 检查是否有成交量确认(成交量减少表示下跌动能减弱) + volume_confirmation = False + if (first_klu.volume > 0 and second_klu.volume > 0 and third_klu.volume > 0 and + third_klu.volume < second_klu.volume and second_klu.volume < first_klu.volume): + volume_confirmation = True + + if is_near_support or volume_confirmation: + third_klu.set_pattern(Chan_KLU_PATTERN.TWEEZER_BOTTOM) + return + def get_decimal(self, value): return Decimal("{:.2f}".format(value)) \ No newline at end of file diff --git a/strategies/PatternTrader.json b/strategies/PatternTrader.json deleted file mode 100644 index b5dc634..0000000 --- a/strategies/PatternTrader.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "strategy_name": "PatternTrader", - "params": { - "trailing": { - "trailing_stop": false, - "trailing_stop_positive": null, - "trailing_stop_positive_offset": 0.0, - "trailing_only_offset_is_reached": false - }, - "max_open_trades": { - "max_open_trades": 1 - }, - "buy": { - "fast_ma": 9, - "lev": 2.9, - "slow_ma": 31, - "time": 29 - }, - "sell": { - "exit_delay": 6 - }, - "protection": {}, - "roi": { - "0": 0.062, - "6": 0.019, - "16": 0.014, - "40": 0 - }, - "stoploss": { - "stoploss": -0.316 - } - }, - "ft_stratparam_v": 1, - "export_time": "2025-10-28 07:39:54.768566+00:00" -} \ No newline at end of file diff --git a/web/.DS_Store b/web/.DS_Store index 823233e..8b8c023 100644 Binary files a/web/.DS_Store and b/web/.DS_Store differ diff --git a/web/app.py b/web/app.py index d63b576..a6cd768 100644 --- a/web/app.py +++ b/web/app.py @@ -352,39 +352,8 @@ def analyze_chan(df, symbol=None, timeframe=None): # 初始化多时间周期数据以获取EMA52 ema52_dict = None - # 先暂时不用这个功能,太慢了 - if symbol and timeframe and False: - try: - # 获取不同时间周期的数据用于初始化 - df_1h = get_kl_data(symbol, '1h', limit=1500) if timeframe != '1h' else df - df_1d = get_kl_data(symbol, '1d', limit=2000) if timeframe != '1d' else df - df_1M = get_kl_data(symbol, '1M', limit=1500) if timeframe != '1M' else df - - # 添加指标 - if df_1h is not None and len(df_1h) > 0: - df_1h = add_indicators(df_1h) - if df_1d is not None and len(df_1d) > 0: - df_1d = add_indicators(df_1d) - if df_1M is not None and len(df_1M) > 0: - df_1M = add_indicators(df_1M) - - # 初始化多时间周期数据 - chan.init_dataframes(df, df_1h, df_1d, df_1M) - - # 获取EMA52数据 - ema52_dict = chan.get_ema52_dict() - # 处理NaN值 - if ema52_dict: - for key, value in ema52_dict.items(): - if pd.isna(value) or value is None: - ema52_dict[key] = None - else: - ema52_dict[key] = float(value) - except Exception as e: - print(f"获取多时间周期EMA52数据失败: {e}") - ema52_dict = None - # 获取分析结果 + klu_list = chan.get_kl_data(df) klc_list = chan.get_klc_list(df) bi_list = chan.cal_bi_list(klc_list) #for index in range(0, 10): @@ -408,8 +377,6 @@ def analyze_chan(df, symbol=None, timeframe=None): chan_macd = None chan_macd_data = {} try: - # 直接使用ChanLun的get_klu_list方法获取KLU列表 - klu_list = chan.get_klu_list(df) if klu_list and len(klu_list) > 0: print(f"获取到KLU列表,长度: {len(klu_list)}") @@ -457,20 +424,6 @@ def analyze_chan(df, symbol=None, timeframe=None): 'cross0_down_list': [] } - # 获取原始K线数据用于KLU分型分析 - klu_list = [] - try: - # 尝试获取KLU数据 - if hasattr(chan, 'get_klu_list'): - klu_list = chan.get_klu_list(df) - elif hasattr(chan, 'klu_list'): - klu_list = chan.klu_list - else: - # 如果没有专门的KLU方法,尝试从KLC获取原始K线数据 - pass - except Exception as e: - klu_list = [] - # 提取K线分型信息 klc_fx_info = [] for klc in klc_list: