from decimal import Decimal import chanlun.core.ChanKLC as ChanKLC from chanlun.core.ChanEnum import Chan_BI_DIR class ChanBI(): def __init__(self, klc: ChanKLC, index, ddir=Chan_BI_DIR.UP): self.start_klc = klc self.end_klc = klc self.next = None self.pre = None self.dir = ddir self.index = index self.is_sure = False self.high = klc.high self.low = klc.low self.sure_time = None self.klc_list = [] self.klc_list.append(klc) self._klc_idx = {klc.index} self.end_time = klc.end_time self.start_time = klc.start_time self._macd_hist = 0 self._macd_div = 0 self._macd_dirty = False self.seg = None self.height = 0 self.width = 0 self.slop = 0 self.fib_list = [] self.seg_index = 0 self.bi_zs = None self.seg_zs = None def set_bi_zs(self, bi_zs): for klc in self.klc_list: klc.set_bi_zs(bi_zs) def set_seg(self, seg): self.seg = seg self.seg_index = len(seg.bi_list)-1 # macd_hist / macd_div 改为惰性。原来 add_klc 每加一根 KLC 就把整笔的 # 所有 KLU 重新累加一遍,是 O(k²);而这两个值只有背驰判定(bsp.py)在读, # lean 模式下 bsp 根本不算,等于全程白算。这里只标脏,取值时才算。 # 语义不变:klc_list 只增不减(set_start_klc 会重置并同时清脏), # dir 在 klc 累加期间固定,所以延后到读取时算与逐次重算结果相同。 @property def macd_hist(self): if self._macd_dirty: self.cal_macdhist() return self._macd_hist @macd_hist.setter def macd_hist(self, v): self._macd_hist = v self._macd_dirty = False @property def macd_div(self): self.cal_macd_div() return self._macd_div @macd_div.setter def macd_div(self, v): self._macd_div = v 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 #print(self.start_time, self.end_time, self.macd_hist, self.pre.pre.macd_hist, self.macd_div) def cal_macdhist(self): self._macd_dirty = False self._macd_hist = 0 up = self.dir == Chan_BI_DIR.UP acc = 0 for klc in self.klc_list: for klu in klc.klu_list: h = klu.macdhist if up: if h > 0: acc += h elif h < 0: acc -= h self._macd_hist = acc def check_bi_zs_overlap(self): if self.next and self.next.next: if self.dir == Chan_BI_DIR.UP: return self.low < self.next.next.high else: return self.high > self.next.next.low else: return False def check_overlap(self): if self.next and self.next.next and self.next.next.is_sure: if self.dir == Chan_BI_DIR.UP: return self.high > self.next.low and self.high < self.next.next.high else: return self.high > self.next.high and self.low > self.next.next.low else: return False def set_end_klc(self, klc, sure_klc): if self.dir == Chan_BI_DIR.UP and klc.high > self.high: self.high = klc.high if self.dir == Chan_BI_DIR.DOWN and klc.low < self.low: self.low = klc.low self.end_klc = klc self.set_is_sure(True, sure_klc.end_time) self.end_time = klc.end_time self.cal_properties() #print(self.start_time, klc.fx, "This bi is ended", len(self.klc_list), klc.index - self.start_klc.index) def cal_properties(self): if self.is_sure: self.height = float(format(self.high - self.low, ".2f")) self.width = self.end_klc.index - self.start_klc.index self.slop = float(format(self.height / self.width, ".2f")) fib_list = [0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0] for fib in fib_list: self.fib_list.append(float(format(self.height * fib + self.low, ".2f"))) #print(self.end_time, self.height, self.width, self.slop, self.fib_list) def set_is_sure(self, is_sure, time): self.is_sure = is_sure self.sure_time = time def set_start_klc(self, klc, ddir): self.start_klc = klc self.klc_list = [] self.klc_list.append(klc) # klc_list 被整个换掉,去重集合与惰性缓存都要跟着重置, # 否则后续 add_klc 会以为旧下标还在里面而漏加 self._klc_idx = {klc.index} self._macd_dirty = True self.high = klc.high self.low = klc.low self.dir = ddir def set_pre(self, bi): self.pre = bi def set_next(self, bi): self.next = bi def add_klc(self, klc): # 去重原本是对 klc_list 线性扫描,配合下面每次全量重算的 macdhist, # 让「往一笔里加 k 根 KLC」变成 O(k²)。改用下标集合,O(1)。 if klc.index not in self._klc_idx: self._klc_idx.add(klc.index) self.klc_list.append(klc) self.end_klc = klc self.end_time = klc.klu_list[-1].time self._macd_dirty = True def append_klc_list(self, klc_list): self.klc_list.append(klc_list) def get_decimal(self, value): return Decimal("{:.2f}".format(value)) def update_bi(self, klc): self.end_klc = None if self.dir == Chan_BI_DIR.UP and klc.high > self.high: self.high = klc.high if self.dir == Chan_BI_DIR.DOWN and klc.low < self.low: self.low = klc.low self.is_sure = False self.sure_time = None #print(self.start_time, klc.start_time, klc.fx, "This bi is extended")