更新macd和signal形态判断

This commit is contained in:
jackyu66git
2025-09-06 01:01:51 +08:00
parent 09cfa56e1d
commit 154462d3f8
5 changed files with 104 additions and 43 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ class ChanKLC():
self.strength = klu.strength
self.last_top_klc = None
self.last_bottom_klc = None
self.bb_out = False
self.bb_out = True
self.macd = 0
self.signal = 0
def set_last_top_klu(self, last_top_klc):
+83 -25
View File
@@ -641,39 +641,67 @@ class ChanKLU:
#self.cal_macd_state()
def cal_macd_state(self):
# 按定义精简实现:优先级 CROSS0 > 位置(HIGH/HE/RETURN_ZERO) > NEAR0 > UNKNOWN
# 1) 首条或缺前一根
# 首条或缺前一根
if not hasattr(self, 'pre') or self.pre is None:
self.macd_state = Chan_MACD_STATE.START
return self.macd_state
# 2) 基本校验
if self.macd == 0 and self.signal == 0 and self.macdhist == 0:
# 基本校验
if (self.macd == 0 and self.signal == 0 and self.macdhist == 0) or self.ema52 == 0:
self.macd_state = Chan_MACD_STATE.UNKNOWN
return self.macd_state
# 3) CROSS0 仅以 Signal 穿越零轴判定
# CROSS0 仅以 Signal 穿越零轴判定
if self.pre.signal >= 0 and self.signal < 0:
self.macd_state = Chan_MACD_STATE.CROSS0_DOWN
return self.macd_state
if self.pre.signal <= 0 and self.signal > 0:
self.macd_state = Chan_MACD_STATE.CROSS0_UP
return self.macd_state
# 6) 趋近零轴:任一线接近零轴即可,无限接近零轴,EMA52没有加
# 穿零轴后的形态:缠绕/倒挂(基于前一状态为CROSS0_*)
if self.pre.macd_state == Chan_MACD_STATE.CROSS0_UP or self.pre.macd_state == Chan_MACD_STATE.CROSS0_DOWN:
direction = 1 if self.pre.macd_state == Chan_MACD_STATE.CROSS0_UP else -1
hist_same_dir = (self.macdhist * direction) > 0
hist_decreasing = abs(self.macdhist) < abs(self.pre.macdhist)
lines_tight = abs(self.macd - self.signal) <= 12
# 倒挂:能量柱衰减且黄白线相对方向不利/出现反向能量释放
if hist_decreasing and (((self.macd - self.signal) * direction) < 0 or not hist_same_dir):
self.macd_state = Chan_MACD_STATE.CROSS_REV
return self.macd_state
# 缠绕/粘合:紧贴能量柱运行,无反向能量释放
if lines_tight and hist_same_dir:
self.macd_state = Chan_MACD_STATE.CROSS_OS
return self.macd_state
# 趋近零轴:细化 NEAR0_* 判定
NEAR0_EPS = 15
if abs(self.macd) <= NEAR0_EPS or abs(self.signal) <= NEAR0_EPS:
lines_near_zero = abs(self.macd) <= NEAR0_EPS or abs(self.signal) <= NEAR0_EPS
touch_52 = (self.ema52 != 0) and ((abs(self.close - self.ema52) <= NEAR0_EPS) or (self.low <= self.ema52 <= self.high))
touch_24 = (self.ema24 != 0) and ((abs(self.close - self.ema24) <= NEAR0_EPS) or (self.low <= self.ema24 <= self.high))
# 完美形态:白线接近零轴 + 价格触碰/轻破EMA52 + 黄线不穿零轴
if abs(self.macd) <= NEAR0_EPS and touch_52 and (not (self.pre.signal >= 0 and self.signal < 0)) and (not (self.pre.signal <= 0 and self.signal > 0)):
self.macd_state = Chan_MACD_STATE.NEAR0_PERFECT
return self.macd_state
# EMA24 附近
if lines_near_zero and touch_24:
self.macd_state = Chan_MACD_STATE.NEAR0_24
return self.macd_state
# EMA52 附近
if lines_near_zero and touch_52:
self.macd_state = Chan_MACD_STATE.NEAR0_52
return self.macd_state
# 白线接近零轴但价格未至EMA52
if abs(self.macd) <= NEAR0_EPS and not touch_52:
self.macd_state = Chan_MACD_STATE.NEAR0_DIFF
return self.macd_state
# 一般近零轴
if lines_near_zero or touch_52:
self.macd_state = Chan_MACD_STATE.NEAR0
return self.macd_state
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:
# 穿零轴后离开零轴
if self.pre.macd_state == Chan_MACD_STATE.CROSS0_UP and ((self.macd >= self.pre.macd and self.signal >= self.pre.signal) or (abs(self.macdhist) >= abs(self.pre.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:
if self.pre.macd_state == Chan_MACD_STATE.CROSS0_DOWN and ((self.macd <= self.pre.macd and self.signal <= self.pre.signal) or (abs(self.macdhist) >= abs(self.pre.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:
@@ -682,8 +710,24 @@ class ChanKLU:
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:
# 趋势兜底:强势同步上行/下行直接进入 UP/DOWN
if self.macd > 0 and self.signal > 0 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.macd < 0 and self.signal < 0 and (self.macd <= self.pre.macd and self.signal <= self.pre.signal):
self.macd_state = Chan_MACD_STATE.DOWN
return self.macd_state
# 峰值:白线高位出现局部顶
if hasattr(self.pre, 'pre') and self.pre and self.pre.pre and self.macd > 0:
if self.pre.macd > self.pre.pre.macd and self.pre.macd > self.macd:
self.macd_state = Chan_MACD_STATE.PEAK
return self.macd_state
# 高位状态的位置状态, 高位,高位空,归零轴
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 or self.pre.macd_state == Chan_MACD_STATE.PEAK or self.pre.macd_state == Chan_MACD_STATE.HIGH_EMPTY) and self.macd > 0:
# 高位空(正区间):能量柱衰减且黄白线间距较大
if abs(self.pre.macdhist) > 0 and abs(self.macdhist) < abs(self.pre.macdhist) and abs(self.macd - self.signal) > 5:
self.macd_state = Chan_MACD_STATE.HIGH_EMPTY
return self.macd_state
if abs(self.pre.macd - self.macd) < 10:
self.macd_state = Chan_MACD_STATE.HIGH
return self.macd_state
@@ -694,7 +738,11 @@ class ChanKLU:
elif self.macd < self.pre.macd and self.signal < self.pre.signal:
self.macd_state = Chan_MACD_STATE.RETURN_ZERO
return self.macd_state
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 (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 or self.pre.macd_state == Chan_MACD_STATE.PEAK or self.pre.macd_state == Chan_MACD_STATE.HIGH_EMPTY) and self.macd < 0:
# 高位空(负区间):能量柱衰减且黄白线间距较大
if abs(self.pre.macdhist) > 0 and abs(self.macdhist) < abs(self.pre.macdhist) and abs(self.macd - self.signal) > 5:
self.macd_state = Chan_MACD_STATE.HIGH_EMPTY
return self.macd_state
if abs(self.pre.macd - self.macd) < 10:
self.macd_state = Chan_MACD_STATE.HIGH
return self.macd_state
@@ -706,26 +754,36 @@ class ChanKLU:
self.macd_state = Chan_MACD_STATE.DOWN
return self.macd_state
# 7 离开0轴开始上涨或者下跌阶段,高位之前的
# 离开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):
if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_UP or self.pre.macd_state == Chan_MACD_STATE.CROSS0_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):
if (self.pre.macd_state == Chan_MACD_STATE.NEAR0 or self.pre.macd_state == Chan_MACD_STATE.RZ_DOWN or self.pre.macd_state == Chan_MACD_STATE.CROSS0_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:
if self.pre.macd > self.macd or abs(self.macdhist) <= abs(self.pre.macdhist) or self.signal <= self.pre.signal:
self.macd_state = Chan_MACD_STATE.RETURN_ZERO
return self.macd_state
else:
if self.pre.macd < self.macd:
if self.pre.macd < self.macd or abs(self.macdhist) <= abs(self.pre.macdhist) or self.signal >= self.pre.signal:
self.macd_state = Chan_MACD_STATE.RETURN_ZERO
return self.macd_state
# 9) 其余情况
# 从 NEAR0 收敛到零轴的归零轴承接(正负两侧)
if self.pre.macd_state == Chan_MACD_STATE.NEAR0:
# 正区间朝零轴收敛
if self.macd > 0 and self.pre.macd > 0 and self.macd <= self.pre.macd and self.signal <= self.pre.signal:
self.macd_state = Chan_MACD_STATE.RETURN_ZERO
return self.macd_state
# 负区间朝零轴收敛
if self.macd < 0 and self.pre.macd < 0 and self.macd >= self.pre.macd and self.signal >= self.pre.signal:
self.macd_state = Chan_MACD_STATE.RETURN_ZERO
return self.macd_state
# 其余情况
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
+3 -1
View File
@@ -128,7 +128,9 @@ class ChanMACD():
if not last_unittf.is_end:
last_unittf.add_klu(klu)
last_seg.add_klu(klu)
last_klu = klu
last_klu = klu
klu.cal_macd_state()
print(klu.time, klu.macd_state, klu.continue_div, klu.separate_div, klu.macd, klu.signal, klu.macdhist, klu.ema24, klu.ema52, klu.close)
if last_histset:
last_histset.set_end_klu(last_klu)
if last_unittf:
+11 -11
View File
@@ -18,18 +18,22 @@ class ChanMACDHistSet():
self.last_klu = start_klu
self.start_klu = start_klu
self.peak_div_list = []
self.middle_area = 0
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
self.middle_area = abs(middle_klu.macdhist)
def set_unittf_div(self, unittf_div):
self.unittf_div = unittf_div
def add_klu(self, klu):
klu.set_histset(self)
self.klu_list.append(klu)
self.area += klu.macdhist
self.area += abs(klu.macdhist)
if self.middle_klu:
self.middle_area += abs(klu.macdhist)
if self.middle_klu and self.middle_klu.index + 1 == klu.index:
self.low_klu = None
self.peak_klu = None
@@ -52,10 +56,6 @@ class ChanMACDHistSet():
else:
self.peak_div_list.append(klu.pre)
self.div_count += 1
if klu.macd > 0 and self.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
klu.pre.continue_div = True
elif klu.macd < 0 and self.histset_dir == Chan_MACDHISTSET_DIR.UNDER:
klu.pre.continue_div = True
else:
self.peak_klu = klu.pre
else:
@@ -70,15 +70,15 @@ class ChanMACDHistSet():
else:
self.peak_div_list.append(klu.pre)
self.div_count += 1
if klu.macd > 0 and self.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
klu.pre.continue_div = True
elif klu.macd < 0 and self.histset_dir == Chan_MACDHISTSET_DIR.UNDER:
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
if len(self.peak_div_list) > 0:
klu = self.peak_div_list[-1]
if klu.macd * klu.macdhist > 0:
klu.continue_div = True
if self.start_klu.index == end_klu.index:
self.peak_klu = self.start_klu
if self.start_klu.index + 1 == end_klu.index:
@@ -95,6 +95,6 @@ class ChanMACDHistSet():
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)
#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)
+6 -5
View File
@@ -43,11 +43,12 @@ class ChanMACDUnitTF():
self.div_type = self.histset_list[0].unittf_div
self.peak_klu = self.histset_list[0].peak_klu
else:
for index in range(0, len(self.histset_list)):
histset = self.histset_list[index]
if self.same_dir(histset):
if histset.peak_klu:
print("Unittf: ", self.start_klu.time, len(self.histset_list), histset.peak_klu.time)
#if histset.peak_klu:
#print("Unittf: ", self.start_klu.time, len(self.histset_list), histset.peak_klu.time)
if self.peak_klu:
if histset.peak_klu and histset.end_time:
if abs(histset.peak_klu.macdhist) >= abs(self.peak_klu.macdhist):
@@ -58,7 +59,7 @@ class ChanMACDUnitTF():
self.div_type = Chan_MACDUNITTF_DIV.DISCRETE
self.div_count += 1
self.div_peak_list.append(histset.peak_klu)
print("Unittf: ", self.start_klu.time)
#print("Unittf: ", self.start_klu.time)
if histset.peak_klu.macd > 0 and histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
histset.peak_klu.separate_div = True
elif histset.peak_klu.macd < 0 and histset.histset_dir == Chan_MACDHISTSET_DIR.UNDER:
@@ -134,7 +135,7 @@ class ChanMACDUnitTF():
for histset in self.histset_list:
histset_time += f"{histset.start_time}, "
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))
#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))