Files
chan.py/Seg/Seg.py
T
2025-06-10 01:16:09 +08:00

148 lines
5.5 KiB
Python

from typing import Generic, List, Optional, Self, TypeVar
from Bi.Bi import CBi
from Common.CEnum import BI_DIR, MACD_ALGO, TREND_LINE_SIDE
from Common.ChanException import CChanException, ErrCode
from KLine.KLine_Unit import CKLine_Unit
from Math.TrendLine import CTrendLine
from .EigenFX import CEigenFX
LINE_TYPE = TypeVar('LINE_TYPE', CBi, "CSeg")
class CSeg(Generic[LINE_TYPE]):
def __init__(self, idx: int, start_bi: LINE_TYPE, end_bi: LINE_TYPE, is_sure=True, seg_dir=None, reason="normal"):
assert start_bi.idx == 0 or start_bi.dir == end_bi.dir or not is_sure, f"{start_bi.idx} {end_bi.idx} {start_bi.dir} {end_bi.dir}"
self.idx = idx
self.start_bi = start_bi
self.end_bi = end_bi
self.is_sure = is_sure
self.dir = end_bi.dir if seg_dir is None else seg_dir
from ZS.ZS import CZS
self.zs_lst: List[CZS[LINE_TYPE]] = []
self.eigen_fx: Optional[CEigenFX] = None
self.seg_idx = None # 线段的线段用
self.parent_seg: Optional[CSeg] = None # 在哪个线段里面
self.pre: Optional[Self] = None
self.next: Optional[Self] = None
from BuySellPoint.BS_Point import CBS_Point
self.bsp: Optional[CBS_Point] = None # 尾部是不是买卖点
self.bi_list: List[LINE_TYPE] = [] # 仅通过self.update_bi_list来更新
self.reason = reason
self.support_trend_line = None
self.resistance_trend_line = None
if end_bi.idx - start_bi.idx < 2:
self.is_sure = False
self.check()
self.ele_inside_is_sure = False
def set_seg_idx(self, idx):
self.seg_idx = idx
def check(self):
if not self.is_sure:
return
if self.is_down():
if self.start_bi.get_begin_val() < self.end_bi.get_end_val():
raise CChanException(f"下降线段起始点应该高于结束点! idx={self.idx}", ErrCode.SEG_END_VALUE_ERR)
elif self.start_bi.get_begin_val() > self.end_bi.get_end_val():
raise CChanException(f"上升线段起始点应该低于结束点! idx={self.idx}", ErrCode.SEG_END_VALUE_ERR)
if self.end_bi.idx - self.start_bi.idx < 2:
raise CChanException(f"线段({self.start_bi.idx}-{self.end_bi.idx})长度不能小于2! idx={self.idx}", ErrCode.SEG_LEN_ERR)
def __str__(self):
return f"{self.start_bi.idx}->{self.end_bi.idx}: {self.dir} {self.is_sure}"
def add_zs(self, zs):
self.zs_lst = [zs] + self.zs_lst # 因为中枢是反序加入的
def cal_klu_slope(self):
assert self.end_bi.idx >= self.start_bi.idx
return (self.get_end_val()-self.get_begin_val())/(self.get_end_klu().idx-self.get_begin_klu().idx)/self.get_begin_val()
def cal_amp(self):
return (self.get_end_val()-self.get_begin_val())/self.get_begin_val()
def cal_bi_cnt(self):
return self.end_bi.idx-self.start_bi.idx+1
def clear_zs_lst(self):
self.zs_lst = []
def _low(self):
return self.end_bi.get_end_klu().low if self.is_down() else self.start_bi.get_begin_klu().low
def _high(self):
return self.end_bi.get_end_klu().high if self.is_up() else self.start_bi.get_begin_klu().high
def is_down(self):
return self.dir == BI_DIR.DOWN
def is_up(self):
return self.dir == BI_DIR.UP
def get_end_val(self):
return self.end_bi.get_end_val()
def get_begin_val(self):
return self.start_bi.get_begin_val()
def amp(self):
return abs(self.get_end_val() - self.get_begin_val())
def get_end_klu(self) -> CKLine_Unit:
return self.end_bi.get_end_klu()
def get_begin_klu(self) -> CKLine_Unit:
return self.start_bi.get_begin_klu()
def get_klu_cnt(self):
return self.get_end_klu().idx - self.get_begin_klu().idx + 1
def cal_macd_metric(self, macd_algo, is_reverse):
if macd_algo == MACD_ALGO.SLOPE:
return self.Cal_MACD_slope()
elif macd_algo == MACD_ALGO.AMP:
return self.Cal_MACD_amp()
else:
raise CChanException(f"unsupport macd_algo={macd_algo} of Seg, should be one of slope/amp", ErrCode.PARA_ERROR)
def Cal_MACD_slope(self):
begin_klu = self.get_begin_klu()
end_klu = self.get_end_klu()
if self.is_up():
return (end_klu.high - begin_klu.low)/end_klu.high/(end_klu.idx - begin_klu.idx + 1)
else:
return (begin_klu.high - end_klu.low)/begin_klu.high/(end_klu.idx - begin_klu.idx + 1)
def Cal_MACD_amp(self):
begin_klu = self.get_begin_klu()
end_klu = self.get_end_klu()
if self.is_down():
return (begin_klu.high-end_klu.low)/begin_klu.high
else:
return (end_klu.high-begin_klu.low)/begin_klu.low
def update_bi_list(self, bi_lst, idx1, idx2):
for bi_idx in range(idx1, idx2+1):
bi_lst[bi_idx].parent_seg = self
self.bi_list.append(bi_lst[bi_idx])
if len(self.bi_list) >= 3:
self.support_trend_line = CTrendLine(self.bi_list, TREND_LINE_SIDE.INSIDE)
self.resistance_trend_line = CTrendLine(self.bi_list, TREND_LINE_SIDE.OUTSIDE)
def get_first_multi_bi_zs(self):
return next((zs for zs in self.zs_lst if not zs.is_one_bi_zs()), None)
def get_final_multi_bi_zs(self):
return next((zs for zs in self.zs_lst[::-1] if not zs.is_one_bi_zs()), None)
def get_multi_bi_zs_cnt(self):
return sum(not zs.is_one_bi_zs() for zs in self.zs_lst)