refactor: 缠论引擎包化与 Web 分层(ECR-001)
将根目录引擎迁入 chanlun/ 并保留兼容 shim;拆分 TF_DF 与 web 服务; 前端模块化;strategies 改用 chanlun 导入;补充 ESS 文档与 golden 回归。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
from chanlun.core.ChanKLU import ChanKLU
|
||||
from chanlun.core.ChanEnum import Chan_MACD_STATE, Chan_MACDSEG_DIR, Chan_MACDHISTSET_DIR, Chan_MACDUNITTF_DIR, Chan_MACDUNITTF_TYPE
|
||||
from chanlun.indicators.ChanMACDSeg import ChanMACDSeg
|
||||
from chanlun.indicators.ChanMACDUnitTF import ChanMACDUnitTF
|
||||
from chanlun.indicators.ChanMACDHistSet import ChanMACDHistSet
|
||||
|
||||
class ChanMACD():
|
||||
def __init__(self, klu_list: list[ChanKLU]):
|
||||
self.klu_list = klu_list
|
||||
self.seg_list = []
|
||||
self.unittf_list = []
|
||||
self.histset_list = []
|
||||
# 状态标记列表
|
||||
self.high_position_list = [] # 高位列表
|
||||
self.high_empty_list = [] # 高位空列表
|
||||
self.return_zero_list = [] # 归零轴列表
|
||||
self.cross0_up_list = [] # 向上穿越零轴列表
|
||||
self.cross0_down_list = [] # 向下穿越零轴列表
|
||||
# 计算段 / UnitTF / HistSet 及状态标记
|
||||
self.cal_macd_state()
|
||||
self.get_klu_sd_list()
|
||||
def get_klu_sd(self):
|
||||
if self.klu_list:
|
||||
sd = self.klu_list[-1].separate_div
|
||||
if sd > 1:
|
||||
print(self.klu_list[-1].time, sd)
|
||||
return True
|
||||
return False
|
||||
def get_klu_sd_list(self):
|
||||
sd_list = []
|
||||
if self.klu_list:
|
||||
for klu in self.klu_list:
|
||||
hist = klu.macdhist
|
||||
signal = False
|
||||
if klu.pre and klu.next:
|
||||
if klu.signal > 0:
|
||||
signal = klu.pre.signal > klu.signal and klu.next.signal < klu.signal
|
||||
else:
|
||||
signal = klu.pre.signal < klu.signal and klu.next.signal > klu.signal
|
||||
sd = klu.separate_div
|
||||
if sd > 1 and ((hist > 0 and hist < 200) or (hist < 0 and hist > -200)):
|
||||
sd_list.append(klu.time)
|
||||
#print(klu.time, sd)
|
||||
return sd_list
|
||||
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
|
||||
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)
|
||||
return self.klu_list
|
||||
def cal_macd(self):
|
||||
last_seg = None
|
||||
last_unittf = None
|
||||
last_histset = None
|
||||
histset = None
|
||||
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:
|
||||
# 初始化首个直方图集合(根据当前柱体正负)
|
||||
if klu.macdhist >= 0:
|
||||
histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, None, Chan_MACDHISTSET_DIR.ABOVE)
|
||||
else:
|
||||
histset = ChanMACDHistSet(len(self.histset_list), klu.time, klu, None, Chan_MACDHISTSET_DIR.UNDER)
|
||||
self.histset_list.append(histset)
|
||||
last_histset = histset
|
||||
|
||||
# 初始化首段
|
||||
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, last_unittf)
|
||||
self.seg_list.append(seg)
|
||||
last_seg = seg
|
||||
|
||||
# 初始化首个UnitTF
|
||||
unittf_dir = Chan_MACDUNITTF_DIR.ABOVE if klu.signal >= 0 else Chan_MACDUNITTF_DIR.UNDER
|
||||
unittf = ChanMACDUnitTF(len(self.unittf_list), klu.time, klu, None, unittf_dir, Chan_MACDUNITTF_TYPE.START, histset)
|
||||
self.unittf_list.append(unittf)
|
||||
last_unittf = unittf
|
||||
last_seg.add_unittf(unittf)
|
||||
# 未就绪则继续等下一根;已就绪亦已完成首个结构初始化,继续下一根
|
||||
last_klu = klu
|
||||
continue
|
||||
# 3) 直方图集合(基于当前 unittf)
|
||||
if klu.macdhist >= 0:
|
||||
if last_histset and last_histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
|
||||
last_histset.add_klu(klu)
|
||||
else:
|
||||
# 结束旧 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 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_unittf:
|
||||
last_unittf.add_histset(histset)
|
||||
else:
|
||||
if last_histset and last_histset.histset_dir == Chan_MACDHISTSET_DIR.UNDER:
|
||||
last_histset.add_klu(klu)
|
||||
else:
|
||||
# 结束旧 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 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_unittf:
|
||||
last_unittf.add_histset(histset)
|
||||
# 2) 过零切段(使用KLU中的穿越状态)
|
||||
if (klu.macd_state == Chan_MACD_STATE.CROSS0_UP or
|
||||
klu.macd_state == Chan_MACD_STATE.CROSS0_DOWN):
|
||||
# 结束旧 unittf
|
||||
last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.CROSS0)
|
||||
# 新的单位时间周期
|
||||
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)
|
||||
last_unittf = unittf
|
||||
# 收尾旧段
|
||||
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, last_unittf)
|
||||
self.seg_list.append(seg)
|
||||
last_seg.set_next(seg)
|
||||
last_seg = seg
|
||||
last_seg.add_unittf(unittf)
|
||||
else:
|
||||
# 4) UnitTF 状态机:用黄线Signal的归零轴
|
||||
if last_klu.macd_state == Chan_MACD_STATE.NEAR0 and last_unittf.div_count > 1:
|
||||
#print(klu.time, klu.macd_state)
|
||||
if klu.macd_state == Chan_MACD_STATE.RZ_UP:
|
||||
last_unittf.set_end_klu(last_klu, Chan_MACDUNITTF_TYPE.NEAR0)
|
||||
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)
|
||||
last_unittf = unittf
|
||||
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.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)
|
||||
last_unittf = unittf
|
||||
last_seg.add_unittf(unittf)
|
||||
else:
|
||||
last_unittf.add_klu(klu)
|
||||
last_seg.add_klu(klu)
|
||||
else:
|
||||
last_unittf.add_klu(klu)
|
||||
last_seg.add_klu(klu)
|
||||
|
||||
last_klu = klu
|
||||
last_histset.set_end_klu(last_klu)
|
||||
last_unittf.set_end_klu(last_klu, None)
|
||||
last_seg.set_end_klu(last_klu)
|
||||
return self.klu_list
|
||||
@@ -0,0 +1,117 @@
|
||||
from chanlun.core.ChanEnum import Chan_MACDHISTSET_DIR, Chan_MACDUNITTF_DIV, Chan_MACD_STATE
|
||||
|
||||
class ChanMACDHistSet():
|
||||
def __init__(self, index, start_time, start_klu, pre_histset, dir):
|
||||
self.index = index
|
||||
self.start_time = start_time
|
||||
self.end_time = None
|
||||
self.klu_list = []
|
||||
self.klu_list.append(start_klu)
|
||||
self.histset_dir = dir
|
||||
self.next = None
|
||||
self.pre = pre_histset
|
||||
self.peak_klu = None
|
||||
self.area = start_klu.macdhist
|
||||
self.unittf_div = Chan_MACDUNITTF_DIV.UNDIV
|
||||
self.middle_klu = None
|
||||
self.div_count = 0
|
||||
self.last_klu = start_klu
|
||||
self.start_klu = start_klu
|
||||
self.peak_div_list = []
|
||||
self.middle_area = 0
|
||||
self.total_macdhist = 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)
|
||||
#self.middle_klu = None
|
||||
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 += 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
|
||||
self.div_count = 0
|
||||
self.peak_div_list = []
|
||||
else:
|
||||
if self.last_klu:
|
||||
self.cal_macdhist_klu(klu)
|
||||
self.last_klu = klu
|
||||
def cal_macdhist_klu(self, klu):
|
||||
if self.middle_klu:
|
||||
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:
|
||||
if klu.pre.macd * klu.pre.macdhist > 0:
|
||||
self.peak_div_list.append(klu.pre)
|
||||
self.div_count += 1
|
||||
klu.pre.continue_div = True
|
||||
else:
|
||||
self.peak_klu = klu.pre
|
||||
else:
|
||||
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:
|
||||
if klu.pre.macd * klu.pre.macdhist > 0 and klu.pre.signal * klu.pre.macdhist > 0:
|
||||
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
|
||||
#if len(self.peak_div_list) > 0:
|
||||
#klu = self.peak_div_list[-1]
|
||||
#if klu.macd * klu.macdhist > 0:
|
||||
#end_klu.continue_div = True
|
||||
#print(end_klu.time, "Continue Div")
|
||||
if self.start_klu.index == end_klu.index:
|
||||
self.peak_klu = self.start_klu
|
||||
if self.start_klu.index + 1 == end_klu.index:
|
||||
if abs(self.start_klu.macdhist) > abs(end_klu.macdhist):
|
||||
self.peak_klu = self.start_klu
|
||||
else:
|
||||
self.peak_klu = end_klu
|
||||
if len(self.klu_list) >= 3 and self.peak_klu == None:
|
||||
self.peak_klu = self.klu_list[0]
|
||||
for klu in self.klu_list:
|
||||
if abs(klu.macdhist) > abs(self.peak_klu.macdhist):
|
||||
self.peak_klu = klu
|
||||
peak_str = ""
|
||||
state_str = ""
|
||||
for peak_div in self.peak_div_list:
|
||||
peak_str += f"{peak_div.time}, "
|
||||
state_str += f"{peak_div.macd_state}, "
|
||||
total_macdhist = 0
|
||||
first_klu = self.klu_list[0]
|
||||
last_klu = self.klu_list[-1]
|
||||
if (first_klu.macd > 0 and last_klu.macd > 0 and first_klu.macdhist > 0) or (first_klu.macd < 0 and last_klu.macd < 0 and first_klu.macdhist < 0):
|
||||
for klu in self.klu_list:
|
||||
self.total_macdhist += klu.macdhist
|
||||
if abs(self.total_macdhist) < 150:
|
||||
#print(self.end_time, "Total MACDHist: ", self.total_macdhist)
|
||||
last_klu.separate_div = 99999
|
||||
#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, state_str)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
from chanlun.core.ChanEnum import Chan_MACDSEG_DIR
|
||||
|
||||
|
||||
class ChanMACDSeg():
|
||||
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
|
||||
self.start_klu = start_klu
|
||||
self.end_klu = None
|
||||
self.klu_list = []
|
||||
self.klu_list.append(start_klu)
|
||||
self.unittf_list = []
|
||||
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)
|
||||
klu.set_seg(self)
|
||||
if self.seg_dir == Chan_MACDSEG_DIR.ABOVE:
|
||||
if klu.macdhist > self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist > self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
if self.high_klu.index != self.start_klu.index:
|
||||
self.ref_klu = self.high_klu
|
||||
def add_unittf(self, unittf):
|
||||
self.unittf_list.append(unittf)
|
||||
unittf.set_next(self)
|
||||
def set_end_klu(self, end_klu):
|
||||
self.add_klu(end_klu)
|
||||
self.end_klu = end_klu
|
||||
self.end_time = end_klu.time
|
||||
@@ -0,0 +1,141 @@
|
||||
from chanlun.core.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, unittf_dir, start_type, start_histset):
|
||||
self.index = index
|
||||
self.start_time = start_time
|
||||
self.end_time = None
|
||||
self.start_klu = start_klu
|
||||
self.end_klu = None
|
||||
self.klu_list = []
|
||||
self.klu_list.append(start_klu)
|
||||
self.histset_list = []
|
||||
self.histset_list.append(start_histset)
|
||||
self.div_count = 0
|
||||
start_histset.set_middle_klu(start_klu)
|
||||
self.next = None
|
||||
self.pre = pre_unittf
|
||||
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.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.peak_klu = None
|
||||
if len(self.histset_list) == 0:
|
||||
return
|
||||
if len(self.histset_list) == 1:
|
||||
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 self.peak_klu:
|
||||
if histset.peak_klu:
|
||||
if abs(histset.peak_klu.macdhist) >= abs(self.peak_klu.macdhist):
|
||||
self.peak_klu = histset.peak_klu
|
||||
self.div_type = Chan_MACDUNITTF_DIV.UNDIV
|
||||
self.div_count = 0
|
||||
else:
|
||||
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)
|
||||
if histset.peak_klu.macd > 0 and histset.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
|
||||
histset.peak_klu.set_separate_div(self.div_count)
|
||||
elif histset.peak_klu.macd < 0 and histset.histset_dir == Chan_MACDHISTSET_DIR.UNDER:
|
||||
histset.peak_klu.set_separate_div(self.div_count)
|
||||
else:
|
||||
if histset.peak_klu:
|
||||
self.peak_klu = histset.peak_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_zero = False
|
||||
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.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}, "
|
||||
histset_time = ""
|
||||
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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user