From cdc40f795c9912dd37a6ae18e370fc99c20d4f2b Mon Sep 17 00:00:00 2001 From: Porter Date: Sat, 24 May 2025 22:42:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=86=E5=9E=8B=E5=BC=BA?= =?UTF-8?q?=E5=BC=B1=E8=AE=A1=E7=AE=97=EF=BC=8C=E5=8F=AF=E4=BB=A5=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E8=B7=91=E6=9C=8D=E5=8A=A1=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChanKLC.py | 350 +++++++++++++++++++++++++- __pycache__/ChanBI.cpython-312.pyc | Bin 6715 -> 6709 bytes __pycache__/ChanBSP.cpython-312.pyc | Bin 1359 -> 1368 bytes __pycache__/ChanCTime.cpython-312.pyc | Bin 3396 -> 3405 bytes __pycache__/ChanEnum.cpython-312.pyc | Bin 6292 -> 6301 bytes __pycache__/ChanKLC.cpython-312.pyc | Bin 61874 -> 72403 bytes __pycache__/ChanKLU.cpython-312.pyc | Bin 3698 -> 3707 bytes __pycache__/ChanLun.cpython-312.pyc | Bin 111155 -> 110786 bytes __pycache__/ChanSBI.cpython-312.pyc | Bin 3867 -> 3876 bytes __pycache__/ChanSEG.cpython-312.pyc | Bin 3479 -> 3488 bytes __pycache__/ChanZS.cpython-312.pyc | Bin 3796 -> 3805 bytes web/app.py | 6 +- web/templates/index.html | 22 +- 13 files changed, 365 insertions(+), 13 deletions(-) diff --git a/ChanKLC.py b/ChanKLC.py index 0e9d994..35d88f4 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -49,6 +49,7 @@ class ChanKLC(): self.volume_ratio = self.volume_ratio / len(self.klus) self.volume = self.volume / len(self.klus) self.macdhist = self.macdhist / len(self.klus) + def set_next(self, klc): self.next = klc def set_pre(self, klc): @@ -1132,7 +1133,7 @@ class ChanKLC(): # ===== 分型强度特征 ===== # 添加分型强度相关特征 - features['klc_fx_strength'] = self.calculate_fx_strength() + features['klc_fx_strength'] = self.cal_fx_strength() features['klc_fx_strength_level'] = self.get_fx_strength_level() features['klc_is_strong_fx'] = 1 if self.is_strong_fx() else 0 @@ -1146,6 +1147,269 @@ class ChanKLC(): return features + def cal_fx_strength(self): + """ + 用self.pre和self.next实现分型强弱判断 + + 核心缠论原理: + - 强分型:出现在笔的末端,能够终结当前笔,标志着趋势转折 + - 弱分型:出现在笔的中间,是中继性质,笔还会继续延伸 + + 返回值: + 3: 极强分型(笔终结+强确认) + 2: 强分型(笔终结) + 1: 偏强分型(可能终结笔) + 0: 中性分型 + -1: 偏弱分型(中继特征明显) + -2: 弱分型(明显中继) + -3: 极弱分型(无效分型) + """ + # 检查是否为分型,且有前后K线数据 + if self.fx == Chan_FX_TYPE.UNKNOWN: + return 0 + if not self.pre or not self.next: + return 100 + # === 核心判断:分型在笔中的位置 === + + # 1. 检查这个分型是否能够终结当前笔 + is_bi_end = self._check_if_bi_ending_fx() + + # 2. 检查分型的后续走势确认 + post_fx_confirmation = self._check_post_fx_confirmation() + + # 3. 检查分型的标准性和强度 + fx_quality = self._check_fx_quality() + + # === 综合评分 === + base_score = 0 + + # 笔位置是最重要的判断标准 + if is_bi_end == 2: # 强烈确认笔终结 + base_score = 2 + elif is_bi_end == 1: # 可能笔终结 + base_score = 1 + elif is_bi_end == -1: # 明显中继 + base_score = -2 + elif is_bi_end == -2: # 强烈中继特征 + base_score = -3 + else: # 不确定 + base_score = 0 + + # 后续确认调整 + base_score += post_fx_confirmation + + # 分型质量调整 + base_score += fx_quality + print(self.start_time, base_score, is_bi_end, post_fx_confirmation, fx_quality) + # 限制在-3到3范围内 + return max(-3, min(3, base_score)) + + def _check_if_bi_ending_fx(self): + """ + 检查分型是否为笔终结分型 + 返回值: + 2: 强烈确认笔终结 + 1: 可能笔终结 + 0: 不确定 + -1: 明显中继 + -2: 强烈中继特征 + """ + # 检查是否有足够的后续数据来判断 + if not self.next or not hasattr(self.next, 'next'): + return 0 + + # 获取分型后的几根K线数据 + subsequent_klcs = [] + temp = self.next + for i in range(5): # 检查后续5根K线 + if temp: + subsequent_klcs.append(temp) + temp = temp.next if hasattr(temp, 'next') else None + else: + break + + if len(subsequent_klcs) < 2: + return 0 + + if self.fx == Chan_FX_TYPE.TOP: + return self._check_top_bi_ending(subsequent_klcs) + else: # BOTTOM + return self._check_bottom_bi_ending(subsequent_klcs) + + def _check_top_bi_ending(self, subsequent_klcs): + """检查顶分型是否为笔终结""" + # 强烈笔终结特征: + # 1. 后续K线持续下跌,且跌破关键位置 + # 2. 没有新的更高的高点出现 + + broken_key_levels = 0 + new_highs = 0 + downward_trend = 0 + + # 检查关键价位突破 + first_low = self.pre.low + middle_low = self.low + key_support = min(first_low, middle_low) + + for i, klc in enumerate(subsequent_klcs): + # 检查是否跌破关键支撑 + if klc.low < key_support: + broken_key_levels += 1 + + # 检查是否出现新高 + if klc.high > self.high: + new_highs += 1 + + # 检查下跌趋势 + if i > 0 and klc.close < subsequent_klcs[i-1].close: + downward_trend += 1 + + # 强烈笔终结:跌破关键位且无新高 + if broken_key_levels >= 1 and new_highs == 0 and downward_trend >= 2: + return 2 + + # 可能笔终结:部分条件满足 + if (broken_key_levels >= 1 and new_highs <= 1) or (new_highs == 0 and downward_trend >= 3): + return 1 + + # 明显中继:出现新高且未跌破关键位 + if new_highs >= 2 and broken_key_levels == 0: + return -2 + + # 中继倾向:出现新高 + if new_highs >= 1: + return -1 + + return 0 + + def _check_bottom_bi_ending(self, subsequent_klcs): + """检查底分型是否为笔终结""" + # 强烈笔终结特征: + # 1. 后续K线持续上涨,且突破关键位置 + # 2. 没有新的更低的低点出现 + + broken_key_levels = 0 + new_lows = 0 + upward_trend = 0 + + # 检查关键价位突破 + first_high = self.pre.high + middle_high = self.high + key_resistance = max(first_high, middle_high) + + for i, klc in enumerate(subsequent_klcs): + # 检查是否突破关键阻力 + if klc.high > key_resistance: + broken_key_levels += 1 + + # 检查是否出现新低 + if klc.low < self.low: + new_lows += 1 + + # 检查上涨趋势 + if i > 0 and klc.close > subsequent_klcs[i-1].close: + upward_trend += 1 + + # 强烈笔终结:突破关键位且无新低 + if broken_key_levels >= 1 and new_lows == 0 and upward_trend >= 2: + return 2 + + # 可能笔终结:部分条件满足 + if (broken_key_levels >= 1 and new_lows <= 1) or (new_lows == 0 and upward_trend >= 3): + return 1 + + # 明显中继:出现新低且未突破关键位 + if new_lows >= 2 and broken_key_levels == 0: + return -2 + + # 中继倾向:出现新低 + if new_lows >= 1: + return -1 + + return 0 + + def _check_post_fx_confirmation(self): + """ + 检查分型后的走势确认 + 返回值:-1到1的调整分数 + """ + if not self.next: + return 0 + + score = 0 + + # 检查第三根K线的确认 + third_klc = self.next + + if self.fx == Chan_FX_TYPE.TOP: + # 顶分型:第三根K线应该走弱 + middle_price = (self.high + self.low) / 2 + + if third_klc.close < middle_price: + score += 0.5 + if third_klc.low < self.pre.low: # 跌破第一根K线低点 + score += 0.5 + if third_klc.close < third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5: + score += 0.3 # 明显阴线 + + else: # BOTTOM + # 底分型:第三根K线应该走强 + middle_price = (self.high + self.low) / 2 + + if third_klc.close > middle_price: + score += 0.5 + if third_klc.high > self.pre.high: # 突破第一根K线高点 + score += 0.5 + if third_klc.close > third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5: + score += 0.3 # 明显阳线 + + return min(1, max(-1, score)) + + def _check_fx_quality(self): + """ + 检查分型本身的质量 + 返回值:-1到1的调整分数 + """ + score = 0 + + # 检查分型的标准性 + if self.fx == Chan_FX_TYPE.TOP: + # 高点突出程度 + high_diff1 = (self.high - self.pre.high) / self.high if self.high > 0 else 0 + high_diff2 = (self.high - self.next.high) / self.high if self.high > 0 else 0 + min_diff = min(high_diff1, high_diff2) + + if min_diff > 0.03: # 非常突出 + score += 0.5 + elif min_diff > 0.01: # 比较突出 + score += 0.2 + elif min_diff < 0.003: # 不够突出 + score -= 0.5 + + else: # BOTTOM + # 低点突出程度 + low_diff1 = (self.pre.low - self.low) / self.pre.low if self.pre.low > 0 else 0 + low_diff2 = (self.next.low - self.low) / self.next.low if self.next.low > 0 else 0 + min_diff = min(low_diff1, low_diff2) + + if min_diff > 0.03: # 非常突出 + score += 0.5 + elif min_diff > 0.01: # 比较突出 + score += 0.2 + elif min_diff < 0.003: # 不够突出 + score -= 0.5 + + # 检查量价配合 + avg_volume = self._calculate_average_volume(lookback=5) + if avg_volume > 0: + volume_ratio = self.volume / avg_volume + if volume_ratio > 1.5: + score += 0.3 + elif volume_ratio < 0.7: + score -= 0.2 + + return min(1, max(-1, score)) + def calculate_fx_strength(self): """ 基于专业缠论理论的分型强度评估体系 @@ -1490,7 +1754,7 @@ class ChanKLC(): 根据专业评分标准:≥80分为有效强势分型,≤40分建议忽略 """ strength = self.calculate_fx_strength() - + return "" if strength >= 80: return "极强" elif strength >= 65: @@ -1507,4 +1771,84 @@ class ChanKLC(): 判断是否为强分型 根据专业标准调整阈值为65分 """ - return self.calculate_fx_strength() >= threshold \ No newline at end of file + return self.calculate_fx_strength() >= threshold + + def _default_top_strength_judgment(self, first_info, middle_info, last_info, first_kline, middle_kline, last_kline): + """ + 顶分型默认强弱判断 + 当不满足特定强弱条件时的保底判断 + """ + # 严格的强分型判断条件 + strong_signals = 0 + + # 判断条件1:成交量显著放大(提高标准) + avg_volume = self._calculate_average_volume(lookback=5) + volume_significantly_amplified = middle_kline.volume > avg_volume * 2.0 if avg_volume > 0 else False + if volume_significantly_amplified: + strong_signals += 1 + + # 判断条件2:中间K线有长上影线(提高标准) + has_long_upper_shadow = middle_info['upper_shadow_ratio'] > 0.6 # 从0.3提高到0.6 + if has_long_upper_shadow: + strong_signals += 1 + + # 判断条件3:后续K线收盘明显偏低(更严格) + middle_range = middle_kline.high - middle_kline.low + last_close_position = (last_kline.close - middle_kline.low) / middle_range if middle_range > 0 else 0.5 + close_significantly_low = last_close_position < 0.3 # 从0.6提高到0.3 + if close_significantly_low: + strong_signals += 1 + + # 判断条件4:最后一根K线是明显的阴线且跌幅较大 + is_significant_bearish = (last_info['is_bearish'] and + last_info['body_size'] > last_info['total_range'] * 0.5) + if is_significant_bearish: + strong_signals += 1 + + # 判断条件5:跌破前一根K线重要价位 + breaks_important_level = last_kline.low < first_kline.low + if breaks_important_level: + strong_signals += 1 + + # 需要至少4个强信号才判断为强分型,否则为弱分型 + return 1 if strong_signals >= 4 else -1 + + def _default_bottom_strength_judgment(self, first_info, middle_info, last_info, first_kline, middle_kline, last_kline): + """ + 底分型默认强弱判断 + 当不满足特定强弱条件时的保底判断 + """ + # 严格的强分型判断条件 + strong_signals = 0 + + # 判断条件1:成交量显著放大(提高标准) + avg_volume = self._calculate_average_volume(lookback=5) + volume_significantly_amplified = middle_kline.volume > avg_volume * 2.0 if avg_volume > 0 else False + if volume_significantly_amplified: + strong_signals += 1 + + # 判断条件2:中间K线有长下影线(提高标准) + has_long_lower_shadow = middle_info['lower_shadow_ratio'] > 0.6 # 从0.3提高到0.6 + if has_long_lower_shadow: + strong_signals += 1 + + # 判断条件3:后续K线收盘明显偏高(更严格) + middle_range = middle_kline.high - middle_kline.low + last_close_position = (last_kline.close - middle_kline.low) / middle_range if middle_range > 0 else 0.5 + close_significantly_high = last_close_position > 0.7 # 从0.4降低到0.7 + if close_significantly_high: + strong_signals += 1 + + # 判断条件4:最后一根K线是明显的阳线且涨幅较大 + is_significant_bullish = (last_info['is_bullish'] and + last_info['body_size'] > last_info['total_range'] * 0.5) + if is_significant_bullish: + strong_signals += 1 + + # 判断条件5:突破前一根K线重要价位 + breaks_important_level = last_kline.high > first_kline.high + if breaks_important_level: + strong_signals += 1 + + # 需要至少4个强信号才判断为强分型,否则为弱分型 + return 1 if strong_signals >= 4 else -1 \ No newline at end of file diff --git a/__pycache__/ChanBI.cpython-312.pyc b/__pycache__/ChanBI.cpython-312.pyc index b454148d40b96e45bf67ab8a55b2b8f3f3b519be..9b13e87b356c9d0e25b2e6fe93aeb6a8183abc92 100644 GIT binary patch delta 132 zcmdmOvekt9G%qg~0}x1Q@onU`VV1Sm4=qkDD%Q_ROwQJK$xklLP0cGQ)_2b=@hDB& z9L@ZNRkjhRyn*3{ut`AQbe2int;ya9uakB20`7;+eG|W8E;Kyl`;bWMP(YNFDRck; diff --git a/__pycache__/ChanBSP.cpython-312.pyc b/__pycache__/ChanBSP.cpython-312.pyc index 177daec74704ed80a648f080380c6b15ebd02be3..cc05b4cce47830f5a8acf5fa538a820e3e139dbd 100644 GIT binary patch delta 62 zcmX@lb%TrNG%qg~0}vee$Cj~?=Nyx)gMMgnYEiL%R$_9tzDs^`X>Mv>NwL0rW{F2> R(&l$e`b>1UOpL!K ItFsyc0LNJoiU0rr diff --git a/__pycache__/ChanCTime.cpython-312.pyc b/__pycache__/ChanCTime.cpython-312.pyc index b9efe3f5ed8e57ce8f5400c2c88103387ea80110..c08bfc5fa9dff8e5604de28374d71f213e750d71 100644 GIT binary patch delta 79 zcmX>ibykY!G%qg~0}vee$Cj~?=Q^XTlYVG%YEiL%R$_9tzDs^`X>Mv>NwL0rW{F2> i(&q1sHyOEaG3wu9GBCQusBmlZZDuP@##@ucc=Z4-GaG#X delta 69 zcmX>rbwrBiG%qg~0}v=Iyp+C?=Q^W^rG98}YEiL%R$_9ten3%vR%&v|CZ?N=+`kz0 YZ!sAd-C|VuwfPCN6({4b$@08<01>MfX8-^I diff --git a/__pycache__/ChanEnum.cpython-312.pyc b/__pycache__/ChanEnum.cpython-312.pyc index 0e8de31bdeddbea2654b7c9e6180e118d449cd69..60e4aad0907431f15607de2dcd005cd7af2fc802 100644 GIT binary patch delta 62 zcmbPYIM^5 HaSKKOkZupj diff --git a/__pycache__/ChanKLC.cpython-312.pyc b/__pycache__/ChanKLC.cpython-312.pyc index 7cbe3d479142c6843b63e430625011e43371536c..79c6bf665f8f94649b979dea528ff6f1bc7d6c04 100644 GIT binary patch delta 10249 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 delta 2026 zcmY*aeNaZge2p&w`6#*1a?N zopbIv=l;&QA1~7%(U*Uu(!ONbWC9KA&eg4rzY>A8@5wk3c<`w)$EiC2I}OfUryj{1 zXVw8?XRg!e%tn^6-(b#@mf#giRbH~)U8%=@r3xrHz_F3Wv<4r?p)KEHYSaZ`* z88uW+8#XKuNvv6@$*wI!@*#x+AF2pd?g9adT0l8j&xE*WR&iJv@kCc!qFEN7&EIt7 z#fKF3OP8}lPE^&a`x{6k&Kx)k$!dqa!_m`W_qwDlhkmA$-o=%?CDk2mO_K@Q1%gpz z2;o!47m)l}Nu;W0s%Owj1f#!`I2ai8 zcSf3T@Sj6ucdVc>>iu>IEZU|dW zI7Uok=9A{2W1{u%tx?^oZ!=0J)eX{jAKwAlrf9*Y>4F;RUy*|#9KENIuFcHQ44(o7 zA$)Kvha94%uWlWuz$@(jp^*H5mJa=Jg;t+~S$Riycl#UY9n9eeMG(JM3$=3s^aSx+P)HBprH1=bhbhvt59lRTRQXTd# zXNRkWw|BW+d@Gvr$WUdu%Y!%LD*MG}Xec80GFM-w;TYWvD2iW!J&Cg+u$hC+)fg1m zT#K~F`*H|RlwnX|Sd;K0@Fbz2r+J3ON(JPZ&NIk&5&6*G$qBW_r--LN<5wdY~gjx z`uby5PVJK+*5iG{eNQo?Z zd88*HUG_+q_bbfFqBRu`|C#?UBJII@@$b`b|8(t>dz-OMAwULy@Uio5|KKbnw&d(p&80YkHRy~q_c-#!niqC7o0Pl-iwNL~)aZn33ab64Sn8kdCSud{AK@D6G_v%2U myNDB>MXZU~{8axHj^a#W5YMOxvvi^pA)!5%oW4D`>y~ diff --git a/__pycache__/ChanKLU.cpython-312.pyc b/__pycache__/ChanKLU.cpython-312.pyc index 2cfd46678b134fd78ebcd6b6dd51272308627794..9c66c5ff48fb80e786e808eeca80c5d7b72bd980 100644 GIT binary patch delta 61 zcmew)^IL}dG%qg~0}$|Js&3?NV3Kvv4=qkDD%Q_ROwQJK$xklLP0cGQ)_2b=@hDB& PJfCSfH{-3z?tIz+Ie8PM delta 52 zcmew@^GSyLG%qg~0}x0(klo1Lz$9X>A6lGRRIHzsn4GO2P?VpQnq0DZ1=DhF#$S^I G__P71R}l38 diff --git a/__pycache__/ChanLun.cpython-312.pyc b/__pycache__/ChanLun.cpython-312.pyc index 4eb781224410d66dd7610ceb942d387dfa1c5660..550c702b4f34956cdb352e4074b1dd2694c13091 100644 GIT binary patch delta 2103 zcmYjSdu&tJ9X>xF+lk+=du=C<(>AyFR#sgy@+il-t?V>|aIsP!L5 z_IJ+te&6@~&N&vZYbUNY{Q0tDK?K?uxZSL9{YW{Us-wQpz z+PNdNqIc)YzE0xTtn>bitrpOX$<`kgDl?8Eq4M{2`+^yVi#826k=Hd79$fUKA-;{=+@7oCZ5#m*J5OLim&RUSa)l#2v5E> zU6WxF;XUGAvsa}P9`cYP+b)@ieCG6sqqY@h)qsj@`@~6XCGX<2wNgx!^aDn=D)Mw0 z?@n1Og}#j1oL2J*H9ydOS?$RxlY?bn2Ez(x#$pqynLwd4gH377B``PeWSS2o_`t~8 zBp<$v=d&%W;9!|s9QV~}p^7n#_%7h8!tT!7P-3b8Sq#{@Iw%jWlE$dHfg3USKdBX{fmhLN#c9I3yZ z4_oH872_F}T4M2eGm9r{MFotVXX?q(rgkM?^^z$bA|%ne6weqPq9^)oo`Rb<<#Di| zIJd9FX+x>FWxGqu*vrKIyXrXio;Mdn%Tl#&QYLAA5zW0;%uUE0| z1<0AN|AN!pLUQu9pX|N)Hb#7e1a5`rup%Pdno_Vew_6#uoUOa5M*I^%Uc2+tIiQGS z?@Z}sF#Agtvet_K{ANo&{8 zILwDr9G{1G9MX>bA`y{ zkcy-52gqmNasg!K={NmQOvgIFM$=EjJ$j=J#!L)nlXg$+(X_3M#x}!I8t(+X)Uh54 zfk$>^p9>?i>jxha^KlxO2UjjAduT}8$|dIE18^d{{|DvqqS~Z8n6iZE z%Uz1}@QwS+SvowFbvVQUMR&WuAJ`cg`cp~@0Z@`1-=ljN>jgua~c?> zzk3A+{8y?&NptwP|48|PT`~2+y(501DsB!xZ0l2`IAtiIOJ0S4=g5Cc77KHq&5A^vRG)m&H`DHwwFtn55iUUxH|lF^bmBggC3x@ zL+k=PIsl^_a@O7rAgwFI&zpVkQ+!aKc3Vd3G8$7>gPfsk5a}KCq8G~O1uwMFHwM92 zoao$|T=YB}>b57>s6#mq^rB5kOYZXN@d3Qt>IRCfaW zR%CPEW4Flh1y>-vG;J@W%TB-oX3;}mJ^`zp$XJ!z4s#rFcU6+BP8({ZYbT&|mc)4K k$0SaVutz3&;uJJ0B>PXnYWBwvkm9G{4u-4r{8{MxKeuI|ApigX delta 2536 zcmZuzYitzP6~1Tg?AtT@n(^A+wZUtz@pE?p1Ljd2UV`GZ!6bGJ#v$gR5K<`tf}k`_ z7ph25UYm^Rbsiu$2t*WGNG53I1c!%6K?zaT9${}(DjwlSlK`3QI#HWeY0u2!LZ$AH zIp4kKG3Pty+&g>zhE=^~b$ucTPJ%!EcIi7Vt3{d?YumJT{o2*f zD^bg%;Z`(CkgI}scYC5b;}0dOcQ$U1X8Zxx{Bm=aa5SVGveZzN>c^Hk&b`I7&lLEx zgr{>s`O&tHH-P%I{R0qJ=Cy)sXeTQT&ZQKky2IH{-Pti+4t3i=xgmUko(Mh*1l5~j zDJQ;kKemldQS9EW)Q|;QP(9>bC~~iHN_Rw7{xz=Ou6e3+B*@2kdEK8yP4);j`1H zxnaz=7Rq(vq~eg!V$i7kT31U%qon`Dz7_&Xm8f0s_qcabpmpa zC|}2l?V5W+j`*=5wzv(b0lX7;Q~0ZLu(8Chxhk@xh?XkvH@-(vsvD-GNFwEGmuWJ1Pg#oX;dC(n{rn)2-N{Se97$u;LzQ zqlSEHpn{@O-8(R!N*tKk78c=jm`RE>qFg`Qb>Howb9uMka}jilsAtc;$bm;`z7WO! zM6#rS)+^6l_>`hlANr`p(CxWs=&B4|R2jHv=%VW0OI;4G!f21|72H@C!6=T=nnLPR zgrV;!O4XuOQU95H2gtO-6DDHsgrR`4WO%<5v0g@;zC=uE-5ON+k;7i@fJK?DPgSn{ zZMs8q*JC9C9fDu}!LCU&azwNQlrvwZsUctaDxTl;Sc-8oq%6Agu|+R8Rwuu1L)C&D z@tF1zrQ!BR)WF~0o;;=)^SSIq5B+hRRa&f;-F?c=9R*Awq8|T#GB`3qv2mX~46MTr zG0)Wgsb`w|o3HRKy2aR4$Nzm@0oTME4(tREbFfymIZ{c(EXTvovCoUKVb(C4Z-M>P z0Q+qaVsQ(2@9S(<*lX%~t*{)o=jUC%v%>GkTq^EwpRz%Zgpu@Se2cyqh-hZG%*=2B z&(UR&>a)W&9`3S)0FvDtejoKPCP1@Y^G5NSvy`yU1vo+tuw4WU|G@TPukJvF?j)jT z$22{HzNt<(%(PW(mLAw&O84 zE+EiLh=9jeq7u8i0={Mcd>p*2sU2Pwa0~A!5ywuVzSQUK@E7nQ8m%Y3VDD7T8_tnB zYDt~zfQt}BG}-~gBbymNq7~I^?uIO}(`SJlTn>?tfku7z4AP-`t*AkBW3lXXE3gr? z;7#=JK5n@@NUlRE z)m-E9=}?1K6xG~#S=i|YU|p+BdK(_37uAYlnmcY-Yy-y70_h<-v&y7bXwds9$8N5I z0i=iM&DF3ckbd&%;Th}Goh#1Hxdi7I^iR38WpHNuP^x7Od_gfxY#o&20jo5=q$TXp zbubA(r6sAI>p(7nA5w>Q!21>$V#{_yvL;g-8y4ezm3y}K@_S!Qi}6GaKE@_tnNp^? z#%GC-7BX=coDmS{wM3Bc5}*NN5{lTJT`(ZvN)Hp`(ygX$h6O82rGE#1f-o+#?Le%; zP511?^jlcDg_;j5*UVeDZ%J(0IrkR3whQFc$vyBPP~2r3_Q8`5O|H)pKaVH=S`vcn zn|<(Z&{%$3PppBAT$TTvYBElS#LqLWirA<7!R9cQdXzZ*EO7+F>^DcCl|7P#f}-@Q zXNG6}BHi`G+3ri_=hybPrCU1&f6_6;ewl>Tc(O5+gAW+*Yo`cOO)tYcUM$yFZ$dW* zv)IE&;1j%9%Cq?88^=nH!kS_PqY|E(q_<~Yuc%2AG#CE2m`a_gSB^q}vu8YkETJ}$ z9X|#U89@$Dv;VqOoYD=|4+-z7h}G&eP`q*&iQv&5q` RX|p=>7H-B{lkf1^0{}_k6jlHL delta 53 zcmZ1?H(QS9G%qg~0}x33c#^)6hn-o(TtBopwWwG>D=|4+KcFZ-D>b=fvjOuKZpL4e IpYquQ0H(eXSO5S3 diff --git a/__pycache__/ChanSEG.cpython-312.pyc b/__pycache__/ChanSEG.cpython-312.pyc index dac2f10047089de9ff297a3c17e2a5e859e70458..309ff0782713bb4b28e1d3dcbfc97828a88adebc 100644 GIT binary patch delta 61 zcmbO(y+E4#G%qg~0}$wB@@(W@&MfPoA6lGRRIHzsn4GQelAm0fo0?ZrtnZ##;!&Ek P`55yAPR3i4!+9M57oZbQ delta 52 zcmZ1=JzbjnG%qg~0}xEKW8cWVoLR(NKeRZts8~NMF*#d5peR2pHMwN-dFBb6jK3x) H@HzkhfAbJm diff --git a/__pycache__/ChanZS.cpython-312.pyc b/__pycache__/ChanZS.cpython-312.pyc index c3d36260054d9b1db64876f3ccd38ebbf403a195..db18ccb2faa8a093d385403355f16a701fe64021 100644 GIT binary patch delta 62 zcmca2dsmj{G%qg~0}vee$Cj~?=OweOy?$tMYEiL%R$_9tzDs^`X>Mv>NwL0rW{F2> R(q>MU$y|)LCeP(F2LOj^6(Ils delta 53 zcmcaBdqtM#G%qg~0}$xU{+_;(=Owd