From 164db4ab517d4cf5734a2113a1fdaa4abb30e831 Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Thu, 4 Sep 2025 19:52:01 +0800 Subject: [PATCH] Add Continue Div and Cross Div --- ChanEnum.py | 4 +- ChanKLU.py | 129 ++++++++++++++++++++++-------------- ChanLun.py | 2 +- ChanMACD.py | 139 +++++++++++++++++++++++++++++++++++---- ChanMACDHistSet.py | 87 +++++++++++------------- ChanMACDSeg.py | 9 ++- ChanMACDUnitTF.py | 83 ++++++++++++++++------- web/templates/index.html | 8 +-- 8 files changed, 318 insertions(+), 143 deletions(-) diff --git a/ChanEnum.py b/ChanEnum.py index 927f8de..28865a8 100644 --- a/ChanEnum.py +++ b/ChanEnum.py @@ -96,7 +96,9 @@ class Chan_MACD_STATE(Enum): RETURN_ZERO = auto() # 归零轴:能量柱呈现一根比一根短的排列方式 RZ_UP = auto() # 归零轴后的零轴上涨 RZ_DOWN = auto() # 归零轴后的零轴下跌 - + UP = auto() # 穿零轴后向上 + DOWN = auto() # 穿零轴后向下 + PEAK = auto() # 峰值:MACD白线处于高位 # 基础状态 UNKNOWN = auto() # 未知 START = auto() # 开始 diff --git a/ChanKLU.py b/ChanKLU.py index 76bf6b3..f3b7ecf 100644 --- a/ChanKLU.py +++ b/ChanKLU.py @@ -52,6 +52,8 @@ class ChanKLU: 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 self.strength = 0 if self.candle_dir == Chan_K_DIR.CROSS else self.cal_klu_strength() + self.continue_div = False + self.separate_div = False self.ema52 = 0 self.ema24 = 0 self.macd_slop = 0 @@ -73,6 +75,8 @@ class ChanKLU: self.div_type = "none" # {bearish, bullish, hidden_bearish, hidden_bullish, none} self.div_score = 0.0 # 背离强度(0-100) #print(self.open, self.close, self.high, self.low, self.candle_dir, self.strength) + def set_macd_state(self, state): + self.macd_state = state def cal_klu_strength(self): strength = 0 if range != 0: @@ -608,7 +612,9 @@ class ChanKLU: self.ma5 = float(item['ma5']) if 'ma5' in item and item['ma5'] else 0 self.ma10 = float(item['ma10']) if 'ma10' in item and item['ma10'] else 0 self.ma30 = float(item['ma30']) if 'ma30' in item and item['ma30'] else 0 - + self.ema52 = float(item['ema52']) if 'ema52' in item and item['ema52'] else 0 + self.ema24 = float(item['ema24']) if 'ema24' in item and item['ema24'] else 0 + # 安全检查 ma250、ma50 和 ma200 self.ma250 = float(item['ma250']) if 'ma250' in item and item['ma250'] else 0 self.ma50 = float(item['ma50']) if 'ma50' in item and item['ma50'] else 0 @@ -645,70 +651,93 @@ class ChanKLU: self.macd_state = Chan_MACD_STATE.UNKNOWN return self.macd_state - # 调试:当前值 - #print(f"DEBUG: MACD值检查 - 时间: {self.time}, MACD: {self.macd:.4f}, Signal: {self.signal:.4f}, 前一根Signal: {self.pre.signal:.4f}") - # 3) CROSS0 仅以 Signal 穿越零轴判定 if self.pre.signal >= 0 and self.signal < 0: self.macd_state = Chan_MACD_STATE.CROSS0_DOWN - #print(f"DEBUG: CROSS0触发(向下) - 时间: {self.time}, Signal: {self.pre.signal:.4f}->{self.signal:.4f}") return self.macd_state if self.pre.signal <= 0 and self.signal > 0: self.macd_state = Chan_MACD_STATE.CROSS0_UP - #print(f"DEBUG: CROSS0触发(向上) - 时间: {self.time}, Signal: {self.pre.signal:.4f}->{self.signal:.4f}") return self.macd_state - - # 4) 高位状态的位置状态, 高位,高位空,归零轴 - position_state = Chan_MACD_STATE.UNKNOWN - if abs(self.macd) > 50: - position_state = self._cal_position_state() - if position_state != Chan_MACD_STATE.UNKNOWN: - self.macd_state = position_state - #print(f"DEBUG: 位置状态设置 - 时间: {self.time}, 状态: {self.macd_state}, MACD: {self.macd:.4f}, Signal: {self.signal:.4f}") - return self.macd_state - - # 5) 趋近零轴:任一线接近零轴即可,无限接近零轴,EMA52没有加 + # 6) 趋近零轴:任一线接近零轴即可,无限接近零轴,EMA52没有加 NEAR0_EPS = 15 if abs(self.macd) <= NEAR0_EPS or abs(self.signal) <= NEAR0_EPS: self.macd_state = Chan_MACD_STATE.NEAR0 - #print(f"DEBUG: 趋近零轴触发 - 时间: {self.time}, MACD: {self.macd:.4f}, Signal: {self.signal:.4f}") return self.macd_state - # 6) 离开0轴开始上涨或者下跌阶段,高位之前的 - if self.macd_state == Chan_MACD_STATE.UNKNOWN: - if self.macd > 0 and self.pre: - if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_UP) and self.signal > self.pre.signal: - self.macd_state = Chan_MACD_STATE.RZ_UP + if self.macd > 0 and abs(self.low - self.ema52) <= NEAR0_EPS: + self.macd_state = Chan_MACD_STATE.NEAR0 + return self.macd_state + if self.macd < 0 and abs(self.high - self.ema52) <= NEAR0_EPS: + self.macd_state = Chan_MACD_STATE.NEAR0 + return self.macd_state + # 4) 穿零轴后离开零轴 + if self.pre.macd_state == Chan_MACD_STATE.CROSS0_UP and self.macd > self.pre.macd and self.signal < self.macdhist: + self.macd_state = Chan_MACD_STATE.UP + return self.macd_state + if self.pre.macd_state == Chan_MACD_STATE.CROSS0_DOWN and self.macd < self.pre.macd and self.signal > self.macdhist: + self.macd_state = Chan_MACD_STATE.DOWN + return self.macd_state + if self.pre.macd_state == Chan_MACD_STATE.UP and self.macd > self.pre.macd and self.signal > self.pre.signal: + self.macd_state = Chan_MACD_STATE.UP + return self.macd_state + if self.pre.macd_state == Chan_MACD_STATE.DOWN and self.macd < self.pre.macd and self.signal < self.pre.signal: + self.macd_state = Chan_MACD_STATE.DOWN + return self.macd_state + # 5) 高位状态的位置状态, 高位,高位空,归零轴 + if (self.pre.macd_state == Chan_MACD_STATE.UP or self.pre.macd_state == Chan_MACD_STATE.HIGH or self.pre.macd_state == Chan_MACD_STATE.RZ_UP) and self.macd > 0: + if abs(self.pre.macd - self.macd) < 10: + self.macd_state = Chan_MACD_STATE.HIGH + return self.macd_state + else: + if self.macd > self.pre.macd and self.signal > self.pre.signal: + self.macd_state = Chan_MACD_STATE.UP return self.macd_state - elif self.macd < 0 and self.pre: - if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_DOWN) and self.signal < self.pre.signal: - self.macd_state = Chan_MACD_STATE.RZ_DOWN + elif self.macd < self.pre.macd and self.signal < self.pre.signal: + self.macd_state = Chan_MACD_STATE.RETURN_ZERO return self.macd_state - # 7) 其余情况 - self.macd_state = Chan_MACD_STATE.UNKNOWN + if (self.pre.macd_state == Chan_MACD_STATE.DOWN or self.pre.macd_state == Chan_MACD_STATE.HIGH or self.pre.macd_state == Chan_MACD_STATE.RZ_DOWN) and self.macd < 0: + if abs(self.pre.macd - self.macd) < 10: + self.macd_state = Chan_MACD_STATE.HIGH + return self.macd_state + else: + if self.macd > self.pre.macd and self.signal > self.pre.signal: + self.macd_state = Chan_MACD_STATE.RETURN_ZERO + return self.macd_state + elif self.macd < self.pre.macd and self.signal < self.pre.signal: + self.macd_state = Chan_MACD_STATE.DOWN + return self.macd_state + + # 7) 离开0轴开始上涨或者下跌阶段,高位之前的 + if self.macd > 0 and self.pre: + if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_UP) and (self.signal > self.pre.signal or self.close > self.ema52): + self.macd_state = Chan_MACD_STATE.RZ_UP + return self.macd_state + elif self.macd < 0 and self.pre: + if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_DOWN) and (self.signal < self.pre.signal or self.close < self.ema52): + self.macd_state = Chan_MACD_STATE.RZ_DOWN + return self.macd_state + # 8) 归零轴走势 + if self.pre.macd_state == Chan_MACD_STATE.RETURN_ZERO: + if self.macd > 0: + if self.pre.macd > self.macd: + self.macd_state = Chan_MACD_STATE.RETURN_ZERO + return self.macd_state + else: + if self.pre.macd < self.macd: + self.macd_state = Chan_MACD_STATE.RETURN_ZERO + return self.macd_state + # 9) 其余情况 + if self.pre.macd_state == Chan_MACD_STATE.UNKNOWN: + if self.macd > 0 and self.close > self.ema52 and self.pre.pre and (self.pre.pre.macd_state == Chan_MACD_STATE.UP or self.pre.pre.macd_state == Chan_MACD_STATE.RZ_UP): + self.macd_state = self.pre.pre.macd_state + return self.macd_state + elif self.macd < 0 and self.close < self.ema52 and self.pre.pre and (self.pre.pre.macd_state == Chan_MACD_STATE.DOWN or self.pre.pre.macd_state == Chan_MACD_STATE.RZ_DOWN): + self.macd_state = self.pre.pre.macd_state + return self.macd_state + else: + self.macd_state = Chan_MACD_STATE.UNKNOWN + return self.macd_state return self.macd_state - def _cal_position_state(self): - """计算MACD位置状态:高位、高位空、归零轴""" - if not hasattr(self, 'pre') or self.pre is None: - return Chan_MACD_STATE.UNKNOWN - pre_hist = abs(self.pre.macdhist) - cur_hist = abs(self.macdhist) - if self.next: - next_hist = abs(self.next.macdhist) - if cur_hist > pre_hist and cur_hist > next_hist: - return Chan_MACD_STATE.HIGH - if self.pre.macd_state == Chan_MACD_STATE.HIGH or self.pre.macd_state == Chan_MACD_STATE.HIGH_EMPTY: - if self.macd > 0: - if self.macd > self.signal: - return Chan_MACD_STATE.HIGH_EMPTY - else: - return Chan_MACD_STATE.RETURN_ZERO - elif self.macd < 0: - if self.macd < self.signal: - return Chan_MACD_STATE.HIGH_EMPTY - else: - return Chan_MACD_STATE.RETURN_ZERO - return Chan_MACD_STATE.UNKNOWN def get_feature_data(self): features = dict() features['klu_close'] = self.close diff --git a/ChanLun.py b/ChanLun.py index ce3191e..079a195 100644 --- a/ChanLun.py +++ b/ChanLun.py @@ -1161,7 +1161,7 @@ class ChanLun(): klc_list = [] last_klu = None macd = ChanMACD(klu_list) - klu_list = macd.cal_macd() + klu_list = macd.cal_macd_state() for klu in klu_list: if len(klc_list) > 0: last_klc = klc_list[-1] diff --git a/ChanMACD.py b/ChanMACD.py index a539695..e6b7d8d 100644 --- a/ChanMACD.py +++ b/ChanMACD.py @@ -17,7 +17,125 @@ class ChanMACD(): self.cross0_up_list = [] # 向上穿越零轴列表 self.cross0_down_list = [] # 向下穿越零轴列表 # 计算段 / UnitTF / HistSet 及状态标记 - self.cal_macd() + self.cal_macd_state() + def cal_macd_state(self): + last_seg = None + last_unittf = None + last_histset = None + last_klu = None + for klu in self.klu_list: + # initialise first histset + if klu.macd == 0 and klu.signal == 0 and klu.macdhist == 0: + continue + if last_histset is None: + if klu.macdhist > 0: + last_histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, None, Chan_MACDHISTSET_DIR.ABOVE) + self.histset_list.append(last_histset) + else: + last_histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, None, Chan_MACDHISTSET_DIR.UNDER) + self.histset_list.append(last_histset) + else: + # initialise first seg and unittf + if last_seg is None: + # create histset afterwards + if last_histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE: + if klu.macdhist > 0: + last_histset.add_klu(klu) + else: + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.UNDER) + self.histset_list.append(histset) + last_histset.set_next(histset) + histset.set_pre(last_histset) + last_histset.set_end_klu(last_klu) + last_histset = histset + else: + if klu.macdhist < 0: + last_histset.add_klu(klu) + else: + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.ABOVE) + self.histset_list.append(histset) + last_histset.set_next(histset) + histset.set_pre(last_histset) + last_histset.set_end_klu(last_klu) + last_histset = histset + if last_klu.signal >= 0 and klu.signal < 0: + last_unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, None, Chan_MACDUNITTF_DIR.UNDER, Chan_MACDUNITTF_TYPE.CROSS0, last_histset) + self.unittf_list.append(last_unittf) + last_seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, None, Chan_MACDSEG_DIR.UNDER, last_unittf) + self.seg_list.append(last_seg) + elif last_klu.signal <= 0 and klu.signal > 0: + last_unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, None, Chan_MACDUNITTF_DIR.ABOVE, Chan_MACDUNITTF_TYPE.CROSS0, last_histset) + self.unittf_list.append(last_unittf) + last_seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, None, Chan_MACDSEG_DIR.ABOVE, last_unittf) + self.seg_list.append(last_seg) + # after the first seg and unittf + else: + # create histset afterwards + if last_histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE: + if klu.macdhist > 0: + last_histset.add_klu(klu) + else: + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.UNDER) + self.histset_list.append(histset) + last_histset.set_next(histset) + histset.set_pre(last_histset) + last_histset.set_end_klu(last_klu) + last_histset = histset + if last_unittf: + last_unittf.add_histset(last_histset) + else: + if klu.macdhist < 0: + last_histset.add_klu(klu) + else: + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.ABOVE) + self.histset_list.append(histset) + last_histset.set_next(histset) + histset.set_pre(last_histset) + last_histset.set_end_klu(last_klu) + last_histset = histset + if last_unittf: + last_unittf.add_histset(last_histset) + if last_klu.signal >= 0 and klu.signal < 0: + last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.CROSS0) + unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, last_unittf, Chan_MACDUNITTF_DIR.UNDER, Chan_MACDUNITTF_TYPE.CROSS0, last_histset) + self.unittf_list.append(unittf) + last_unittf.set_next(unittf) + last_seg.set_end_klu(last_klu) + seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, last_seg, Chan_MACDSEG_DIR.UNDER, unittf) + self.seg_list.append(seg) + last_seg.set_next(seg) + last_seg = seg + last_unittf = unittf + elif last_klu.signal <= 0 and klu.signal > 0: + last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.CROSS0) + unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, last_unittf, Chan_MACDUNITTF_DIR.ABOVE, Chan_MACDUNITTF_TYPE.CROSS0, last_histset) + self.unittf_list.append(unittf) + last_unittf.set_next(unittf) + last_seg.set_end_klu(last_klu) + seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, last_seg, Chan_MACDSEG_DIR.ABOVE, unittf) + self.seg_list.append(seg) + last_seg.set_next(seg) + last_seg = seg + last_unittf = unittf + elif last_unittf.is_end and last_klu.macd < klu.macd and klu.macd > klu.signal: + unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, last_unittf, Chan_MACDUNITTF_DIR.ABOVE, Chan_MACDUNITTF_TYPE.NEAR0, last_histset) + self.unittf_list.append(unittf) + last_unittf.set_next(unittf) + last_seg.add_unittf(unittf) + last_unittf = unittf + last_seg.add_klu(klu) + else: + if not last_unittf.is_end: + last_unittf.add_klu(klu) + last_seg.add_klu(klu) + last_klu = klu + if last_histset: + last_histset.set_end_klu(last_klu) + if last_unittf: + last_unittf.set_end_klu(last_klu, None) + if last_seg: + last_seg.set_end_klu(last_klu) + return self.klu_list def cal_macd(self): last_seg = None last_unittf = None @@ -26,6 +144,7 @@ class ChanMACD(): last_klu = None for klu in self.klu_list: klu.cal_macd_state() + print(klu.time, klu.macd_state) # 1) 只有当 MACD 已可用(非 UNKNOWN)时,才开始初始化段/单元 if last_seg is None: if klu.macd_state != Chan_MACD_STATE.UNKNOWN: @@ -39,10 +158,9 @@ class ChanMACD(): # 初始化首段 seg_dir = Chan_MACDSEG_DIR.ABOVE if klu.signal >= 0 else Chan_MACDSEG_DIR.UNDER - seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, None, seg_dir) + seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, None, seg_dir, last_unittf) self.seg_list.append(seg) last_seg = seg - last_seg.add_histset(histset) # 初始化首个UnitTF unittf_dir = Chan_MACDUNITTF_DIR.ABOVE if klu.signal >= 0 else Chan_MACDUNITTF_DIR.UNDER @@ -61,13 +179,11 @@ class ChanMACD(): # 结束旧 histset(以前一根结束更合理) if last_histset and last_klu: last_histset.set_end_klu(last_klu) - histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.ABOVE) + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.ABOVE if klu.macdhist >= 0 else Chan_MACDHISTSET_DIR.UNDER) self.histset_list.append(histset) if last_histset: last_histset.set_next(histset) last_histset = histset - if last_seg: - last_seg.add_histset(histset) if last_unittf: last_unittf.add_histset(histset) else: @@ -77,13 +193,11 @@ class ChanMACD(): # 结束旧 histset(以前一根结束更合理) if last_histset and last_klu: last_histset.set_end_klu(last_klu) - histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.UNDER) + histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, last_histset, Chan_MACDHISTSET_DIR.ABOVE if klu.macdhist >= 0 else Chan_MACDHISTSET_DIR.UNDER) self.histset_list.append(histset) if last_histset: last_histset.set_next(histset) last_histset = histset - if last_seg: - last_seg.add_histset(histset) if last_unittf: last_unittf.add_histset(histset) # 2) 过零切段(使用KLU中的穿越状态) @@ -92,7 +206,7 @@ class ChanMACD(): # 结束旧 unittf last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.CROSS0) # 新的单位时间周期 - new_dir = Chan_MACDUNITTF_DIR.UNDER if last_unittf.unittf_dir == Chan_MACDUNITTF_DIR.ABOVE else Chan_MACDUNITTF_DIR.ABOVE + new_dir = Chan_MACDUNITTF_DIR.ABOVE if klu.signal >= 0 else Chan_MACDUNITTF_DIR.UNDER unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, last_unittf, new_dir, Chan_MACDUNITTF_TYPE.CROSS0, histset) self.unittf_list.append(unittf) last_unittf.set_next(unittf) @@ -101,11 +215,10 @@ class ChanMACD(): last_seg.set_end_klu(last_klu) # 新段方向取反 new_dir = Chan_MACDSEG_DIR.UNDER if last_seg.seg_dir == Chan_MACDSEG_DIR.ABOVE else Chan_MACDSEG_DIR.ABOVE - seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, last_seg, new_dir) + seg = ChanMACDSeg(len(self.seg_list), klu.time, klu, last_seg, new_dir, last_unittf) self.seg_list.append(seg) last_seg.set_next(seg) last_seg = seg - last_seg.add_histset(last_histset) last_seg.add_unittf(unittf) else: # 4) UnitTF 状态机:用黄线Signal的归零轴 @@ -121,7 +234,7 @@ class ChanMACD(): last_seg.add_unittf(unittf) elif klu.macd_state == Chan_MACD_STATE.RZ_DOWN: last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.NEAR0) - new_dir = Chan_MACDUNITTF_DIR.UNDER if klu.signal >= 0 else Chan_MACDUNITTF_DIR.ABOVE + new_dir = Chan_MACDUNITTF_DIR.ABOVE if klu.signal >= 0 else Chan_MACDUNITTF_DIR.UNDER unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, last_unittf, new_dir, Chan_MACDUNITTF_TYPE.NEAR0, histset) self.unittf_list.append(unittf) last_unittf.set_next(unittf) diff --git a/ChanMACDHistSet.py b/ChanMACDHistSet.py index 47a0c39..beb650a 100644 --- a/ChanMACDHistSet.py +++ b/ChanMACDHistSet.py @@ -11,18 +11,17 @@ class ChanMACDHistSet(): self.next = None self.pre = pre_histset self.peak_klu = None - self.second_peak_klu = None self.area = start_klu.macdhist self.unittf_div = Chan_MACDUNITTF_DIV.UNDIV self.middle_klu = None - self.middle_peak = None - self.second_middle_peak = None self.div_count = 0 self.last_klu = start_klu - self.low_klu = None self.start_klu = start_klu + self.peak_div_list = [] def set_next(self, next_histset): self.next = next_histset + def set_pre(self, pre_histset): + self.pre = pre_histset def set_middle_klu(self, middle_klu): self.middle_klu = middle_klu def set_unittf_div(self, unittf_div): @@ -35,44 +34,42 @@ class ChanMACDHistSet(): self.low_klu = None self.peak_klu = None self.div_count = 0 + self.peak_div_list = [] else: if self.last_klu: - self.cal_peak_klu(klu) + self.cal_macdhist_klu(klu) self.last_klu = klu - def cal_peak_klu(self, klu): + def cal_macdhist_klu(self, klu): if self.middle_klu: - if self.low_klu is None and abs(klu.macdhist) > abs(self.last_klu.macdhist): - self.low_klu = self.last_klu - return - else: - if self.peak_klu is None and self.low_klu and abs(klu.macdhist) < abs(self.last_klu.macdhist): - self.peak_klu = self.last_klu - self.low_klu = None - elif self.low_klu and self.peak_klu: - if abs(self.last_klu.macdhist) > abs(self.peak_klu.macdhist): - self.peak_klu = self.last_klu - self.low_klu = None - elif abs(self.last_klu.macdhist) > abs(klu.macdhist): - self.second_peak_klu = self.last_klu - self.div_count += 1 - self.low_klu = None + if klu.index >= self.middle_klu.index + 2: + if klu.pre.pre: + if abs(klu.pre.macdhist) > abs(klu.pre.pre.macdhist) and abs(klu.pre.macdhist) > abs(klu.macdhist): + if self.peak_klu: + if abs(klu.pre.macdhist) > abs(self.peak_klu.macdhist): + self.peak_klu = klu.pre + self.div_count = 0 + self.peak_div_list = [] + else: + self.peak_div_list.append(klu.pre) + self.div_count += 1 + klu.pre.continue_div = True + else: + self.peak_klu = klu.pre else: - if self.peak_klu is None and abs(klu.macdhist) < abs(self.last_klu.macdhist): - self.peak_klu = self.last_klu - return - else: - if self.low_klu is None and self.peak_klu and abs(klu.macdhist) > abs(self.last_klu.macdhist): - self.low_klu = self.last_klu - return - else: - if self.peak_klu and self.low_klu: - if abs(self.last_klu.macdhist) > abs(self.peak_klu.macdhist): - self.peak_klu = self.last_klu - self.low_klu = None - elif abs(self.last_klu.macdhist) > abs(klu.macdhist): - self.second_peak_klu = self.last_klu - self.div_count += 1 - self.low_klu = None + if len(self.klu_list) >= 3: + if klu.pre.pre: + if abs(klu.pre.macdhist) > abs(klu.pre.pre.macdhist) and abs(klu.pre.macdhist) > abs(klu.macdhist): + if self.peak_klu: + if abs(klu.pre.macdhist) > abs(self.peak_klu.macdhist): + self.peak_klu = klu.pre + self.div_count = 0 + self.peak_div_list = [] + else: + self.peak_div_list.append(klu.pre) + self.div_count += 1 + klu.pre.continue_div = True + else: + self.peak_klu = klu.pre def set_end_klu(self, end_klu): self.end_klu = end_klu self.end_time = end_klu.time @@ -83,13 +80,9 @@ class ChanMACDHistSet(): self.peak_klu = self.start_klu else: self.peak_klu = end_klu - #if self.div_count > 0: - #print("Continue:", self.index, self.start_time, self.second_peak_klu.time, self.div_count) - """ - if self.div_klu: - print(self.start_time, self.peak_klu.time, self.div_klu.time, self.klu_list[-1].time, len(self.klu_list), self.histset_dir) - elif self.peak_klu: - print(self.start_time, "Peak:", self.peak_klu.time, self.klu_list[-1].time, len(self.klu_list), self.histset_dir) - else: - print(self.start_time, "None", self.klu_list[-1].time, len(self.klu_list), self.histset_dir) - """ \ No newline at end of file + peak_str = "" + for peak_div in self.peak_div_list: + peak_str += f"{peak_div.time}, " + if self.peak_klu and len(self.peak_div_list) > 0: + print("Continue Div: ",self.start_time, "Peak:", self.peak_klu.time, "Div: ", peak_str, self.histset_dir, self.div_count) + \ No newline at end of file diff --git a/ChanMACDSeg.py b/ChanMACDSeg.py index 62c18a6..b013b3f 100644 --- a/ChanMACDSeg.py +++ b/ChanMACDSeg.py @@ -2,7 +2,7 @@ from ChanEnum import Chan_MACDSEG_DIR class ChanMACDSeg(): - def __init__(self, index, start_time, start_klu, pre_seg, seg_dir): + def __init__(self, index, start_time, start_klu, pre_seg, seg_dir, start_unittf): self.index = index self.start_time = start_time self.end_time = None @@ -11,15 +11,17 @@ class ChanMACDSeg(): self.klu_list = [] self.klu_list.append(start_klu) self.unittf_list = [] - self.hist_set = [] self.seg_dir = seg_dir self.pre = pre_seg self.next = None self.high_klu = start_klu self.low_klu = start_klu self.ref_klu = None + self.unittf_list.append(start_unittf) def set_next(self, next_seg): self.next = next_seg + def set_pre(self, pre_seg): + self.pre = pre_seg def add_klu(self, klu): if klu: self.klu_list.append(klu) @@ -41,9 +43,6 @@ class ChanMACDSeg(): def add_unittf(self, unittf): self.unittf_list.append(unittf) unittf.set_next(self) - def add_histset(self, histset): - self.hist_set.append(histset) - histset.set_next(self) def set_end_klu(self, end_klu): self.add_klu(end_klu) self.end_klu = end_klu diff --git a/ChanMACDUnitTF.py b/ChanMACDUnitTF.py index 8e77c67..37b0a75 100644 --- a/ChanMACDUnitTF.py +++ b/ChanMACDUnitTF.py @@ -1,8 +1,8 @@ -from ChanEnum import Chan_MACD_STATE, Chan_MACDUNITTF_DIR, Chan_MACDHISTSET_DIR, Chan_MACDUNITTF_DIV +from ChanEnum import Chan_MACD_STATE, Chan_MACDUNITTF_DIR, Chan_MACDHISTSET_DIR, Chan_MACDUNITTF_DIV, Chan_MACDUNITTF_TYPE class ChanMACDUnitTF(): - def __init__(self, index, start_time, start_klu, pre_unittf, dir, start_type, start_histset): + def __init__(self, index, start_time, start_klu, pre_unittf, unittf_dir, start_type, start_histset): self.index = index self.start_time = start_time self.end_time = None @@ -16,26 +16,26 @@ class ChanMACDUnitTF(): start_histset.set_middle_klu(start_klu) self.next = None self.pre = pre_unittf - self.unittf_dir = dir + self.unittf_dir = unittf_dir self.start_type = start_type self.end_type = None self.peak_klu = None self.div_type = Chan_MACDUNITTF_DIV.UNDIV self.div_peak_list = [] - self.div_low_list = [] - self.rev_low_klu = None + self.is_end = False def set_next(self, next_unittf): self.next = next_unittf + def set_pre(self, pre_unittf): + self.pre = pre_unittf def add_histset(self, histset): self.histset_list.append(histset) def add_klu(self, klu): self.klu_list.append(klu) self.cal_peak_div() + self.cal_macd_state() def cal_peak_div(self): self.div_count = 0 self.div_peak_list = [] - self.div_low_list = [] - self.rev_low_klu = None self.peak_klu = None if len(self.histset_list) == 0: return @@ -59,26 +59,66 @@ class ChanMACDUnitTF(): else: if histset.peak_klu: self.peak_klu = histset.peak_klu - else: - if self.rev_low_klu: - if histset.low_klu: - if abs(histset.low_klu.macdhist) < abs(self.rev_low_klu.macdhist): - self.rev_low_klu = histset.low_klu - self.div_low_list.append(histset.low_klu) - else: - if histset.low_klu: - self.rev_low_klu = histset.low_klu - self.div_low_list.append(histset.low_klu) + def cal_macd_state(self): + if len(self.klu_list) > 0: + last_klu = self.klu_list[0] + macd_peak_klu = None + signal_peak_klu = None + for index in range(1, len(self.klu_list)): + klu = self.klu_list[index] + if klu.macd == 0 and klu.signal == 0 and klu.macdhist == 0: + continue + if self.start_type == Chan_MACDUNITTF_TYPE.CROSS0 or self.start_type == Chan_MACDUNITTF_TYPE.NEAR0: + if self.unittf_dir == Chan_MACDUNITTF_DIR.ABOVE: + if macd_peak_klu is None: + if last_klu.macd < klu.macd: + if last_klu.signal < last_klu.macdhist: + last_klu.set_macd_state(Chan_MACD_STATE.UP) + else: + last_klu.set_macd_state(Chan_MACD_STATE.HIGH) + else: + macd_peak_klu = last_klu + last_klu.set_macd_state(Chan_MACD_STATE.PEAK) + elif klu.macd > macd_peak_klu.macd: + macd_peak_klu = None + last_klu.set_macd_state(Chan_MACD_STATE.HIGH) + elif last_klu.signal < klu.signal: + last_klu.set_macd_state(Chan_MACD_STATE.HIGH_EMPTY) + elif signal_peak_klu is None: + signal_peak_klu = last_klu + last_klu.set_macd_state(Chan_MACD_STATE.HIGH_EMPTY) + elif klu.signal > signal_peak_klu.signal: + signal_peak_klu = None + last_klu.set_macd_state(Chan_MACD_STATE.HIGH) + elif last_klu.macd < last_klu.signal: + last_klu.set_macd_state(Chan_MACD_STATE.RETURN_ZERO) + if self.return_zero(last_klu, klu): + self.end_type = Chan_MACDUNITTF_TYPE.NEAR0 + self.is_end = True + self.end_klu = klu + self.end_time = klu.time + klu.set_macd_state(Chan_MACD_STATE.NEAR0) + #print(self.index, last_klu.time, last_klu.macd, last_klu.signal, last_klu.macd_state, klu.macd_state) + break + #print(self.index, last_klu.time, last_klu.macd, last_klu.signal, last_klu.macd_state) + last_klu = klu + + def return_zero(self, last_klu, klu): + return_zero = False + if last_klu.close < last_klu.ema52 and klu.close > klu.ema52: + return_zero = True + return return_zero def same_dir(self, histset): if self.unittf_dir == Chan_MACDUNITTF_DIR.ABOVE: return histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE else: return histset.histset_dir == Chan_MACDHISTSET_DIR.UNDER def set_end_klu(self, end_klu, end_type): - self.add_klu(end_klu) self.end_type = end_type self.end_klu = end_klu self.end_time = end_klu.time + self.is_end = True + self.cal_macd_state() div_time = "" for div in self.div_peak_list: div_time += f"{div.time}, " @@ -86,8 +126,7 @@ class ChanMACDUnitTF(): for histset in self.histset_list: histset_time += f"{histset.start_time}, " - if self.peak_klu: - print(self.index, self.start_klu.time, self.peak_klu.time, self.div_count, self.div_type, div_time, len(self.histset_list)) - else: - print(self.index, "None", len(self.histset_list)) + if self.peak_klu and self.div_type == Chan_MACDUNITTF_DIV.DISCRETE: + print("Cross Div: ", self.start_klu.time, self.peak_klu.time, self.div_count, self.div_type, self.unittf_dir, div_time, len(self.histset_list)) + \ No newline at end of file diff --git a/web/templates/index.html b/web/templates/index.html index 6cd2a1d..0bb3dab 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -5081,7 +5081,7 @@ if (fx.fx_strength < 1.0) { // 降低阈值,让更多分型显示 displayText = fx.fx_strength >= 0.8 ? '' : '' // 0.8以上显示点,0.8以下不显示文本 } - displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("4", "").replace("5", ""); + displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("41", "").replace("51", ""); // 添加标记配置 const markerConfig = { time: timestamp, @@ -5145,7 +5145,7 @@ if (fx.fx_strength < 1.0) { // 降低阈值,让更多分型显示 displayText = fx.fx_strength >= 1.5 ? '' : '' // 0.8以上显示点,0.8以下不显示文本 } - displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("4", "").replace("5", ""); + displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("41", "").replace("51", ""); // 添加标记配置 const markerConfig = { time: timestamp, @@ -5229,7 +5229,7 @@ if (fx.fx_strength < 1.0){ // 调整小周期阈值 displayText = fx.fx_strength >= 0.6 ? '' : '' // 0.6以上显示点 } - displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("4", "").replace("5", ""); + displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("41", "").replace("51", ""); // 小周期分型标记配置 const markerConfig = { time: timestamp, @@ -5285,7 +5285,7 @@ if (fx.fx_strength < 2.0){ // 调整小周期阈值 displayText = fx.fx_strength >= 1.5 ? '' : '' // 0.6以上显示点 } - displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("4", "").replace("5", ""); + displayText = fx.fx_type.replace("TOP", "").replace("BOTTOM", "").replace("11", "").replace("21", "").replace("31", "").replace("41", "").replace("51", ""); // 小周期KLU分型标记配置 const markerConfig = { time: timestamp,