diff --git a/ChanBI.py b/ChanBI.py index d8d3e78..34a70b8 100644 --- a/ChanBI.py +++ b/ChanBI.py @@ -53,6 +53,7 @@ class ChanBI(): self.end_klc = klc self.set_is_sure(True, sure_klc.end_time) self.end_time = klc.end_time + #print(self.start_time, klc.start_time, klc.fx, "This bi is ended") def set_is_sure(self, is_sure, time): self.is_sure = is_sure self.sure_time = time @@ -88,4 +89,4 @@ class ChanBI(): self.low = klc.low self.is_sure = False self.sure_time = None - #print(self.start_klc.start_time, klc.start_time, klc.fx, "This bi is extended") \ No newline at end of file + #print(self.start_time, klc.start_time, klc.fx, "This bi is extended") \ No newline at end of file diff --git a/ChanEnum.py b/ChanEnum.py index 93c2d78..1db70bb 100644 --- a/ChanEnum.py +++ b/ChanEnum.py @@ -40,6 +40,17 @@ class Chan_FX_TYPE(Enum): DOWN = auto() TT = auto() BB = auto() + PTOP = auto() + PBOTTOM = auto() + +class Chan_KLC_FX(Enum): + TOP1 = auto() + TOP2 = auto() + TOP3 = auto() + BOTTOM1 = auto() + BOTTOM2 = auto() + BOTTOM3 = auto() + UNKNOWN = auto() class Chan_BI_DIR(Enum): diff --git a/ChanKLC.py b/ChanKLC.py index 7c40a75..b70bc6c 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -1,7 +1,7 @@ import copy from typing import Dict, Optional -from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR +from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX import ChanKLU import ChanCTime @@ -29,6 +29,10 @@ class ChanKLC(): self.bi_macdhist = 0 self.bi_macd_div = 0.0 self.bi = None + self.distance = 0 + self.klc_fx_type = Chan_KLC_FX.UNKNOWN + def set_klc_fx_type(self, klc_fx_type): + self.klc_fx_type = klc_fx_type def add_klu(self, klu): self.klus.append(klu) def set_end_klu(self, klu): @@ -123,6 +127,12 @@ class ChanKLC(): self.bi_macdhist += klc.get_macdhist() elif bi.dir == Chan_BI_DIR.DOWN and klc.get_macdhist() < 0: self.bi_macdhist -= klc.get_macdhist() + self.distance = self.index - bi.start_klc.index + if False: + if bi.is_sure: + print(self.start_time, self.distance, bi.index, bi.start_time, bi.dir, bi.end_time) + else: + print(self.start_time, self.distance, bi.index, bi.start_time, bi.dir) def get_macdhist(self): self.macdhist = 0 for klu in self.klus: @@ -164,6 +174,7 @@ class ChanKLC(): features['klc_pre_fx'] = (0 if self.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre else 0 #10 features['klc_pre_pre_fx'] = (0 if self.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre else 0 #11 features['klc_pre_pre_pre_fx'] = (0 if self.pre.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre and self.pre.pre.pre else 0 #12 + features['klc_distance'] = self.distance #13 # New Add 20250422 #features['klc_macdhist'] = self.get_macdhist() #11 #features['klc_bi_macdhist'] = self.bi_macdhist #12 diff --git a/ChanKLU.py b/ChanKLU.py index 237dae5..681672c 100644 --- a/ChanKLU.py +++ b/ChanKLU.py @@ -21,6 +21,15 @@ class ChanKLU: def set_idx(self, idx): self.idx = idx self.index = idx + def set_indicators(self, dict): + self.macd = dict['macd'] + self.signal = dict['macdsignal'] + self.macdhist = dict['macdhist'] + self.ma5 = dict['ma5'] + self.ma10 = dict['ma10'] + self.ma30 = dict['ma30'] + self.ma250 = dict['ma250'] + self.rsi = dict['rsi'] def get_feature_data(self): features = dict() features['klu_close'] = self.close diff --git a/ChanLun.py b/ChanLun.py index dc29327..ad46946 100644 --- a/ChanLun.py +++ b/ChanLun.py @@ -1,6 +1,6 @@ from datetime import timedelta from pandas import DataFrame -from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_SEG_DIR, Chan_ZS_DIR, Chan_BSP_DIR, Chan_BSP_TYPE +from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_SEG_DIR, Chan_ZS_DIR, Chan_BSP_DIR, Chan_BSP_TYPE, Chan_KLC_FX from ChanKLU import ChanKLU from ChanKLC import ChanKLC from ChanBI import ChanBI @@ -88,6 +88,7 @@ class ChanLun(): df['macdhist'] = macd['macdhist'] return df def plot_dataframe(self, dataframe): + return self.get_klu_list(dataframe) klc_list = self.get_klc_list(dataframe) bi_list= self.cal_bi_list(klc_list) seg_list = self.get_seg_list(bi_list) @@ -529,7 +530,7 @@ class ChanLun(): fx = self.check_fx(klc) # Do nothing if fx == Chan_FX_TYPE.UNKNOWN: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + klc.set_fx(fx) if len(bi_list) > 0: bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) @@ -541,16 +542,19 @@ class ChanLun(): if last_bottom.index < last_top.index: # Second top lower to be second sell point if last_top.high > klc.high: - klc.set_fx(Chan_FX_TYPE.TT) + #klc.set_fx(Chan_FX_TYPE.TT) klc.set_state("20") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) - #print(klc.start_time, klc.fx, "二类买卖点Sell 1") + #print(klc.start_time, klc.fx, "二类卖点Sell 1") else: # A new top found #last_top.set_fx(Chan_FX_TYPE.UNKNOWN) last_top = klc - #print(klc.start_time, klc.fx, "一类买卖点Sell 1") + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 1") + klc.set_klc_fx_type(Chan_KLC_FX.TOP1) + #print(klc.start_time, klc.fx, "一类卖点Sell 1") + #klc.set_fx(fx) klc.set_state("10") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) @@ -558,8 +562,8 @@ class ChanLun(): # 不满足结合律的分型 if last_bottom.index + 4 > klc.index: if last_top.high > klc.high: - #print(klc.start_time, last_bottom.start_time, klc.fx, "中枢买卖点Sell 1") - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + #print(klc.start_time, klc.fx, "二类卖点Sell 1") + #klc.set_fx(Chan_FX_TYPE.PTOP) bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) # New TOP Found replace last top @@ -571,18 +575,21 @@ class ChanLun(): pre_last_bi.update_bi(klc) bi_list.remove(last_bi) pre_last_bi.set_next(None) - last_top.set_fx(Chan_FX_TYPE.UNKNOWN) + #last_top.set_fx(Chan_FX_TYPE.PTOP) last_top = klc last_bottom = pre_last_bi.start_klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Bottom Change 1") + klc.set_klc_fx_type(Chan_KLC_FX.TOP2) #print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi") klc.set_state("10") + #print(klc.start_time, klc.fx, "笔卖点Sell 1") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) else: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + klc.set_fx(Chan_FX_TYPE.PTOP) bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) - #print(klc.start_time, last_bottom.start_time, klc.fx, "中枢买卖点Sell 2") + #print(klc.start_time, klc.fx, "无效分型") # 满足结合律 else: # New Temp TOP and last bottom confirmed ***** confirm last down bi(last bottom and last top) @@ -595,10 +602,13 @@ class ChanLun(): bi.add_klc(klc) bi_list.append(bi) last_top = klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 2") + klc.set_klc_fx_type(Chan_KLC_FX.TOP2) klc.set_state('30') bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) #print(klc.start_time, last_bottom.start_time, "Normal TOP Found, Confirm down bi 4") + #print(klc.start_time, klc.fx, "笔卖点Sell 2") # last bottom = None else: if last_top.high < klc.high: @@ -606,29 +616,42 @@ class ChanLun(): last_bi.set_start_klc(klc, Chan_BI_DIR.DOWN) #last_top.set_fx(Chan_FX_TYPE.UNKNOWN) last_top = klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 3") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "笔卖点Sell 3") else: klc.set_fx(Chan_FX_TYPE.TT) klc.set_state('20') - #print(klc.start_time, klc.fx, "二类买卖点Sell 2") + #print(klc.start_time, klc.fx, "二类卖点Sell 2") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) else: if last_bottom: # 不满足结合律的分型 if last_bottom.index + 4 > klc.index: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + #klc.set_fx(Chan_FX_TYPE.PTOP) + bi_list[-1].add_klc(klc) + klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "中枢卖点Sell 1") else: # First temp top and last bottom confirmed last_top = klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 4") + bi_list[-1].add_klc(klc) + klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "一类卖点Sell 1") # Last top = None, last bottom = None, create first down bi else: # First temp top last_top = klc bi = ChanBI(klc, len(bi_list), Chan_BI_DIR.DOWN) bi_list.append(bi) + bi_list[-1].add_klc(klc) + klc.set_bi(bi_list[-1]) + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 5") #print(klc.start_time, 'Create first top') + #print(klc.start_time, klc.fx, "笔卖点Sell 1") #klc.fx = Bottom ======================== else: if last_bottom: @@ -637,16 +660,18 @@ class ChanLun(): if last_top.index < last_bottom.index: # Second bottom uppper to be second buy point and confirm last bi if last_bottom.low < klc.low: - klc.set_fx(Chan_FX_TYPE.BB) + #klc.set_fx(Chan_FX_TYPE.BB) klc.set_state("-20") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) - #print(klc.start_time, klc.fx, "二类买卖点Buy 1") + #print(klc.start_time, klc.fx, "二类买点Buy 1") else: # A new bottom found #last_bottom.set_fx(Chan_FX_TYPE.UNKNOWN) last_bottom = klc - #print(klc.start_time, klc.fx, "一类买卖点Buy 1") + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 1") + klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM1) + #print(klc.start_time, klc.fx, "一类买点Buy 1") klc.set_state("-10") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) @@ -654,10 +679,10 @@ class ChanLun(): # 不满足结合律的分型 if last_top.index + 4 > klc.index: if last_bottom.low < klc.low: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + #klc.set_fx(Chan_FX_TYPE.PBOTTOM) #klc.set_fx(Chan_FX_TYPE.BB) #klc.set_state("-100") - #print(klc.start_time, klc.fx, "中枢买卖点Buy 1") + #print(klc.start_time, klc.fx, "中枢买点Buy 1") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) # Found new bottom @@ -669,18 +694,21 @@ class ChanLun(): pre_last_bi.update_bi(klc) bi_list.remove(last_bi) pre_last_bi.set_next(None) - last_bottom.set_fx(Chan_FX_TYPE.UNKNOWN) + #last_bottom.set_fx(Chan_FX_TYPE.PBOTTOM) last_bottom = klc last_top = pre_last_bi.start_klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Bottom Change 2") + klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2) #print(klc.start_time, last_bi.start_klc.start_time, "New BOTTOM Found reset last bi") klc.set_state("-10") + #print(klc.start_time, klc.fx, "笔买点Buy 1") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) else: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + #klc.set_fx(Chan_FX_TYPE.UNKNOWN) bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) - #print(klc.start_time, klc.fx, "中枢买卖点Buy 2") + #print(klc.start_time, klc.fx, "无效分型") # 满足结合律的分型 else: # New Temp Bottom and last top confirmed ***** confirm last up bi(last bottom and last top) @@ -693,9 +721,12 @@ class ChanLun(): bi.add_klc(klc) bi_list.append(bi) 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) klc.set_state('-30') bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "笔买点Buy 2") #print(klc.start_time, last_top.start_time, "Normal Bottom Found, Confirm up bi 6") # last_top = None else: @@ -704,12 +735,14 @@ class ChanLun(): last_bi.set_start_klc(klc, Chan_BI_DIR.UP) #last_bottom.set_fx(Chan_FX_TYPE.UNKNOWN) last_bottom = klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 3") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "笔买点Buy 3") else: klc.set_fx(Chan_FX_TYPE.BB) klc.set_state('-20') - #print(klc.start_time, klc.fx, "二类买卖点Buy 2") + #print(klc.start_time, klc.fx, "二类买点Buy 2") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) # last_bottom = None @@ -717,14 +750,17 @@ class ChanLun(): if last_top: # 不满足结合律的分型 if last_top.index + 4 > klc.index: - klc.set_fx(Chan_FX_TYPE.UNKNOWN) + #klc.set_fx(Chan_FX_TYPE.PBOTTOM) bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "中枢买点Buy 1") else: # First temp bottom and last top confirmed last_bottom = klc + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 4") bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) + #print(klc.start_time, klc.fx, "一类买点Buy 1") # Last top = None, last bottom = None, create first up bi else: # First temp bottom and no top yet @@ -733,8 +769,11 @@ class ChanLun(): bi_list.append(bi) bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) - #print(klc.start_time, 'Create first bottom') - #print(klc.time, klc.fx, klc.state) + print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Bottom Change 5") + #print(klc.start_time, klc.fx, "笔买点Buy 4") + #if klc.fx != Chan_FX_TYPE.UNKNOWN: + #print(klc.start_time, klc.fx, klc.index) + """ for klc in klc_list: if klc.fx == Chan_FX_TYPE.TOP: klc.state = "10" @@ -742,6 +781,7 @@ class ChanLun(): if klc.fx == Chan_FX_TYPE.BOTTOM: klc.state = "-10" #print(klc.time, klc.state) + """ return bi_list def get_zs_list(self, bi_list, seg_list): @@ -997,7 +1037,20 @@ class ChanLun(): def get_decimal(self, value): return Decimal("{:.2f}".format(value)) - + def add_indicators(self, df): + fast = 8 + slow = 16 + period = 6 + macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period) + df['macd'] = macd['macd'] + df['macdsignal'] = macd['macdsignal'] + df['macdhist'] = macd['macdhist'] + df['ma5'] = ta.MA(df, timeperiod=5) + df['ma10'] = ta.MA(df, timeperiod=10) + df['ma30'] = ta.EMA(df, timeperiod=30) + df['ma250'] = ta.MA(df, timeperiod=250) + df['rsi'] = ta.RSI(df, timeperiod=14) + return df def get_klc_list(self, dataframe): klu_list = self.get_klu_list(dataframe) klc_list = [] @@ -1075,14 +1128,8 @@ class ChanLun(): klu = ChanKLU(time_str, o, h, l, c, v) klu.set_idx(i) klu_list.append(klu) - klu.macd = item['macd'] - klu.signal = item['macdsignal'] - klu.macdhist = item['macdhist'] - klu.ma5 = item['ma5'] - klu.ma10 = item['ma10'] - klu.ma30 = item['ma30'] - klu.ma250 = item['ma250'] - klu.rsi = item['rsi'] + if True: + klu.set_indicators(item) return klu_list def get_bsp_list1(self, big_df): diff --git a/ChanLun_Classifier.py b/ChanLun_Classifier.py index 9261dcf..e088d5b 100644 --- a/ChanLun_Classifier.py +++ b/ChanLun_Classifier.py @@ -289,6 +289,13 @@ class ChanLunClassifier: bi_index = 0 sample_list = [] for klc in klc_list: + if klc.pre and klc.next: + if klc.high > klc.pre.high and klc.high > klc.next.high: + klc.set_fx(Chan_FX_TYPE.TOP) + elif klc.low < klc.pre.low and klc.low < klc.next.low: + klc.set_fx(Chan_FX_TYPE.BOTTOM) + else: + klc.set_fx(Chan_FX_TYPE.UNKNOWN) if klc.fx != Chan_FX_TYPE.UNKNOWN: sample_list.append(klc) for klc in sample_list: @@ -311,8 +318,8 @@ class ChanLunClassifier: # 判断这个bi是否赚钱(这里简单定义为:如果bi的结束价格高于起始价格,则标记为1,否则为0) # 这个标签定义可以根据实际需求修改 - seg = seg_list[bi_index] - if bi.start_klc.index == klc.index and bi.dir == Chan_BI_DIR.UP: + bi = bi_list[bi_index] + if bi.start_klc.index == klc.index: #if klc.index == seg.start_bi.start_klc.index and seg.dir == Chan_SEG_DIR.UP: label = 1 bi_index += 2 @@ -339,6 +346,13 @@ class ChanLunClassifier: bi_index = 0 sample_list = [] for klc in klc_list: + if klc.pre and klc.next: + if klc.high > klc.pre.high and klc.high > klc.next.high: + klc.set_fx(Chan_FX_TYPE.TOP) + elif klc.low < klc.pre.low and klc.low < klc.next.low: + klc.set_fx(Chan_FX_TYPE.BOTTOM) + else: + klc.set_fx(Chan_FX_TYPE.UNKNOWN) if klc.fx != Chan_FX_TYPE.UNKNOWN: sample_list.append(klc) for klc in sample_list: @@ -357,7 +371,7 @@ class ChanLunClassifier: else: feature_vec.append(0) seg = seg_list[bi_index] - if bi.start_klc.index == klc.index and bi.dir == Chan_BI_DIR.UP: + if bi.start_klc.index == klc.index: #if klc.index == seg.start_bi.start_klc.index and seg.dir == Chan_SEG_DIR.UP: label = 1 bi_index += 2 @@ -449,5 +463,5 @@ class ChanLunClassifier: return self.get_decimal(self.model.predict(dtest)[0]) def get_decimal(self, value): - return Decimal("{:.2f}".format(value)) + return Decimal("{:.4f}".format(value)) diff --git a/__pycache__/ChanBI.cpython-312.pyc b/__pycache__/ChanBI.cpython-312.pyc index 8b5d9cb..8e5f2e8 100644 Binary files a/__pycache__/ChanBI.cpython-312.pyc and b/__pycache__/ChanBI.cpython-312.pyc differ diff --git a/__pycache__/ChanEnum.cpython-312.pyc b/__pycache__/ChanEnum.cpython-312.pyc index 4a77e10..2f7ebd5 100644 Binary files a/__pycache__/ChanEnum.cpython-312.pyc and b/__pycache__/ChanEnum.cpython-312.pyc differ diff --git a/__pycache__/ChanKLC.cpython-312.pyc b/__pycache__/ChanKLC.cpython-312.pyc index 9ba2066..d2c67b5 100644 Binary files a/__pycache__/ChanKLC.cpython-312.pyc and b/__pycache__/ChanKLC.cpython-312.pyc differ diff --git a/__pycache__/ChanKLU.cpython-312.pyc b/__pycache__/ChanKLU.cpython-312.pyc index 2fe6c5e..c211084 100644 Binary files a/__pycache__/ChanKLU.cpython-312.pyc and b/__pycache__/ChanKLU.cpython-312.pyc differ diff --git a/__pycache__/ChanLun.cpython-312.pyc b/__pycache__/ChanLun.cpython-312.pyc index f3adc55..2b45e4d 100644 Binary files a/__pycache__/ChanLun.cpython-312.pyc and b/__pycache__/ChanLun.cpython-312.pyc differ diff --git a/__pycache__/ChanLun_Classifier.cpython-312.pyc b/__pycache__/ChanLun_Classifier.cpython-312.pyc index 2e4b553..e364a86 100644 Binary files a/__pycache__/ChanLun_Classifier.cpython-312.pyc and b/__pycache__/ChanLun_Classifier.cpython-312.pyc differ diff --git a/web/app.py b/web/app.py index af86b4a..540de34 100644 --- a/web/app.py +++ b/web/app.py @@ -128,14 +128,25 @@ def get_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=None): # 按时间排序 df = df.sort_values('timestamp') - + chan = ChanLun() + klc_list = chan.get_klc_list(df) + klc_index = 0 + df_copy = df.copy() + ret_df = pd.DataFrame(columns=['timestamp', 'open', 'high', 'low', 'close', 'volume', 'date']) + for index in range(0, len(df)): + if klc_index >= len(klc_list): + klc_index = len(klc_list) - 1 + klc = klc_list[klc_index] + if index == klc.start_klu.index: + ret_df.loc[klc_index] = df_copy.loc[index] + klc_index += 1 # 如果过滤后没有数据,返回None - if len(df) == 0: + if len(ret_df) == 0: print("过滤后无数据") return None - print(f"获取到总共 {len(df)} 条数据") - return df + print(f"获取到总共 {len(ret_df)} 条数据") + return ret_df except Exception as e: print(f"获取数据错误: {e}") @@ -166,9 +177,6 @@ def analyze_chan(df): seg_list = chan.get_seg_list(bi_list) zs_list = chan.calculate_zs(bi_list, seg_list) - # 获取笔中枢列表 - bi_zs_list = chan.get_bi_zs_list(bi_list) - # 添加买卖点识别 buy_sell_points = identify_trade_points(bi_list, seg_list, zs_list) @@ -177,7 +185,6 @@ def analyze_chan(df): 'bi_list': bi_list, 'seg_list': seg_list, 'zs_list': zs_list, - 'bi_zs_list': bi_zs_list, # 添加笔中枢数据 'trade_points': buy_sell_points } @@ -403,36 +410,16 @@ def analyze(): 'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None, 'zg': zs.zg, 'zd': zs.zd, - 'is_sure': zs.is_sure, # 添加中枢是否完成的标志 - 'type': getattr(zs, 'type', 'SEG_ZS') # 中枢类型,默认为线段中枢 + 'is_sure': zs.is_sure # 添加中枢是否完成的标志 } for zs in analysis_result['zs_list'] if zs.end_klc], - # 添加笔中枢列表 - 'bi_zs_list': [{ - 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), - 'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None, - 'zg': zs.zg, - 'zd': zs.zd, - 'is_sure': zs.is_sure, # 添加中枢是否完成的标志 - 'type': 'BI_ZS' # 标记为笔中枢 - } for zs in analysis_result['bi_zs_list'] if zs.end_klc], # 添加未完成中枢列表 'uncompleted_zs_list': [{ 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), 'end_time': None, # 未完成中枢没有结束时间 'zg': zs.zg, 'zd': zs.zd, - 'is_sure': zs.is_sure, # 未完成中枢的is_sure为False - 'type': getattr(zs, 'type', 'SEG_ZS') # 中枢类型,默认为线段中枢 + 'is_sure': zs.is_sure # 未完成中枢的is_sure为False } for zs in analysis_result['zs_list'] if not zs.is_sure], - # 添加未完成笔中枢列表 - 'uncompleted_bi_zs_list': [{ - 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), - 'end_time': None, # 未完成中枢没有结束时间 - 'zg': zs.zg, - 'zd': zs.zd, - 'is_sure': zs.is_sure, # 未完成中枢的is_sure为False - 'type': 'BI_ZS' # 标记为笔中枢 - } for zs in analysis_result['bi_zs_list'] if not zs.is_sure], 'trade_points': [{ 'type': point['type'], 'time': format_time_safely(point['time'], client_tz), @@ -477,40 +464,18 @@ def analyze(): 'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None, 'zg': zs.zg, 'zd': zs.zd, - 'is_sure': zs.is_sure, # 添加中枢是否完成的标志 - 'type': getattr(zs, 'type', 'SEG_ZS') # 中枢类型,默认为线段中枢 + 'is_sure': zs.is_sure # 添加中枢是否完成的标志 } for zs in element_analysis['zs_list'] if zs.end_klc] - # 添加小周期笔中枢 - result['element_bi_zs_list'] = [{ - 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), - 'end_time': (zs.end_klc.end_time if isinstance(zs.end_klc.end_time, str) else zs.end_klc.end_time.astimezone(client_tz).isoformat()) if zs.end_klc else None, - 'zg': zs.zg, - 'zd': zs.zd, - 'is_sure': zs.is_sure, # 添加中枢是否完成的标志 - 'type': 'BI_ZS' # 标记为笔中枢 - } for zs in element_analysis['bi_zs_list'] if zs.end_klc] - # 添加小周期未完成中枢列表 result['element_uncompleted_zs_list'] = [{ 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), 'end_time': None, # 未完成中枢没有结束时间 'zg': zs.zg, 'zd': zs.zd, - 'is_sure': zs.is_sure, # 未完成中枢的is_sure为False - 'type': getattr(zs, 'type', 'SEG_ZS') # 中枢类型,默认为线段中枢 + 'is_sure': zs.is_sure # 未完成中枢的is_sure为False } for zs in element_analysis['zs_list'] if not zs.is_sure] - # 添加小周期未完成笔中枢列表 - result['element_uncompleted_bi_zs_list'] = [{ - 'start_time': zs.start_klc.start_time if isinstance(zs.start_klc.start_time, str) else zs.start_klc.start_time.astimezone(client_tz).isoformat(), - 'end_time': None, # 未完成中枢没有结束时间 - 'zg': zs.zg, - 'zd': zs.zd, - 'is_sure': zs.is_sure, # 未完成中枢的is_sure为False - 'type': 'BI_ZS' # 标记为笔中枢 - } for zs in element_analysis['bi_zs_list'] if not zs.is_sure] - result['element_trade_points'] = [{ 'type': point['type'], 'time': format_time_safely(point['time'], client_tz), diff --git a/web/templates/index.html b/web/templates/index.html index cb7eb05..d6a648d 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -196,16 +196,6 @@ font-weight: bold; } - .main-bi-zs { - color: #FF9800; - font-weight: bold; - } - - .element-bi-zs { - color: #9C27B0; - font-weight: bold; - } - /* 加载指示器旋转动画 */ @keyframes spin { 0% { transform: rotate(0deg); } @@ -308,14 +298,6 @@ -
- - -
-
- - -
@@ -335,14 +317,6 @@
-
- - -
-
- - -
@@ -542,14 +516,10 @@ mainSegSeries: [], mainZsSeries: [], mainUncompletedZsSeries: [], - mainBiZsSeries: [], // 添加主周期笔中枢系列 - mainUncompletedBiZsSeries: [], // 添加未完成主周期笔中枢系列 elementBiSeries: [], elementSegSeries: [], elementZsSeries: [], elementUncompletedZsSeries: [], - elementBiZsSeries: [], // 添加元素周期笔中枢系列 - elementUncompletedBiZsSeries: [], // 添加未完成元素周期笔中枢系列 tradePointSeries: [] }, state: { @@ -735,16 +705,6 @@ updateChartDisplay(); }); - // 添加笔中枢复选框变更事件 - $('#showMainBiZs').change(function() { - updateChartDisplay(); - }); - - // 添加未完成笔中枢复选框变更事件 - $('#showMainUncompletedBiZs').change(function() { - updateChartDisplay(); - }); - // 添加买卖点复选框变更事件 $('#showElementBi').change(function() { updateChartDisplay(); @@ -765,16 +725,6 @@ updateChartDisplay(); }); - // 添加笔中枢复选框变更事件 - $('#showElementBiZs').change(function() { - updateChartDisplay(); - }); - - // 添加未完成笔中枢复选框变更事件 - $('#showElementUncompletedBiZs').change(function() { - updateChartDisplay(); - }); - // 添加买卖点复选框变更事件 $('#showTradePoints').change(function() { updateChartDisplay(); @@ -946,39 +896,51 @@ }); function updateChartDisplay() { - // 获取复选框状态 - var showMainBi = $('#showMainBi').prop('checked'); - var showMainSeg = $('#showMainSeg').prop('checked'); - var showMainZs = $('#showMainZs').prop('checked'); - var showMainUncompletedZs = $('#showMainUncompletedZs').prop('checked'); - var showMainBiZs = $('#showMainBiZs').prop('checked'); - var showMainUncompletedBiZs = $('#showMainUncompletedBiZs').prop('checked'); - var showElementBi = $('#showElementBi').prop('checked'); - var showElementSeg = $('#showElementSeg').prop('checked'); - var showElementZs = $('#showElementZs').prop('checked'); - var showElementUncompletedZs = $('#showElementUncompletedZs').prop('checked'); - var showElementBiZs = $('#showElementBiZs').prop('checked'); - var showElementUncompletedBiZs = $('#showElementUncompletedBiZs').prop('checked'); - var showTradePoints = $('#showTradePoints').prop('checked'); - - // 调用显示/隐藏函数 - if (showMainBi) { drawBi(main_bi_list); } else { removeBi(); } - if (showMainSeg) { drawSeg(main_seg_list); } else { removeSeg(); } - if (showMainZs) { drawZones(main_zs_list); } else { removeZones(); } - if (showMainUncompletedZs) { drawUncompletedZones(main_uncompleted_zs_list); } else { removeUncompletedZones(); } - if (showMainBiZs) { drawBiZones(main_bi_zs_list); } else { removeBiZones(); } - if (showMainUncompletedBiZs) { drawUncompletedBiZones(main_uncompleted_bi_zs_list); } else { removeUncompletedBiZones(); } - - // 元素显示 - if (showElementBi) { drawBiOnElement(element_bi_list); } else { removeBiOnElement(); } - if (showElementSeg) { drawSegOnElement(element_seg_list); } else { removeSegOnElement(); } - if (showElementZs) { drawZonesOnElement(element_zs_list); } else { removeZonesOnElement(); } - if (showElementUncompletedZs) { drawUncompletedZonesOnElement(element_uncompleted_zs_list); } else { removeUncompletedZonesOnElement(); } - if (showElementBiZs) { drawBiZonesOnElement(element_bi_zs_list); } else { removeBiZonesOnElement(); } - if (showElementUncompletedBiZs) { drawUncompletedBiZonesOnElement(element_uncompleted_bi_zs_list); } else { removeUncompletedBiZonesOnElement(); } - - // 买卖点 - if (showTradePoints) { drawTradePoints(trade_points_list); } else { removeTradePoints(); } + if (currentData) { + // 保存当前的可见逻辑范围 + let logicalRange = null; + let visibleRange = null; + + if (tvWidget && tvWidget.mainChart) { + // 优先使用逻辑范围,这样在缩放级别上更准确 + logicalRange = tvWidget.mainChart.timeScale().getVisibleLogicalRange(); + // 备用方案,获取实际时间戳范围 + visibleRange = tvWidget.mainChart.timeScale().getVisibleRange(); + } + + console.log('更新图表显示'); + console.log('- 显示K线:', $('#showOriginalKline').is(':checked')); + console.log('- 显示笔:', $('#showMainBi').is(':checked')); + console.log('- 显示线段:', $('#showMainSeg').is(':checked')); + console.log('- 显示中枢:', $('#showMainZs').is(':checked')); + console.log('- 显示未完成中枢:', $('#showMainUncompletedZs').is(':checked')); + console.log('- 显示MACD:', $('#showMacd').is(':checked')); + console.log('- 显示买卖点:', $('#showTradePoints').is(':checked')); + + // 重新初始化图表,这将清除旧图形并重新绘制 + initTradingView($('#symbol').val(), $('#timeframe').val()); + + // 如果有保存的范围,恢复它 + setTimeout(() => { + if (tvWidget) { + if (logicalRange) { + // 应用保存的逻辑范围到所有图表 + tvWidget.mainChart.timeScale().setVisibleLogicalRange(logicalRange); + tvWidget.volumeChart.timeScale().setVisibleLogicalRange(logicalRange); + if (tvWidget.macdChart) { + tvWidget.macdChart.timeScale().setVisibleLogicalRange(logicalRange); + } + } else if (visibleRange) { + // 如果没有逻辑范围,使用时间戳范围 + tvWidget.mainChart.timeScale().setVisibleRange(visibleRange); + tvWidget.volumeChart.timeScale().setVisibleRange(visibleRange); + if (tvWidget.macdChart) { + tvWidget.macdChart.timeScale().setVisibleRange(visibleRange); + } + } + } + }, 100); + } } // 确保所有时间处理都使用UTC时间,包括表格数据显示 @@ -1076,8 +1038,8 @@ $('#refreshLoadingSpinner').hide(); // 保存当前数据 - currentData = data; - + currentData = data; + // 刷新图表 refreshChart(data); }, @@ -1116,14 +1078,10 @@ mainSegSeries: [], mainZsSeries: [], mainUncompletedZsSeries: [], - mainBiZsSeries: [], // 添加主周期笔中枢系列 - mainUncompletedBiZsSeries: [], // 添加未完成主周期笔中枢系列 elementBiSeries: [], elementSegSeries: [], elementZsSeries: [], elementUncompletedZsSeries: [], - elementBiZsSeries: [], // 添加元素周期笔中枢系列 - elementUncompletedBiZsSeries: [], // 添加未完成元素周期笔中枢系列 tradePointSeries: [] }, state: { @@ -1348,22 +1306,22 @@ if (currentData.macd && currentData.macd.macd && currentData.macd.macd[i] !== undefined) { macdData.push({ - time: timestamp, + time: timestamp, value: currentData.macd.macd[i] - }); - + }); + signalData.push({ - time: timestamp, + time: timestamp, value: currentData.macd.signal[i] }); // 设置直方图颜色 const histValue = currentData.macd.histogram[i]; histogramData.push({ - time: timestamp, + time: timestamp, value: histValue, color: histValue >= 0 ? 'rgba(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)' - }); + }); } } @@ -2624,7 +2582,7 @@ // 添加事件监听 addChartSyncEvents(mainChartContainer, mainChart); addChartSyncEvents(volumeChartContainer, volumeChart); - if (showMacd && macdChart) { + if (showMacd && macdChart) { addChartSyncEvents(macdChartContainer, macdChart); } @@ -2714,7 +2672,7 @@ if (isNaN(timeValue.getTime())) { console.error(`买卖点 #${i} 时间格式无效:`, tradePointsData[i].time); } - } catch (e) { + } catch (e) { console.error(`买卖点 #${i} 时间格式异常:`, e); } } else { @@ -3366,14 +3324,48 @@ } console.log('重绘分形元素 - 开始'); + console.log('- 显示笔:', $('#showMainBi').is(':checked')); + console.log('- 显示线段:', $('#showMainSeg').is(':checked')); + console.log('- 显示中枢:', $('#showMainZs').is(':checked')); // 保存当前的图表可见范围 const mainChart = tvWidget.mainChart; const visibleRange = mainChart.timeScale().getVisibleRange(); const logicalRange = mainChart.timeScale().getVisibleLogicalRange(); - // 调用显示所有元素函数 - displayAllElements(); + // 获取当前图表设置 + const showMacd = $('#showMacd').is(':checked'); + const showOriginalKline = $('#showOriginalKline').is(':checked'); + const showBi = $('#showMainBi').is(':checked'); + const showSeg = $('#showMainSeg').is(':checked'); + const showZs = $('#showMainZs').is(':checked'); + + // 保存原始K线和MACD数据,确保即使使用小级别,我们依然使用主周期的K线和MACD数据 + const originalKlineData = currentData.kline_data; + const originalMacdData = currentData.macd; + + // 重新初始化图表 - 这将清除所有系列并重新创建 + console.log('重新初始化图表...'); + + // 临时存储currentData中可能被修改的字段 + const tempCurrentData = { + kline_data: originalKlineData, + macd: originalMacdData + }; + + // 在重绘前确保K线和MACD数据不变 + if (currentData.original_kline_data && currentData.original_macd) { + // 如果已经保存了原始数据,恢复它们 + currentData.kline_data = currentData.original_kline_data; + currentData.macd = currentData.original_macd; + } else { + // 首次运行 - 保存原始数据 + currentData.original_kline_data = originalKlineData; + currentData.original_macd = originalMacdData; + } + + // 调用初始化函数 + initTradingView($('#symbol').val(), $('#timeframe').val()); // 恢复原始可见范围 setTimeout(() => { @@ -3486,14 +3478,12 @@ console.log('API返回数据:', data); console.log('K线数据点数:', data.kline_data ? data.kline_data.length : 0); - console.log('笔中枢数据点数:', data.bi_zs_list ? data.bi_zs_list.length : 0); // 检查是否包含小周期数据 if (data.element_timeframe) { console.log('小周期笔数据点数:', data.element_bi_list ? data.element_bi_list.length : 0); console.log('小周期线段数据点数:', data.element_seg_list ? data.element_seg_list.length : 0); console.log('小周期中枢数据点数:', data.element_zs_list ? data.element_zs_list.length : 0); - console.log('小周期笔中枢数据点数:', data.element_bi_zs_list ? data.element_bi_zs_list.length : 0); // 更新小周期选择器 $('#elementTimeframe').val(data.element_timeframe); @@ -3517,220 +3507,6 @@ // 更新表格数据 updateTables(data); } - - // 显示中枢 - function displayZones() { - // 主周期或元素周期中枢 - if ($('#showMainZs').is(':checked') || $('#showElementZs').is(':checked') || - $('#showMainUncompletedZs').is(':checked') || $('#showElementUncompletedZs').is(':checked') || - $('#showMainBiZs').is(':checked') || $('#showElementBiZs').is(':checked') || - $('#showMainUncompletedBiZs').is(':checked') || $('#showElementUncompletedBiZs').is(':checked')) { - - console.log('绘制中枢 - 已启用'); - - // 绘制主周期线段中枢 - if ($('#showMainZs').is(':checked') && currentData.zs_list && currentData.zs_list.length > 0) { - console.log(`绘制主周期线段中枢数据,共${currentData.zs_list.length}条`); - drawZoneList(currentData.zs_list, '#F1C40F', 'SEG_ZS'); - } - - // 绘制主周期笔中枢 - if ($('#showMainBiZs').is(':checked') && currentData.bi_zs_list && currentData.bi_zs_list.length > 0) { - console.log(`绘制主周期笔中枢数据,共${currentData.bi_zs_list.length}条`); - // 添加检查笔中枢数据的详细日志 - if (currentData.bi_zs_list.length > 0) { - console.log('笔中枢数据示例:', currentData.bi_zs_list[0]); - } - drawZoneList(currentData.bi_zs_list, '#FF9800', 'BI_ZS'); - } else { - console.log('笔中枢数据不存在或勾选框未选中:', - '勾选状态=', $('#showMainBiZs').is(':checked'), - '数据存在=', !!(currentData.bi_zs_list), - '数据长度=', currentData.bi_zs_list ? currentData.bi_zs_list.length : 0); - } - - // 元素周期线段中枢 - if ($('#showElementZs').is(':checked') && currentData.element_zs_list && currentData.element_zs_list.length > 0) { - console.log(`绘制元素周期线段中枢数据,共${currentData.element_zs_list.length}条`); - drawZoneList(currentData.element_zs_list, '#3f51b5', 'SEG_ZS'); - } - - // 元素周期笔中枢 - if ($('#showElementBiZs').is(':checked') && currentData.element_bi_zs_list && currentData.element_bi_zs_list.length > 0) { - console.log(`绘制元素周期笔中枢数据,共${currentData.element_bi_zs_list.length}条`); - if (currentData.element_bi_zs_list.length > 0) { - console.log('元素笔中枢数据示例:', currentData.element_bi_zs_list[0]); - } - drawZoneList(currentData.element_bi_zs_list, '#9C27B0', 'BI_ZS'); - } else { - console.log('元素笔中枢数据不存在或勾选框未选中:', - '勾选状态=', $('#showElementBiZs').is(':checked'), - '数据存在=', !!(currentData.element_bi_zs_list), - '数据长度=', currentData.element_bi_zs_list ? currentData.element_bi_zs_list.length : 0); - } - - // 主周期未完成线段中枢 - if ($('#showMainUncompletedZs').is(':checked') && currentData.uncompleted_zs_list && currentData.uncompleted_zs_list.length > 0) { - console.log(`绘制主周期未完成线段中枢数据,共${currentData.uncompleted_zs_list.length}条`); - drawZoneList(currentData.uncompleted_zs_list, '#F1C40F', 'SEG_ZS', true); - } - - // 主周期未完成笔中枢 - if ($('#showMainUncompletedBiZs').is(':checked') && currentData.uncompleted_bi_zs_list && currentData.uncompleted_bi_zs_list.length > 0) { - console.log(`绘制主周期未完成笔中枢数据,共${currentData.uncompleted_bi_zs_list.length}条`); - drawZoneList(currentData.uncompleted_bi_zs_list, '#FF9800', 'BI_ZS', true); - } - - // 元素周期未完成线段中枢 - if ($('#showElementUncompletedZs').is(':checked') && currentData.element_uncompleted_zs_list && currentData.element_uncompleted_zs_list.length > 0) { - console.log(`绘制元素周期未完成线段中枢数据,共${currentData.element_uncompleted_zs_list.length}条`); - drawZoneList(currentData.element_uncompleted_zs_list, '#3f51b5', 'SEG_ZS', true); - } - - // 元素周期未完成笔中枢 - if ($('#showElementUncompletedBiZs').is(':checked') && currentData.element_uncompleted_bi_zs_list && currentData.element_uncompleted_bi_zs_list.length > 0) { - console.log(`绘制元素周期未完成笔中枢数据,共${currentData.element_uncompleted_bi_zs_list.length}条`); - drawZoneList(currentData.element_uncompleted_bi_zs_list, '#9C27B0', 'BI_ZS', true); - } - } else { - console.log('绘制中枢 - 已禁用'); - } - } - - // 绘制中枢列表函数 - function drawZoneList(zoneList, color, type, isUncompleted = false) { - zoneList.forEach(function(zs) { - try { - // 直接使用UTC时间戳(秒) - const startTime = Math.floor(new Date(zs.start_time).getTime() / 1000); - // 未完成中枢的结束时间设为当前K线的最后时间 - let endTime; - - if (isUncompleted) { - endTime = Math.floor(new Date(currentData.kline_data[currentData.kline_data.length-1].date).getTime() / 1000); - } else { - endTime = Math.floor(new Date(zs.end_time).getTime() / 1000); - } - - if (isNaN(startTime) || isNaN(endTime)) { - console.error(`${type}中枢时间转换错误:`, zs.start_time, zs.end_time); - return; - } - - const zg = parseFloat(zs.zg); // 中枢上沿 - const zd = parseFloat(zs.zd); // 中枢下沿 - - if (isNaN(zg) || isNaN(zd)) { - console.error(`${type}中枢价格转换错误:`, zs.zg, zs.zd); - return; - } - - // 创建中枢上边界 - const topSeries = mainChart.addLineSeries({ - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0, // 未完成中枢用虚线 - lastValueVisible: false, - priceLineVisible: false, - }); - - topSeries.setData([ - { time: startTime, value: zg }, - { time: endTime, value: zg } - ]); - - // 为下边界创建另一条线 - const bottomSeries = mainChart.addLineSeries({ - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0, // 未完成中枢用虚线 - lastValueVisible: false, - priceLineVisible: false, - }); - - bottomSeries.setData([ - { time: startTime, value: zd }, - { time: endTime, value: zd } - ]); - - // 添加左边界 - const leftSeries = mainChart.addLineSeries({ - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0, // 未完成中枢用虚线 - lastValueVisible: false, - priceLineVisible: false, - }); - - leftSeries.setData([ - { time: startTime, value: zd }, - { time: startTime, value: zg } - ]); - - // 添加右边界 - const rightSeries = mainChart.addLineSeries({ - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0, // 未完成中枢用虚线 - lastValueVisible: false, - priceLineVisible: false, - }); - - rightSeries.setData([ - { time: endTime, value: zd }, - { time: endTime, value: zg } - ]); - - // 储存到相应的系列集合中 - if (type === 'BI_ZS') { - if (color === '#FF9800') { // 主周期笔中枢 - tvWidget.series.mainBiZsSeries.push({ - time: startTime, - value: zg, - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0 - }); - } else { // 元素周期笔中枢 - tvWidget.series.elementBiZsSeries.push({ - time: startTime, - value: zg, - color: color, - lineWidth: 1, - lineStyle: isUncompleted ? 2 : 0 - }); - } - } - } catch (e) { - console.error(`${type}中枢处理出错:`, e); - } - }); - } - - // 辅助函数,在updateTradingViewData或redrawFractalElements中调用 - function displayAllElements() { - console.log('调用displayAllElements,开始绘制所有图形元素...'); - - // 显示笔 - if ($('#showMainBi').is(':checked') || $('#showElementBi').is(':checked')) { - displayBi(); - } - - // 显示线段 - if ($('#showMainSeg').is(':checked') || $('#showElementSeg').is(':checked')) { - displaySeg(); - } - - // 显示中枢(包含线段中枢和笔中枢) - displayZones(); - - // 显示买卖点 - if ($('#showTradePoints').is(':checked')) { - displayTradePoints(); - } - - console.log('displayAllElements执行完成'); - } \ No newline at end of file