def step_trdmax(self): """ 趋势转换判定的时间超跌超涨法 :return: """ flag = False if self.hlp_env.klist[ self. cursor].hl == 'l' and self.trdnow != 'down': # 当前待判定的是低点,当前趋势不是下跌 pre_h = self.hlp_env.klist[self.cursor].hpi[-1] if self.cursor - pre_h >= constant.TREND_REV: # 自前高超过一定时间还未出现低点 interval = [ ii.low for ii in self.hlp_env.klist[pre_h:(self.cursor + 1)] ] if self.cursor == interval.index(min(interval)) + pre_h: self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'down' self.trdchg.append(self.cursor) self.hlp_env.klist[self.cursor].trd = 'down' flag = True self.cursor += 1 printt( f"##`step_trdmax`,确认下跌趋势开启,位置{self.cursor-1};" f"之前趋势:{self.hlp_env.klist[self.cursor-1].pre_trd};" f"确认条件:超过{constant.TREND_REV}未出现低点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) elif self.hlp_env.klist[ self. cursor].hl == 'h' and self.trdnow != 'up': # 待判定高点,当前趋势非上涨 pre_l = self.hlp_env.klist[self.cursor].lpi[-1] if self.cursor - pre_l >= constant.TREND_REV: interval = [ ii.high for ii in self.hlp_env.klist[pre_l:(self.cursor + 1)] ] if self.cursor == interval.index(max(interval)) + pre_l: self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'up' self.trdchg.append(self.cursor) self.hlp_env.klist[self.cursor].trd = 'up' flag = True self.cursor += 1 printt( f"##`step_trdmax`,确认上涨趋势开启,位置{self.cursor-1};" f"之前趋势:{self.hlp_env.klist[self.cursor-1].pre_trd};" f"确认条件:超过{constant.TREND_REV}未出现高点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) return flag
def init_trd(self): if len(self.hlp_env.hpi) + len(self.hlp_env.lpi) < 4: raise TrendError( f"TrendError:{self.hlp_env.code}高低点个数不足,无法继续策略已被忽略") else: if self.hlp_env.hpi[0] > self.hlp_env.lpi[0]: # 低点先出现 if self.hlp_env.klist[self.hlp_env.lpi[ 1]].low > self.hlp_env.klist[self.hlp_env.lpi[0]].low: # 低点升高,推断为上升趋势,趋势开始时间为第二个低点被确认 self.cursor = self.hlp_env.klist[ self.hlp_env.lpi[1]].hl_confirmed self.hlp_env.klist[self.cursor].trd = 'up' self.trdchg.append(self.cursor) self.trdnow = 'up' printt(f"##`init_trd`,从l1-h1-l2(l2>l1)推断为上涨趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.cursor = self.hlp_env.klist[ self.hlp_env.lpi[1]].hl_confirmed self.hlp_env.klist[self.cursor].trd = 'consd' self.trdchg.append(self.cursor) self.trdnow = 'consd' printt(f"##`init_trd`,从l1-h1-l2(l2<l1)推断为盘整趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: # 高点先出现 if self.hlp_env.klist[ self.hlp_env.hpi[1]].high < self.hlp_env.klist[ self.hlp_env.hpi[0]].high: # 高点降低 self.cursor = self.hlp_env.klist[ self.hlp_env.hpi[1]].hl_confirmed self.hlp_env.klist[self.cursor].trd = 'down' self.trdchg.append(self.cursor) self.trdnow = 'down' printt(f"##`init_trd`,从h1-l1-h2(h2<h1)推断为下跌趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: # 高点抬高 self.cursor = self.hlp_env.klist[ self.hlp_env.hpi[1]].hl_confirmed self.hlp_env.klist[ self.cursor].trd = 'consd' # 高-低-高(抬高)-->盘整 self.trdchg.append(self.cursor) # 记录趋势改变(或首次出现能被判定的趋势类型时) self.trdnow = 'consd' printt(f"##`init_trd`,从h1-l1-h2(h2>h1)推断为盘整趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) self.cursor += 1
def buy_in_day(self, l_p, typ): """ 在日线级别上的买入操作需要满足以下条件 / 1.30min级别买入失败 / 2.日线低点被确认当日K收盘 / 3.确认当日K的最高价距离被确认的低点上涨幅度低于阈值 :param l_p: 最近被确认日线低点索引 :param typ: 卖点类型 :return: 是否发生日线买入操作 """ flag = False # 是否发生买入操作 l_pp = self.klist[l_p].low l_confirmed = self.klist[l_p].hl_confirmed p = self.klist[l_confirmed].high if p <= l_pp * (1 + constant.MAX_UPFLOAT): buy_p = Trade.Buy(self.klist[l_confirmed].t, self.klist[l_confirmed].i, typ, self.klist[l_confirmed].close, self.account, l_pp) printt( f"##`buy_in_day`,发现日线级别买点,位置{l_confirmed},买点类型{typ};" f"买入价格{self.klist[l_confirmed].close};" f"买入理由:日线级别低点被确认时上涨幅度未超过阈值;" f"止损价格{l_pp}-->被确认日线低点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) flag = True buy_p.register() self.order_l.append((buy_p, len(self.bs_list))) self.bs_list.append(buy_p) self.klist[l_confirmed].trade_info( len(self.bs_list) - 1, buy_p.typ, buy_p.price, buy_p.volume, buy_p.stop_p) else: printt(f"##`buy_in_day`,未发现日线级别买点;" f"失败理由:日线级别低点被确认时上涨幅度超过阈值", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) return flag
def init_hl(self): flag = True # 是否找到顶分型或底分型 jj = 0 while flag: if self.klist[jj + 1].high >= self.klist[jj].high and \ self.klist[jj + 1].high > self.klist[jj + 2].high: self.temp_h = jj self.hl = "h" self.temp_min = jj self.klist[jj].temp_h = jj self.klist[jj].hl = "h" self.klist[jj].temp_min = jj self.cursor = jj + 1 flag = False printt( f"##`init_hl`,找到顶分型,位置{jj};" f"当前寻找高点,待判定高点位置{jj},高点价位{self.klist[jj].high}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) elif self.klist[jj + 1].low <= self.klist[jj].low and \ self.klist[jj + 1].low < self.klist[jj + 2].low: self.temp_l = jj self.hl = "l" self.temp_max = jj self.klist[jj].temp_l = jj self.klist[jj].hl = "l" self.klist[jj].temp_max = jj self.cursor = jj + 1 flag = False printt( f"##`init_hl`,找到底分型,位置{jj};" f"当前寻找低点,待判定低点位置{jj},低点价位{self.klist[jj].low}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) else: jj += 1
def roll_forward(self, lev_higher): while self.hlp_env.cursor < len(self.klist) and \ self.klist[self.hlp_env.cursor].i <= lev_higher.i: self.hlp_env.step_hl( wait_thresh=constant.WAIT_30TO5) # step_hl操作会使cursor向后推 # 如果有同时在进行的低级别过程 if self.lev_chg_lower: self.lev_chg_lower.roll_forward( self.klist[self.hlp_env.cursor - 1]) if self.lev_chg_lower.end_up_trd: self.end_up_trd = True printt( f"###`roll_forward`,30min->5min级别下上涨趋势结束," f"位置{lev_higher.i.kti}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) self.sell_k = self.lev_chg_lower.sell_k self.hp5 = [ self.lev_chg_lower.hlp_env.klist[cur] for cur in self.lev_chg_lower.hlp_env.hpi ] self.lp5 = [ self.lev_chg_lower.hlp_env.klist[cur] for cur in self.lev_chg_lower.hlp_env.lpi ] break # 没有更低级别的进程 else: # 是否满足本级别终止条件 # 如果当前级别至少有一个低点 # 由于默认应当已经在上涨趋势,一旦跌破前低就认为是结束本级别上涨趋势 if self.hlp_env.lpi: if self.klist[self.hlp_env.cursor-1].low < \ self.klist[self.hlp_env.lpi[-1]].low: self.end_up_trd = True self.sell_k = self.klist[self.hlp_env.cursor - 1] printt( f"###`roll_forward`," f"{['30min', '5min'][self.lev-2]}级别下上涨趋势结束," f"位置{lev_higher.i.kti},发出卖点信号", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) break # 不满足本级别终止条件,是否需要进入低接别 if self.lev == 2 and self.klist[self.hlp_env.cursor - 1].lev_chg_signal: self.lev_chg_lower = Trade.LevChg( code=self.code, lev=3, start=self.klist[self.hlp_env.cursor], ref_t=self.ref_t) printt( f"###`roll_forward`," f"由30min操作级别转入5min操作级别寻找卖点," f"位置{lev_higher.i.kti}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) # 完成本轮循环,说明本级别过程仍然继续,需要考虑扩充本级别序列的数据 if len(self.klist) - self.hlp_env.cursor <= [ constant.LEN_K5 * 0.25, constant.LEN_K30 * 0.25 ][self.lev == 2]: self.hlp_env.extend_klist(self.ref_t)
def seek_to_sell(self): ''' 此函数用于寻找卖点 :return: ''' flag = False # 是否发生卖出操作 # 如果没有多头仓位,不操作 if not self.order_l: pass else: # 先以日线卖出标准将能够卖出的都卖出 for b in self.order_l: bb = b[0] # b =(buy object, index in order_l) # 符合日线上止损点或止盈点卖出条件, 注意不能在同一天交易 if self.klist[self.cursor].low < bb.stop_p and self.klist[self.cursor].i.kti[0] > \ bb.index_k.kti[0]: # 如果是浮盈后离场 if bb.max_profit > constant.THRESH_PROFIT: typ = "S3" # 其他止损点离场 else: typ = "S2" # 创建卖点对象 sell_p = Trade.Sell(self.klist[self.cursor].t, self.klist[self.cursor].i, typ, bb.volume, self.klist[self.cursor].close, self.account, bb) printt( f"##`seek_to_sell`,发现卖点,位置{self.cursor};" f"卖点类型{typ},卖出价格{self.klist[self.cursor].close};" f"卖出理由:{constant.BUYSELL_TYPE[typ][2]}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) flag = True # 在Account中注册卖点信息 sell_p.register() self.bs_list.append(sell_p) self.order_l.remove(b) self.order_s.append((sell_p, len(self.bs_list) - 1)) self.klist[self.cursor].trade_info( len(self.bs_list) - 1, typ, sell_p.price, sell_p.volume, None) elif self.klist[self.cursor].low < self.klist[self.klist[ self.cursor].lpi[-1]].low and self.klist[ self.cursor].i.kti[0] > bb.index_k.kti[0]: # 不符合上述条件,但是直接跌破前日线低点;一般适用于在日线级别买入后马上跌破 # 或30min低点恰好是日线低点马上跌破的30min买点 typ = "S1" sell_p = Trade.Sell(self.klist[self.cursor].t, self.klist[self.cursor].i, typ, bb.volume, self.klist[self.cursor].close, self.account, bb) printt( f"##`seek_to_sell`,发现卖点,位置{self.cursor};" f"卖点类型S1,卖出价格{self.klist[self.cursor].close};" f"卖出理由:{constant.BUYSELL_TYPE['S1'][2]}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) flag = True sell_p.register() self.bs_list.append(sell_p) self.order_l.remove(b) self.order_s.append((sell_p, len(self.bs_list) - 1)) self.klist[self.cursor].trade_info( len(self.bs_list) - 1, typ, sell_p.price, sell_p.volume, None) # 当日不能以日线卖出的买点,考虑是否需要进行降级别处理 # 降级别计算较复杂,主要功能采用一个特别类对象来处理 if len(self.order_l): if self.klist[self.cursor].trd == "up" and \ self.klist[self.cursor].lev_chg_signal: for b in self.order_l: bb = b[0] # 当前时间买点已经发生 if self.klist[self.cursor].i.kti > bb.index_k.kti: if not bb.lev_chg: bb.lev_chg = Trade.LevChg( code=self.code, lev=2, start=self.klist[self.cursor + 1], ref_t=[k.t for k in self.klist]) printt( f"##`sek_to_sell`,发起30min级别卖点寻找," f"开始位置{self.cursor}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: bb.lev_chg.roll_forward( self.klist[self.cursor]) if bb.lev_chg.end_up_trd: sell_k = bb.lev_chg.sell_k typ = ["S4", "S5"][sell_k.lev == 3] self.hp30 += \ [bb.lev_chg.klist[cur] for cur in bb.lev_chg.hlp_env.hpi] self.lp30 += \ [bb.lev_chg.klist[cur] for cur in bb.lev_chg.hlp_env.lpi] if typ == "S5": self.hp5 += bb.lev_chg.hp5 self.lp5 += bb.lev_chg.lp5 sell_p = Trade.Sell( sell_k.t, sell_k.i, typ, bb.volume, sell_k.close, self.account, bb) printt( f"##`seek_to_sell`,发现卖点,位置{self.cursor};" f"卖点类型{typ},卖出价格{sell_k.close};" f"卖出理由:{constant.BUYSELL_TYPE['S1'][2]}", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) flag = True sell_p.register() self.bs_list.append(sell_p) self.order_l.remove(b) self.order_s.append( (sell_p, len(self.bs_list) - 1)) self.klist[self.cursor].trade_info( len(self.bs_list) - 1, typ, sell_p.price, sell_p.volume, None) else: continue return flag
def buy_in_min30(self, start, end, pre_low, typ): flag1 = False # 是否跌破前日线低点,跌破日线前低点,终止买点搜索 flag2 = False # 是否找到买点机会 begin_time = self.klist[start + 1].t + constant.MIN30_STR[0] end_time = self.klist[end].t + constant.MIN30_STR[-1] klist30 = loadData_min(begin_time, self.code, end_time, 30, start + 1) hlp30_env = HLPointMin(klist30, self.code, constant.THRESH_30, 2, "l") for cursor in range(hlp30_env.cursor, len(hlp30_env.klist)): ref_low30 = -np.inf # 如果要以30min低点作参考, 暂时不需要 # # 如果已经有30min级别低点,不能跌破前低 # if len(hlp30_env.klist[cursor].lpi): # ref_low30 = hlp30_env.klist[hlp30_env.klist[cursor].lpi[-1]].low if hlp30_env.klist[cursor].low < max(self.klist[pre_low].low, ref_low30): flag1 = True # 买点寻找过程中是否跌破前日线低点或更保守的以30min前低点作为参照 printt( f"###`buy_in_min30`,未发现30min买点;" f"失败理由:30min下跌趋势中跌破前日线(或前30min)低点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) break else: hlp30_env.step_hl(wait_thresh=constant.WAIT_30TO5 ) # step_hl使得cursor增加1,注意减回来 if len(hlp30_env.hpi) + len(hlp30_env.lpi) < 3: # printt(f"###`buy_in_min30`,未发现30min买点;" # f"失败理由:30min未构成完整趋势", # msg_mode=constant.RunMode.REPORT, # global_mode=constant.RUN_MODE) pass else: if len(hlp30_env.klist[cursor].hpi ) >= 1: # NOTE:放宽要求,l1-h1-l2-cursor( # c>h2, l2>l1)模式也承认 if hlp30_env.klist[cursor].high > \ hlp30_env.klist[hlp30_env.klist[cursor].hpi[-1]].high and \ (hlp30_env.klist[hlp30_env.klist[cursor].lpi[-1]].low > hlp30_env.klist[hlp30_env.klist[cursor].lpi[-2]].low): flag2 = True # 是否找到符合条件的30min级别买点 # 记录有效(有交易发生)30min高点K对象 self.hp30 += \ [hlp30_env.klist[cur] for cur in hlp30_env.hpi] # 记录有效(有交易发生)30min低点K对象 self.lp30 += \ [hlp30_env.klist[cur] for cur in hlp30_env.lpi] stop_p = hlp30_env.klist[ hlp30_env.klist[cursor].temp_l].low stop_p *= (1 + constant.STOP_P_BUFFER_30) buy_p = Trade.Buy(hlp30_env.klist[cursor].t, hlp30_env.klist[cursor].i, typ, hlp30_env.klist[cursor].close, self.account, stop_p=stop_p) printt( f"###`buy_in_min30`,发现30min买点,买点类型:{typ};" f"买入理由:30min下跌趋势中突破前30min高点;" f"止损价格{stop_p}->30min最近低点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) buy_p.register() self.order_l.append((buy_p, len(self.bs_list))) self.bs_list.append(buy_p) self.klist[ hlp30_env.klist[cursor].i.kti[0]].trade_info( len(self.bs_list) - 1, typ, hlp30_env.klist[cursor].close, buy_p.volume, buy_p.stop_p) break return flag1, flag2
def seek_to_buy(self): """ 处理买入操作 :return: 是否发生买入操作 """ flag = False # 是否发生买入操作 h_confirmed = [self.klist[hh].hl_confirmed for hh in self.hpi] # 回测期间内所有高点被确认时的K线序号 if (self.cursor in h_confirmed) and len( self.klist[self.cursor].lpi): # # 如果本K线当日确认了高点,且非第一个高低点 last_opt = "NA" if not self.bs_list else self.bs_list[-1].typ pre_low = self.klist[self.cursor].lpi[-1] # 前低点序列号 pre_low_i = self.lpi.index(pre_low) # 前低点在低点序列内的序列号 # 如果前低点不是回测区间内最后一个低点,那么30min数据提取范围从本K线到后一低点被确认当日结束;否则从本K线到回测期最后一日 # 此处不涉及未来函数,因为在逐日监控中,30min买点寻找在低点被确认当日自然停止 l_confirmed = len(self.klist) - 1 if pre_low == self.lpi[-1] else \ self.klist[self.lpi[pre_low_i+1]].hl_confirmed # 左侧买点,下跌过程中,高点确认时尚未跌破前低(存在下一低点比前低点抬高的可能) if self.klist[self.cursor].trd == 'down' and \ self.klist[self.cursor].low > self.klist[pre_low].low: self.operate_lev_buy = 2 # 转换买入操作级别为30min级别 printt( f"##`seek_to_buy`,尝试寻找第一买点,位置{self.cursor};" f"确认高点处于下跌趋势中,目前未跌破前低点;" f"30min搜索范围{self.cursor}~{l_confirmed}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) res = self.buy_in_min30(self.cursor, l_confirmed, pre_low, "B1-0") if res[0]: self.operate_lev_buy = 1 elif res[1]: self.operate_lev_buy = 1 flag = True else: if pre_low_i < len(self.lpi) - 1: printt(f"##`seek_to_buy`,转而尝试寻找日线第一买点,位置{self.cursor}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) # NOTE: 不需要额外增加判定日线低点抬高的条件,因为如果中间跌破前低,res[0]为True flag = self.buy_in_day(self.lpi[pre_low_i + 1], "B1-1") # self.operate_lev_buy = [2, 1][flag] self.operate_lev_buy = 1 elif self.klist[self.cursor].trd == "consd" and \ self.klist[self.cursor].pre_trd == "down" and \ self.klist[self.cursor].low > self.klist[pre_low].low: # 由下跌转为盘整趋势中(说明被确认的高点高于前高,而前两个低点降低),目前尚未跌破前低 self.operate_lev_buy = 2 printt( f"##`seek_to_buy`,尝试寻找第二买点,位置{self.cursor};" f"确认高点处于下跌趋势转为盘整,目前未跌破前低点;" f"30min搜索范围{self.cursor}~{l_confirmed}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) res = self.buy_in_min30(self.cursor, l_confirmed, pre_low, "B2-0") if res[0]: self.operate_lev_buy = 1 elif res[1]: self.operate_lev_buy = 1 flag = True else: if pre_low_i < len(self.lpi) - 1: flag = self.buy_in_day(self.lpi[pre_low_i + 1], "B2-1") # self.operate_lev_buy = [2, 1][flag] self.operate_lev_buy = 1 elif self.klist[self.cursor].trd == "up" and \ self.klist[self.cursor].low > self.klist[pre_low].low and last_opt[:2] not in \ ("B2", "B3"): # 当前处于上涨趋势中,且上一操作不是第二买点或第三买点 self.operate_lev_buy = 2 printt( f"##`seek_to_buy`,尝试寻找第二(三)买点,位置{self.cursor};" f"确认高点处于上涨趋势中,目前未跌破前低点;" f"30min搜索范围{self.cursor}~{l_confirmed}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) res = self.buy_in_min30(self.cursor, l_confirmed, pre_low, ["B2-0", "B3-0" ][int(last_opt in ("S4", "S5"))]) if res[0]: self.operate_lev_buy = 1 elif res[1]: self.operate_lev_buy = 1 flag = True else: if pre_low_i < len(self.lpi) - 1: flag = self.buy_in_day(self.lpi[pre_low_i + 1], ["B2-1", "B3-1" ][int(last_opt in ("S4", "S5"))]) # self.operate_lev_buy = [2, 1][flag] self.operate_lev_buy = 1 elif self.klist[self.cursor].trd == "consd" and \ self.klist[self.cursor].pre_trd == "up" and \ self.klist[self.cursor].low > self.klist[pre_low].low and \ "B1" not in last_opt: # 由上涨转入盘整趋势中,高点低点区间连续放宽 self.operate_lev_buy = 2 printt( f"##`seek_to_buy`,尝试寻找第买点一,位置{self.cursor};" f"上涨趋势转为盘整,目前未跌破前低点;" f"30min搜索范围{self.cursor}~{l_confirmed}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) res = self.buy_in_min30(self.cursor, l_confirmed, pre_low, "B1-0") if res[0]: self.operate_lev_buy = 1 elif res[1]: self.operate_lev_buy = 1 flag = True else: if pre_low_i < len(self.lpi) - 1: flag = self.buy_in_day(self.lpi[pre_low_i + 1], "B1-1") # self.operate_lev_buy = [2, 1][flag] self.operate_lev_buy = 1 return flag
def step_hl(self, wait_thresh=constant.WAIT_DTO30): """ 完成导入回测期全部K线数据并创建K对象实例list后,在第二次从头遍历K对象实例时的每步迭代函数 需要完成以下任务: / 1.将当前高低点对象实例维护的全局状态域赋值给当前遍历的K对象实例的自有对应域 :param wait_thresh: :return: """ if self.cursor < len(self.klist): self.klist[self.cursor].hpi = copy(self.hpi) self.klist[self.cursor].lpi = copy(self.lpi) self.klist[self.cursor].hl = self.hl self.klist[self.cursor].temp_l = self.temp_l self.klist[self.cursor].temp_h = self.temp_h self.klist[self.cursor].temp_min = self.temp_min self.klist[self.cursor].temp_max = self.temp_max if self.hl == "h": # 在找高点过程中出现新高,则转换当前高点为待判定高点,自新高(当前K)回调最低点为当前K if self.klist[self.cursor].high > self.klist[self.temp_h].high: self.temp_h = self.cursor self.temp_min = self.cursor self.klist[self.cursor].temp_h = self.temp_h self.klist[self.cursor].temp_min = self.temp_min printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻高点过程出现新高,新待判定高点位置{self.temp_h}," f"新高点价位{self.klist[self.cursor].high}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) else: # 如果找高点过程中未出现新高 self.klist[self.cursor].use_space = self.use_space # 如果自待判定高点回调以来出现新低 if self.klist[self.cursor].low < self.klist[ self.temp_min].low: # 则当前K为回调新低 self.temp_min = self.cursor self.klist[self.cursor].temp_min = self.temp_min printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻高点过程出现自待判定高点以来回调新低," f"新低位置{self.cursor},点位{self.klist[self.cursor].low}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) # 判断是否满足以”空间回撤“大小提前(相对于回调时间长度条件)判定高点的条件 if self.space_h and \ round((self.klist[self.temp_min].low - self.klist[self.temp_h].high) / self.klist[self.temp_h].high, 2) \ < -self.space_h * constant.AVG_BUFFER: self.use_space = True self.klist[self.cursor].use_space = self.use_space printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻高点过程满足空间判定条件,可确认高点", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) if (self.use_space or (self.temp_min - self.temp_h) >= self.thresh or len(self.lpi) and self.klist[self.temp_min].low < self.klist[self.lpi[-1]].low) and\ self.temp_min == self.cursor: # 判定高点的3个条件: # / 0.当前K为自待判定高点以来回调最低点 # 以下条件三选一: # / 1.当前K距离带判定高点(时间,指有效日K线数)距离超过阈值-->时间判定 # / 2.当前K的最低价距离待判定高点最高价回调幅度超过阈值-->空间判定 # / 3.当前K的最低价已经跌破前被确认低点的最低价-->跌破前低判定 printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"确认高点,高点位置{self.temp_h},高点价位" f"{self.klist[self.temp_h].high};当前位置{self.cursor},转为寻低点" f"过程,待判定低点价位{self.klist[self.cursor].low}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) self.hpi.append(self.temp_h) self.klist[self.temp_h].hl_confirmed = self.cursor self.klist[self.cursor].confirm_hl = self.temp_h self.confirm_p.append(self.cursor) # 将全局状态转变为寻找低点相关 self.hl = "l" self.klist[self.cursor].hl = 'l' self.temp_l = self.temp_min self.klist[self.cursor].temp_l = self.temp_l self.temp_max = self.cursor self.klist[self.cursor].temp_max = self.temp_max self.use_space = False self.klist[self.cursor].hpi = copy(self.hpi) # 计算从低点到高点的上涨平均空间水平,是为下一次确认低点的条件2做准备 l2h = self.l2h() if len(l2h) >= constant.AVG_N: self.space_l = round( np.mean( list( map( lambda x, y: (self.klist[x].high - self.klist[y] .low) / self.klist[y].low, [ k[1] for k in l2h[-constant.AVG_N:] ], [ k[0] for k in l2h[-constant.AVG_N:] ]))).item(), 3) if self.space_l == np.nan: self.space_l = 0.0 else: printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"存在低点确认可参考空间涨幅{self.space_l}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) else: # 在找低点过程中 if self.klist[self.cursor].low < self.klist[self.temp_l].low: # 当前出现跌破待判定低点的前低,更新当前K为待判定低点 self.temp_l = self.cursor self.temp_max = self.cursor self.klist[self.cursor].temp_l = self.temp_l self.klist[self.cursor].temp_max = self.temp_max printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻低点过程出现新低,新待判定低点位置{self.temp_l}," f"新低点价位{self.klist[self.cursor].low}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) else: self.klist[self.cursor].use_space = self.use_space if self.klist[self.cursor].high > self.klist[ self.temp_max].high: # 当前出现自待判定低点上涨以来新高,更新当前K为上涨新高 self.temp_max = self.cursor self.klist[self.cursor].temp_max = self.temp_max printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻低点过程出现自待判定低点以来上涨新高," f"新高位置{self.cursor},点位{self.klist[self.cursor].high}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) if self.space_l and \ (self.klist[self.temp_max].high - self.klist[self.temp_l].low) / self.klist[self.temp_l].low > \ self.space_l*constant.AVG_BUFFER: self.use_space = True self.klist[self.cursor].use_space = self.use_space printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"寻低点过程满足空间判定条件,可确认低点", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) if (self.use_space or (self.temp_max - self.temp_l) >= self.thresh or len(self.hpi) and self.klist[self.temp_max].high > self.klist[self.hpi[-1]].high) and\ self.temp_max == self.cursor: # 确认低点的前提条件(条件0)和其他三个任选条件与确认高点是镜像问题 printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"确认低点,低点位置{self.temp_l},低点价位" f"{self.klist[self.temp_l].low};当前位置{self.cursor},转为寻高点" f"过程,待判定高点价位{self.klist[self.cursor].high}", msg_mode=constant.RunMode.DEBUG, global_mode=constant.RUN_MODE) self.lpi.append(self.temp_l) self.klist[self.temp_l].hl_confirmed = self.cursor self.klist[self.cursor].confirm_hl = self.temp_l self.confirm_p.append(self.cursor) # 将全局状态转换为找高点 self.hl = "h" self.klist[self.cursor].hl = 'h' self.temp_h = self.temp_max self.klist[self.cursor].temp_h = self.temp_h self.temp_min = self.cursor self.klist[self.cursor].temp_min = self.temp_min self.use_space = False self.klist[self.cursor].lpi = copy(self.lpi) h2l = self.h2l() if len(h2l) >= constant.AVG_N: self.space_h = round( np.mean( list( map( lambda x, y: (self.klist[x].high - self.klist[y] .low) / self.klist[x].high, [ k[0] for k in h2l[-constant.AVG_N:] ], [ k[1] for k in h2l[-constant.AVG_N:] ]))).item(), 3) if self.space_h == np.nan: self.space_h = 0.0 else: printt( f"##`step_hl-{constant.K_LEV_DICT[self.k_lev]}`," f"存在高点确认可参考空间涨幅{self.space_h}", msg_mode=constant.RunMode.INFO, global_mode=constant.RUN_MODE) if self.hl == "h": # 对于找高点的升频条件判定,如果超过等待时间还不能确认高点,发出级别降低提示 if self.klist[self.cursor].lpi: self.klist[self.cursor].lev_chg_signal = \ (self.cursor - self.klist[self.cursor].lpi[-1]) >= wait_thresh else: self.klist[ self. cursor].lev_chg_signal = self.cursor >= wait_thresh self.cursor += 1
def step_trd(self): """ 趋势判定主函数,在高低点标定之后进行 :return: """ if self.trdnow == 'up' and self.hlp_env.klist[self.cursor].hl == 'h': # 当前上涨趋势+待判定高点 if self.hlp_env.klist[self.cursor].low < self.hlp_env.klist[ self.hlp_env.klist[self.cursor].lpi[-1]].low: # NOTE:该种情况可能不会发生,因为一旦跌破前低点,满足确认高点条件,当即确认高点,hl转变为”l“ self.trdchg.append(self.cursor) # 上升趋势中,待判定高点未确认,若期间跌破前低,转为盘整 self.hlp_env.klist[self.cursor].trd = 'consd' self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'consd' printt( f"##`step_trd`,确认盘整趋势开启,位置{self.cursor};" f"之前趋势:up;确认条件:上涨趋势中高点未确认,跌破前低点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[self.cursor].trd = self.trdnow # 延续上升趋势 self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd elif self.trdnow == 'up' and self.hlp_env.klist[ self.cursor].hl == 'l': # 当前上涨趋势+待判定低点 if self.hlp_env.klist[self.cursor].low < self.hlp_env.klist[ self.hlp_env.klist[self.cursor].lpi[-1]].low: # 当前跌破前低点,上涨趋势终止 if self.hlp_env.klist[self.hlp_env.klist[self.cursor].hpi[-1]].high < \ self.hlp_env.klist[self.hlp_env.klist[self.cursor].hpi[-2]].high: # 高点已连续降低,可追认下跌趋势 self.hlp_env.klist[ self.cursor].trd = 'down' # 上升趋势,待判定低点,期间跌破前低,且高点已连续降低 self.hlp_env.klist[self.cursor].pre_trd = self.trdnow # 上升趋势转为下跌-->跌破前低表明上升结束,追认高点降低为下跌条件 self.trdchg.append(self.cursor) self.trdnow = 'down' printt( f"##`step_trd`,确认下跌趋势开启,位置{self.cursor};" f"之前趋势:up;确认条件:上涨趋势中待判定低点,期间跌破前低点,高点已确认并连续降低,追认下跌趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[ self.cursor].trd = 'consd' # 上升趋势,待判定低点,期间跌破前低,表明上升结束 self.trdchg.append(self.cursor) # 但高点未连续降低,尚不满足下跌条件,转为盘整 self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'consd' printt( f"##`step_trd`,确认盘整趋势开启,位置{self.cursor};" f"之前趋势:up;确认条件:上涨趋势中待判定低点,期间跌破前低点,高点已确认但未连续降低", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[ self.cursor].trd = self.trdnow # 上升趋势未跌破前低,趋势延续 self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd elif self.trdnow == 'down' and self.hlp_env.klist[ self.cursor].hl == 'l': if self.hlp_env.klist[self.cursor].high > self.hlp_env.klist[ self.hlp_env.klist[self.cursor].hpi[-1]].high: # 同其镜像问题,该种情况也不会出现,一点突破前高点,当即确认低点,hl转为h self.trdchg.append(self.cursor) # 下跌趋势,待判定低点,若期间突破前高,转为盘整 self.hlp_env.klist[self.cursor].trd = 'consd' self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'consd' printt( f"##`step_trd`,确认盘整趋势开启,位置{self.cursor};" f"之前趋势:down;确认条件:下跌趋势中低点未确认,突破前高点", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[ self.cursor].trd = self.trdnow # 下跌趋势,待判定低点,不突破前高,趋势保持 self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd elif self.trdnow == 'down' and self.hlp_env.klist[ self.cursor].hl == 'h': if self.hlp_env.klist[self.cursor].high > self.hlp_env.klist[ self.hlp_env.klist[self.cursor].hpi[-1]].high: if self.hlp_env.klist[self.hlp_env.klist[self.cursor].lpi[-1]].low > \ self.hlp_env.klist[self.hlp_env.klist[self.cursor].lpi[-2]].low: self.hlp_env.klist[ self. cursor].trd = 'up' # 下跌趋势,待判定高点,若期间突破前高,且低点已连续抬高,满足上涨条件 self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'up' self.trdchg.append(self.cursor) printt( f"##`step_trd`,确认上涨趋势开启,位置{self.cursor};" f"之前趋势:down;确认条件:下跌趋势中待判定高点,期间突破前高点,低点已确认并连续抬高,追认上涨趋势", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[self.cursor].trd = 'consd' # # 下跌趋势,待判定高点,期间高点突破,下跌结束,但低点未连续抬高,不满足上涨条件,转为盘整 self.trdchg.append(self.cursor) self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'consd' printt( f"##`step_trd`,确认盘整趋势开启,位置{self.cursor};" f"之前趋势:down;确认条件:下跌趋势中待判定高点,期间突破前高点,低点已确认但未连续抬高", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[self.cursor].trd = self.trdnow self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd elif self.trdnow == 'consd' and self.hlp_env.klist[ self.cursor].hl == 'h': # 当前盘整趋势+待判定高点 # NOTE:规范的盘整一般最终都可划归为两种形态 # / 1.h1-l1-h2(h2>h1)-cursor(c<l1,跌破前低),由上涨趋势转化而来 # / 2.l1-h1-l2(l2<l1)-cursor(c>h1,突破前高),由下跌趋势转化而来 # 脱离盘整的判定有2种: # / 1.在step_trdmax中通过时间超跌超涨非结构性的转入上涨或下跌 # / 2.在高点或低点被确认的K线上可能出现新状态 if self.hlp_env.klist[self.hlp_env.klist[ self.cursor].lpi[-1]].hl_confirmed == self.cursor: # 在当前K上确认最近低点,转入h if ((self.hlp_env.klist[self.hlp_env.klist[ self.cursor].hpi[-1]].high > self.hlp_env.klist[ self.hlp_env.klist[self.cursor].hpi[-2]].high) and (self.hlp_env.klist[self.hlp_env.klist[ self.cursor].lpi[-1]].low > self.hlp_env.klist[ self.hlp_env.klist[self.cursor].lpi[-2]].low)): # 通过确认低点后可以马上结束盘整的模式-->h1-l1-h2(h2>h1)-l2(确认,l2>l1) self.hlp_env.klist[self.cursor].trd = 'up' self.trdchg.append(self.cursor) self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'up' printt( f"##`step_trd`,确认上涨趋势开启,位置{self.cursor};" f"之前趋势:{self.hlp_env.klist[self.cursor].pre_trd};" f"确认条件:低点被确认后立即符合上涨形态", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[self.cursor].trd = self.trdnow self.hlp_env.klist[ self.cursor].pre_trd = self.hlp_env.klist[self.cursor - 1].pre_trd else: self.hlp_env.klist[self.cursor].trd = self.trdnow self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd elif self.trdnow == 'consd' and self.hlp_env.klist[ self.cursor].hl == 'l': if self.hlp_env.klist[self.hlp_env.klist[ self.cursor].hpi[-1]].hl_confirmed == self.cursor: # 当前K上确认最近高点 if ((self.hlp_env.klist[self.hlp_env.klist[ self.cursor].hpi[-1]].high < self.hlp_env.klist[ self.hlp_env.klist[self.cursor].hpi[-2]].high) and (self.hlp_env.klist[self.hlp_env.klist[ self.cursor].lpi[-1]].low < self.hlp_env.klist[ self.hlp_env.klist[self.cursor].lpi[-2]].low)): # 通过确认低点后可以马上结束盘整的模式-->l1-h1-l2(l2<l1)-h2(确认,h2<h1) self.hlp_env.klist[self.cursor].trd = 'down' self.trdchg.append(self.cursor) self.hlp_env.klist[self.cursor].pre_trd = self.trdnow self.trdnow = 'down' printt( f"##`step_trd`,确认下跌趋势开启,位置{self.cursor};" f"之前趋势:{self.hlp_env.klist[self.cursor].pre_trd};" f"确认条件:高点被确认后立即符合下跌形态", msg_mode=constant.RunMode.REPORT, global_mode=constant.RUN_MODE) else: self.hlp_env.klist[self.cursor].trd = self.trdnow self.hlp_env.klist[ self.cursor].pre_trd = self.hlp_env.klist[self.cursor - 1].pre_trd else: self.hlp_env.klist[self.cursor].trd = self.trdnow self.hlp_env.klist[self.cursor].pre_trd = self.hlp_env.klist[ self.cursor - 1].pre_trd self.cursor += 1