From 48d5647ebf63a26ea48d01019d3b2bb4c71389e3 Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Wed, 23 Apr 2025 10:39:04 +0800 Subject: [PATCH] Add some classifier code --- .DS_Store | Bin 6148 -> 6148 bytes ChanBI.py | 19 ++- ChanKLC.py | 21 +++- ChanLun.py | 113 +++++++++++++----- ChanLun_Classifier.py | 31 +++-- ChanSEG.py | 2 +- __pycache__/ChanBI.cpython-312.pyc | Bin 4790 -> 6444 bytes __pycache__/ChanBSP.cpython-312.pyc | Bin 1359 -> 1368 bytes __pycache__/ChanKLC.cpython-312.pyc | Bin 17033 -> 19434 bytes __pycache__/ChanKLU.cpython-312.pyc | Bin 2125 -> 2134 bytes __pycache__/ChanLun.cpython-312.pyc | Bin 108624 -> 111772 bytes .../ChanLun_Classifier.cpython-312.pyc | Bin 15561 -> 17079 bytes __pycache__/ChanSEG.cpython-312.pyc | Bin 3481 -> 3479 bytes __pycache__/ChanZS.cpython-312.pyc | Bin 3796 -> 3805 bytes 14 files changed, 139 insertions(+), 47 deletions(-) diff --git a/.DS_Store b/.DS_Store index 462effb19475fd3a8683c87cb61bf1b860cc5e88..6cd3efbfbdcb01df3ab8c2d15aee50b6d5fa35ec 100644 GIT binary patch delta 67 zcmZoMXfc=|#>B)qu~2NHo+2aX#(>?7jGU8sST=87!5YuBvEe1tW_AvK4xp0Ff*jwO VC-aLqaxee^BLf4=<_M8B%m8ex5S9P{ delta 299 zcmZoMXfc=|#>B!ku~2NHo+2an#(>?7ivyUM7`Z3&Fm0}9VQ^;1U`S-hODZoeNXp4i zVqjp{nN*OISzKaZaE+0PnT3^&or9f&nXr1w@?l^GXsk^HPhz8ZuK-fl6Y+GxJjN%boH|^HPezdV|3d=|voz9Gvk2lGW8l z2Il5E3g$*ewK@vbmPQ6T3MR&8wY8iaqRRT#LGjr+xq12BK-U2QBO`=n;DypKst3q` y`=~6qC@&{JFC8exxOop#64PdO4t@?`P;7Q&{?0s^U&N6EXbuxd@8$@RHOv61w@hCE diff --git a/ChanBI.py b/ChanBI.py index e4b3287..d8d3e78 100644 --- a/ChanBI.py +++ b/ChanBI.py @@ -18,10 +18,25 @@ class ChanBI(): self.start_time = klc.start_time self.macd_hist = 0 self.macd_div = 0 - def set_macd_hist(self, macd_hist): + def set_macdhist(self, macd_hist): self.macd_hist = macd_hist def set_macd_div(self, macd_div): self.macd_div = macd_div + def cal_macd_div(self): + self.macd_div = 0.0 + if self.pre and self.pre.pre: + if self.pre.pre.macd_hist == 0: + self.macd_div = 0.0 + else: + self.macd_div = self.macd_hist / self.pre.pre.macd_hist + def cal_macdhist(self): + self.macd_hist = 0 + for klc in self.klc_list: + for klu in klc.klus: + 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: + self.macd_hist -= klu.macdhist def check_overlap(self): if self.next and self.next.next: if self.dir == Chan_BI_DIR.UP: @@ -61,6 +76,8 @@ class ChanBI(): break if not added: self.klc_list.append(klc) + self.cal_macdhist() + self.cal_macd_div() def append_klc_list(self, klc_list): self.klc_list.append(klc_list) def update_bi(self, klc): diff --git a/ChanKLC.py b/ChanKLC.py index 491179e..7c40a75 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -26,6 +26,9 @@ class ChanKLC(): self.close = klu.close self.volume = klu.volume self.macdhist = 0 + self.bi_macdhist = 0 + self.bi_macd_div = 0.0 + self.bi = None def add_klu(self, klu): self.klus.append(klu) def set_end_klu(self, klu): @@ -116,10 +119,10 @@ class ChanKLC(): if klc.index == self.index: break else: - if bi.dir == Chan_BI_DIR.UP: - self.macdhist += klc.get_macdhist() - else: - self.macdhist -= klc.get_macdhist() + if bi.dir == Chan_BI_DIR.UP and klc.get_macdhist() > 0: + self.bi_macdhist += klc.get_macdhist() + elif bi.dir == Chan_BI_DIR.DOWN and klc.get_macdhist() < 0: + self.bi_macdhist -= klc.get_macdhist() def get_macdhist(self): self.macdhist = 0 for klu in self.klus: @@ -158,8 +161,14 @@ class ChanKLC(): features['klc_fx'] = 0 if self.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.fx == Chan_FX_TYPE.TOP else 2 #7 features['klc_klus'] = len(self.klus) #8 features['klc_volume'] = self.volume #9 - 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 - + 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 + # New Add 20250422 + #features['klc_macdhist'] = self.get_macdhist() #11 + #features['klc_bi_macdhist'] = self.bi_macdhist #12 + #features['klc_bi_macd_div'] = self.bi_macd_div #13 + #features['klc_bi_dir'] = 1 if self.bi.dir == Chan_BI_DIR.UP else -1 #14 # ===== 2.1 K线形态因子 ===== # K线实体大小 diff --git a/ChanLun.py b/ChanLun.py index 486531e..dc29327 100644 --- a/ChanLun.py +++ b/ChanLun.py @@ -15,6 +15,9 @@ from matplotlib.dates import DateFormatter, date2num import matplotlib.patches as patches from technical.util import resample_to_interval from decimal import Decimal +import xgboost as xgb +import numpy as np + class ChanLun(): timeframes = ["5m", "15m", "30m", "60m", "4h"] times = { @@ -29,7 +32,6 @@ class ChanLun(): time30 = 30 time60 = 60 time4h = 240 - def create_all_data(self, dataframe, ticker_indicator): all_data = dict() all_data['1m'] = dataframe @@ -910,8 +912,8 @@ class ChanLun(): #self.print_zs(zs_list) return zs_list - def get_bi_macd_hist_list(self, bi_list, dataframe): - bi_macd_hist_list = [] + def get_bi_macdhist_list(self, bi_list, dataframe): + bi_macdhist_list = [] for bi in bi_list: start_index = bi.start_klc.start_klu.index if bi.end_klc: @@ -925,12 +927,12 @@ class ChanLun(): total_macd_hist += macd_hist if bi.dir == Chan_BI_DIR.DOWN and macd_hist < 0: total_macd_hist -= macd_hist - bi_macd_hist_list.append(abs(total_macd_hist)) - bi.set_macd_hist(total_macd_hist) - return bi_macd_hist_list, bi_list + bi_macdhist_list.append(abs(total_macd_hist)) + bi.set_macdhist(total_macd_hist) + return bi_macdhist_list, bi_list - def get_seg_macd_hist_list(self, seg_list, dataframe): - seg_macd_hist_list = [] + def get_seg_macdhist_list(self, seg_list, dataframe): + seg_macdhist_list = [] for seg in seg_list: start_index = seg.start_bi.start_klc.start_klu.index if seg.end_bi: @@ -944,46 +946,46 @@ class ChanLun(): total_macd_hist += macd_hist if seg.dir == Chan_SEG_DIR.DOWN and macd_hist < 0: total_macd_hist -= macd_hist - seg_macd_hist_list.append(abs(total_macd_hist)) - seg.set_macd_hist(total_macd_hist) - return seg_macd_hist_list, seg_list + seg_macdhist_list.append(abs(total_macd_hist)) + seg.set_macdhist(total_macd_hist) + return seg_macdhist_list, seg_list def get_bi_macd_div_list(self, bi_list, dataframe): bi_macd_div_list = [] - bi_macd_hist_list, bi_list = self.get_bi_macd_hist_list(bi_list, dataframe) + bi_macdhist_list, bi_list = self.get_bi_macdhist_list(bi_list, dataframe) for index in range(2, len(bi_list)): - if bi_macd_hist_list[index-2] == 0: + if bi_macdhist_list[index-2] == 0: bi_macd_div = 0.0 - if index > 3 and bi_macd_hist_list[index-4] > 0.0: - bi_macd_div = bi_macd_hist_list[index]/bi_macd_hist_list[index-4] + if index > 3 and bi_macdhist_list[index-4] > 0.0: + bi_macd_div = bi_macdhist_list[index]/bi_macdhist_list[index-4] else: - bi_macd_div = bi_macd_hist_list[index]/bi_macd_hist_list[index-2] + bi_macd_div = bi_macdhist_list[index]/bi_macdhist_list[index-2] if bi_macd_div < 0.01: - if index > 3 and bi_macd_hist_list[index-4] > 0.0: - bi_macd_div = bi_macd_hist_list[index]/bi_macd_hist_list[index-4] + if index > 3 and bi_macdhist_list[index-4] > 0.0: + bi_macd_div = bi_macdhist_list[index]/bi_macdhist_list[index-4] bi_macd_div = self.get_decimal(bi_macd_div) bi_macd_div_list.append(bi_macd_div) bi_list[index].set_macd_div(bi_macd_div) - #print(bi_list[index].start_klc.start_time, self.get_decimal(bi_macd_hist_list[index]), self.get_decimal(bi_macd_hist_list[index - 1]), self.get_decimal(bi_macd_div)) + #print(bi_list[index].start_klc.start_time, self.get_decimal(bi_macdhist_list[index]), self.get_decimal(bi_macdhist_list[index - 1]), self.get_decimal(bi_macd_div)) return bi_macd_div_list, bi_list def get_seg_macd_div_list(self, seg_list, dataframe): seg_macd_div_list = [] - seg_macd_hist_list, seg_list = self.get_seg_macd_hist_list(seg_list, dataframe) + seg_macdhist_list, seg_list = self.get_seg_macdhist_list(seg_list, dataframe) for index in range(2, len(seg_list)): - if seg_macd_hist_list[index-2] == 0: + if seg_macdhist_list[index-2] == 0: seg_macd_div = 0.0 - if index > 3 and seg_macd_hist_list[index-4] > 0.0: - seg_macd_div = seg_macd_hist_list[index]/seg_macd_hist_list[index - 4] + if index > 3 and seg_macdhist_list[index-4] > 0.0: + seg_macd_div = seg_macdhist_list[index]/seg_macdhist_list[index - 4] else: - seg_macd_div = seg_macd_hist_list[index]/seg_macd_hist_list[index - 2] + seg_macd_div = seg_macdhist_list[index]/seg_macdhist_list[index - 2] if seg_macd_div < 0.01: - if index > 3 and seg_macd_hist_list[index-4] > 0.0: - seg_macd_div = seg_macd_hist_list[index]/seg_macd_hist_list[index - 4] + if index > 3 and seg_macdhist_list[index-4] > 0.0: + seg_macd_div = seg_macdhist_list[index]/seg_macdhist_list[index - 4] seg_macd_div = self.get_decimal(seg_macd_div) seg_macd_div_list.append(seg_macd_div) seg_list[index].set_macd_div(seg_macd_div) - #print(seg_list[index].start_bi.start_klc.start_time, self.get_decimal(seg_macd_hist_list[index]), self.get_decimal(seg_macd_hist_list[index - 1]), self.get_decimal(seg_macd_div)) + #print(seg_list[index].start_bi.start_klc.start_time, self.get_decimal(seg_macdhist_list[index]), self.get_decimal(seg_macdhist_list[index - 1]), self.get_decimal(seg_macd_div)) return seg_macd_div_list, seg_list def get_macd_div_list(self, dataframe): @@ -1596,7 +1598,7 @@ class ChanLun(): for index in range(0, len(big_bi_macd_div)): bi_macd_div = big_bi_macd_div[index] bi = big_bi[index + 2] - if bi.end_klc: + if bi.end_klc and False: text_index = bi.end_klc.end_klu.index if bi.dir == Chan_BI_DIR.UP: ax1.text(big_dates_num[text_index], bi.end_klc.high+1, bi_macd_div, color='red', fontsize=10, alpha=0.6) @@ -1605,12 +1607,24 @@ class ChanLun(): for index in range(0, len(big_seg_macd_div)): seg_macd_div = big_seg_macd_div[index] seg = big_seg[index + 2] - if seg.end_bi: + if seg.end_bi and False: text_index = seg.end_bi.end_klc.end_klu.index if seg.dir == Chan_SEG_DIR.UP: ax1.text(big_dates_num[text_index], seg.end_bi.end_klc.high+1, seg_macd_div, color='red', fontsize=14, alpha=0.6) else: ax1.text(big_dates_num[text_index], seg.end_bi.end_klc.low-1, seg_macd_div, color='green', fontsize=14, alpha=0.6) + big_klc = self.get_klc_list(big_df) + model = xgb.Booster() + model.load_model("30m_modelchan_xgb_model.json") + for klc in big_klc: + predict = self.predict(klc, model) + if predict > 0.35 and klc.fx == Chan_FX_TYPE.BOTTOM: + text_index = klc.end_klu.index + ax1.text(big_dates_num[text_index], klc.high+1, predict, color='red', fontsize=14, alpha=0.6) + if predict > 0.35 and klc.fx == Chan_FX_TYPE.TOP: + text_index = klc.end_klu.index + ax1.text(big_dates_num[text_index], klc.low-1, predict, color='green', fontsize=14, alpha=0.6) + """ # 绘制大周期买卖点 marker_styles = { @@ -1748,7 +1762,7 @@ class ChanLun(): for index in range(0, len(small_bi_macd_div)): bi_macd_div = small_bi_macd_div[index] bi = small_bi[index + 2] - if bi.end_klc: + if bi.end_klc and False: text_index = bi.end_klc.end_klu.index if bi.dir == Chan_BI_DIR.UP: ax2.text(small_dates_num[text_index], bi.end_klc.high+1, bi_macd_div, color='red', fontsize=10, alpha=0.6) @@ -1757,12 +1771,23 @@ class ChanLun(): for index in range(0, len(small_seg_macd_div)): seg_macd_div = small_seg_macd_div[index] seg = small_seg[index + 2] - if seg.end_bi: + if seg.end_bi and False: text_index = seg.end_bi.end_klc.end_klu.index if seg.dir == Chan_SEG_DIR.UP: ax2.text(small_dates_num[text_index], seg.end_bi.end_klc.high+1, seg_macd_div, color='red', fontsize=14, alpha=0.8) else: ax2.text(small_dates_num[text_index], seg.end_bi.end_klc.low-1, seg_macd_div, color='green', fontsize=14, alpha=0.8) + small_klc = self.get_klc_list(small_df) + model = xgb.Booster() + model.load_model("5m_modelchan_xgb_model.json") + for klc in small_klc: + predict = self.predict(klc, model) + if predict > 0.35 and klc.fx == Chan_FX_TYPE.BOTTOM: + text_index = klc.end_klu.index + ax2.text(small_dates_num[text_index], klc.high+1, predict, color='red', fontsize=14, alpha=0.6) + if predict > 0.35 and klc.fx == Chan_FX_TYPE.TOP: + text_index = klc.end_klu.index + ax2.text(small_dates_num[text_index], klc.low-1, predict, color='green', fontsize=14, alpha=0.6) """ # 绘制小周期买卖点 for idx, point in small_buy_sell_points.items(): @@ -1806,7 +1831,33 @@ class ChanLun(): plt.xticks(rotation=45) plt.tight_layout() plt.show() + + + def predict(self, klc, model): + """ + 使用训练好的模型预测单个KLC + :param klc: 需要预测的ChanKLC对象 + :return: 预测结果(概率值) + """ + # 提取特征 + features = klc.get_feature_data() + feature_vec = [] + # 与get_feature_data保持一致,只使用相同的特征集 + for key, value in features.items(): + if isinstance(value, (int, float)): + feature_vec.append(value) + else: + feature_vec.append(0) + + # 转换为模型输入格式 + dtest = xgb.DMatrix(np.array([feature_vec])) + # 预测 + return self.get_decimal(model.predict(dtest)[0]) + + def get_decimal(self, value): + return Decimal("{:.2f}".format(value)) + def plot(self, dataframe, bi_list, seg_list, zs_list=None, buy_sell_points=None, divergence_points=None): """ 绘制缠论分析图表,包括K线、笔、线段、中枢、买卖点和MACD背驰 diff --git a/ChanLun_Classifier.py b/ChanLun_Classifier.py index 0efe169..9261dcf 100644 --- a/ChanLun_Classifier.py +++ b/ChanLun_Classifier.py @@ -281,13 +281,18 @@ class ChanLunClassifier: # 使用ChanLun获取bi_list bi_list = self.chan.cal_bi_list(self.chan.get_klc_list(dataframe)) klc_list = self.chan.get_klc_list(dataframe) + seg_list = self.chan.get_seg_list(bi_list) # 筛选方向为UP的bi的起始klc feature_data = [] labels = [] bi_index = 0 + sample_list = [] for klc in klc_list: - if bi_index == len(bi_list): + if klc.fx != Chan_FX_TYPE.UNKNOWN: + sample_list.append(klc) + for klc in sample_list: + if bi_index >= len(bi_list): bi_index = len(bi_list) - 1 bi = bi_list[bi_index] if klc.end_klu and bi.end_klc and klc.start_klu.index >= bi.start_klc.start_klu.index and klc.end_klu.index <= bi.end_klc.end_klu.index: @@ -306,9 +311,11 @@ class ChanLunClassifier: # 判断这个bi是否赚钱(这里简单定义为:如果bi的结束价格高于起始价格,则标记为1,否则为0) # 这个标签定义可以根据实际需求修改 - if bi.start_klc.index == klc.index: + seg = seg_list[bi_index] + if bi.start_klc.index == klc.index and bi.dir == Chan_BI_DIR.UP: + #if klc.index == seg.start_bi.start_klc.index and seg.dir == Chan_SEG_DIR.UP: label = 1 - bi_index += 1 + bi_index += 2 else: label = 0 @@ -325,12 +332,17 @@ class ChanLunClassifier: # 使用ChanLun获取bi_list bi_list = self.chan.cal_bi_list(self.chan.get_klc_list(dataframe)) klc_list = self.chan.get_klc_list(dataframe) + seg_list = self.chan.get_seg_list(bi_list) # 筛选方向为UP的bi的起始klc feature_data = [] labels = [] bi_index = 0 + sample_list = [] for klc in klc_list: - if bi_index == len(bi_list): + if klc.fx != Chan_FX_TYPE.UNKNOWN: + sample_list.append(klc) + for klc in sample_list: + if bi_index >= len(bi_list): bi_index = len(bi_list) - 1 bi = bi_list[bi_index] # 提取特征 @@ -344,10 +356,11 @@ class ChanLunClassifier: feature_vec.append(value) else: feature_vec.append(0) - - if bi.start_klc.index == klc.index: + seg = seg_list[bi_index] + if bi.start_klc.index == klc.index and bi.dir == Chan_BI_DIR.UP: + #if klc.index == seg.start_bi.start_klc.index and seg.dir == Chan_SEG_DIR.UP: label = 1 - bi_index += 1 + bi_index += 2 else: label = 0 @@ -433,6 +446,8 @@ class ChanLunClassifier: dtest = xgb.DMatrix(np.array([feature_vec])) # 预测 - return self.model.predict(dtest)[0] + return self.get_decimal(self.model.predict(dtest)[0]) + def get_decimal(self, value): + return Decimal("{:.2f}".format(value)) diff --git a/ChanSEG.py b/ChanSEG.py index 7cbd1cd..0eb1174 100644 --- a/ChanSEG.py +++ b/ChanSEG.py @@ -26,7 +26,7 @@ class ChanSEG(): self.sure_time = None self.macd_hist = 0 self.macd_div = 0 - def set_macd_hist(self, macd_hist): + def set_macdhist(self, macd_hist): self.macd_hist = macd_hist def set_macd_div(self, macd_div): self.macd_div = macd_div diff --git a/__pycache__/ChanBI.cpython-312.pyc b/__pycache__/ChanBI.cpython-312.pyc index 52a365c0cafe3f7b6a1de40d094d698813ce5825..8b5d9cb6f44f82d612da3c3008529b74c2bf1eab 100644 GIT binary patch delta 1854 zcmZuyZ%k8H6u6?jkN{pCYFvP12{UX7jBR|_7eAWpQ^Ad{bIFo@U$kb~;*w?OJSZUHrup6b?)jZ_ z?>*;tZ@(}9s$Txl;m9S>p7YkuKcxw|mtLK?7IW(IHF7pjR{+(1XVA6q?|YVj6zhn$ zcDJ?bofl*A0kx^Kt*7z${_G^X!v7$;DIt?Yr>sTUon!PSNEgSFIjWDtHC}ASxvZ6% zoErW`JAUchrAk5!QKt#gx?%1o;K{QYS!M4k`P|wPLp!(+*a=X#I`)%(60}4vWMdh) zv7p5$fX)CmF+2eGso{k#28SV4_)2|_?V=;MZ^54 zBV|{{LZ60i^Hbs-aZ0)?r4)6nZ=`Q5F_KtS%9Bd@m#$@{Dy5Z<^S2zoYh|0`j zb?=f{o#?5I(b4G6ZV(+x0QN*S{?N|E0Vol~&ju!=_joe;HIMb=B5P$7&Egq(z)AC$ zqP;N#k7Gb`NSb^5R9ehxH_eAno{2!&vC2jc+AYXOrZ%K)FZl~{&z2k~HQ>iS0f378 z3Zde1N-dZ?a`VV=Q>vhFvhQZ!xCLiI6QO$_OS!7*sgIt`lQ%WE(w=PV$x2Ty&9K~rieVyXZ zQs&m51W;l%DA8g*25_Z$3)~}iUd(6T*gb`K{Xra6x@C}~q=)h(!NrO;9u6Bk0)Zj; z#H+ilf%?rx@wEVPZf~1*kPsg^W@_lIpfzoYcJ!=?NHE%ZE_4{^Y^Vr(5y}99{HAu) zw9uyO9lFVj@nF?7wpZ4Mj=?Z?4FKff%pVpW+vVZ-*x<k+uZBstBO{z&t3jEFh^_I+K;1p zgj$3{2!|0G5MD)SLO2R=pO`W>Ut9yFV**Moc81ZsvT%;@8qLU7;XuY|6?_Qg87C(M zGC4VdHzQNQli{gQkl}L$f5t|CC=@pTN2PpP@qbFrcOvfdl* hc*SUeITUdW{}G;8D5bv=`8T5d&7Gk%kRgbsnSn(oXwk*}1oXktq-OC_Hs|7Lc^Xl4c8;?$D(+{EOR_>9cr zk}47BjKn-APd&KkYPs07z&u7D-G##%;_fx%n5j4->x% zNCG5#i^au1+;4ISUjn1zVt+=QccbxkbOlwAc7f0 zz#Uwq4&s9RRKy1&1VM!PWOZ>JM(fET;x&vylP`*EF{(`dBQB$<3X;?U5gH&u4@4M& z2on%t0V1qGgw14c2{}fe$ypLAlV?iE6*ICbePUr`RsYPw&MH?V15&~YBs5uy9Dvj< z4p6YW=9T6`+y;^=as&}zl~O>~FAkgB{FKt1RJ$T)AeRw{i$#IN2WCb_#@h^hcNrAE OGuboBePRF-U~K@IL~<lY NCVeKxTa)Ej4FM`K6F>j} delta 50 zcmcb?b)Jj!G%qg~0}yQ7$a#@T#9TkLIJKx)KPxdgTR)&EKPxr4Wb=0>eI~|Vlhs)b E0fo;H6aWAK diff --git a/__pycache__/ChanKLC.cpython-312.pyc b/__pycache__/ChanKLC.cpython-312.pyc index 2a7b85d2069c185331194b42e552b907b4f6cd3e..9ba2066309902e4481fc51bb8b215d1a6f88c6b7 100644 GIT binary patch delta 4071 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 Dca$#T diff --git a/__pycache__/ChanKLU.cpython-312.pyc b/__pycache__/ChanKLU.cpython-312.pyc index 9037ccf00c0b799ba76aadd077bad4132f958d1e..2fe6c5eeea93195ddfb8a26d27e1e914f29ba38a 100644 GIT binary patch delta 59 zcmX>ra7}>oG%qg~0}xEv$Z5_b>!2T6oLW?@pOu)Lt?!bbT$-DjS5mC+o>}5inzT8D N=`1Vbt;tFp+5ik35}E)2 delta 50 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 S2IQ!}lV`}~5}FcX*H zBon+_Alu?_b5XWzV%VZ?I%ka2=|5DWCDl2WWq<6CWem)gnJn2ouhhaHi_t&!lK$>F z=bd}rx#!;VyZ!#)`8R0YZLL;CktecVzU%C|bGm~PdI#>6*o_)adYEpMb6QSDMg^zC zS0$!&9j7FkhEpA;8nv97AerINkNqN1TA5rKo-X(h4^*XN){@f{mbOu08Tqjs9hQ?( zAxPFz+m}#OSSct23i#~8hZj=;TR^k$4QRWoC@Mtv*#t#EkFP3BxIRZ&PE&mqQc6&) zrTXdZ$HdTb-k6vyFrU(Kd3O^Dv%}0)>0GRsx+&_kGu#W=ed|gd41KKOBTt)NL+HnC3KZ)B+5V@ zK3SQi3ad$tG=e%{BWjUF8`kj!i4O}pzAz#4#rUVnREZ{D1*0ypL{bWuAX-%>{CKfJ zE1g@Uo-8JwC?u^6WZ;KI=>TG3H3$h-)74~`gdi9J`U zASvNh_F|1X739z zCk>XUAwOcsAFjA-D4CW~=Ilo-WzNI@IE#D0z5C7XA@o7lyIp5m&UTD+L|v;RuGQbZ za-->LQ?zzlq;^}h)*Gqy-f?-yeg3GgGve!v`u0bB`^US(e^Hb`uVem*5298V*XkHi zYlv$N%nU`f(GAR`!8E8EPz|}?)=je%lVQP|91UeA%h0k&N+G0gJSH3wqIz3IZyVlp zdh5xpcl54N_xZ|mm6x_%*>Q2lor(=pxZmYa-P2g7Um)vvv>Z=6w$LZ=?*$+IuRP>R z^3Zm&Rzh%3Wg+bX7Q!~xe7s00pW^_$v7D$1Tw0_Si6EUE1@R$7kdcu2tmhztY@j1L z7n+PvLGBYOuqL7=M?OCx2MV8o3M})epzm)&1SLOVxCC$+02&&718@ZZIvI5UbOKxl@B@4Ya18)j8QlPYo<%nSNROH* zbPL4W1fDeCPG>E(Um*|`SnUZSF&{p>s0C2;ONW7k{(nc+U9 z{{Y|zfG=>r-GX2BxarW?QO^aMIYpBjI%}-Caw$z`ihGe)m_}Q0d;@eck;C!Ls*ihO zFdz27p+j&CL{j_jvWk^Q;1>b_!V_y5Qv?5Utu6izZ#xRp zub~bvPgF5oNG$|`tyTm#F`6RKm9u7-H~7-t;F@-CDCGC~TajztdaptL5bSm8fj+JO zz+lfn&+y)fbi%~0afM4v*1^`{>(x2xpCP7=fJ2XetM)j=)BYY9PXK%gARg*7AUy50Mjuw$_dyd@Q~$tjoROv;dm1!S3JcUyAO!@MFmAM->#DaBN?8CiD4^v>93&WzQ{ z5Aa!==34Hg1_@b%$vLu%aK|EcfYfV{D$fyI$vpT}TIOK;&4MrGfqd1H*lAe)l+?kq zs#MGIZT(Q0B8XYLRGq1bC4A%HOgywb48al%2fE23+*O|Og6#ZSzL1?oICEasV)KfD zED0*V1n{`;W3trBZ{&0l3iOk3O)nsR7}Y}}O|qrX7+$bkN_2Ma=rAVaE;B*Rmfh{! zX_!5u9SjrhY|w1mvtxp9-A|8VP)tyo=mLHE*|Xx~EIMxf+$4`Lr;2+@YPgBV8K zMcDGA()2#!fi3Lknp$T)`v$wJe^+<>hq?zG3iq?N?$=83`$b$HlQ(lEniM_HFyV8= z7zFE@$o91VF)qzf=Qf_RJ=g~=7GrPEm7WhhyBV)pT#BRy|?p)p_RLg`CiMW27n zSNYsk2^UwDdS2m*5QFZ8u~myp?ALq-gXa)~2>Uhnq4fgM50Q9?#9@6rl3yV%n{Fay r;<68oWU=V}&`t`(DmWDnlHtr?d>tk delta 61 zcmbO(JyV+ZG%qg~0}zP3{+jN%k@o|OB5!eONqlZ%a!PzgW^qZCsB=bQUa+gX9$a{{ I3~Mz909^YNLI3~& diff --git a/__pycache__/ChanZS.cpython-312.pyc b/__pycache__/ChanZS.cpython-312.pyc index de2cfbc95afc5da96fd3afb36dd1eeca15da55a6..543e39b6e0e9a6ca8765006009272695ab0e4358 100644 GIT binary patch delta 59 zcmca2dsmk8G%qg~0}$wJ}5inzWgd NWil7zt;uuw%mE$C6CMBn delta 50 zcmcaBdqtM>G%qg~0}$wL@&Et;