def handle_zhongshu(points: list, acc_df, end_index, zhongshu_col="zhongshu", zhongshu_change_col="zhongshu_change"): zhongshu = None zhongshu_change = None interval = None if len(points) == 4: x1 = points[0][0] x2 = points[3][0] interval = points[3][2] - points[0][2] if points[0][1] < points[1][1]: # 向下段 range = intersect((points[0][1], points[1][1]), (points[2][1], points[3][1])) if range: y1, y2 = range # 记录中枢 zhongshu = Rect(x0=x1, x1=x2, y0=y1, y1=y2) zhongshu_change = abs(y1 - y2) / y1 acc_df.loc[end_index, zhongshu_col] = zhongshu acc_df.loc[end_index, zhongshu_change_col] = zhongshu_change points = points[-1:] else: points = points[1:] else: # 向上段 range = intersect((points[1][1], points[0][1]), (points[3][1], points[2][1])) if range: y1, y2 = range # 记录中枢 zhongshu = Rect(x0=x1, x1=x2, y0=y1, y1=y2) zhongshu_change = abs(y1 - y2) / y1 acc_df.loc[end_index, zhongshu_col] = zhongshu acc_df.loc[end_index, zhongshu_change_col] = zhongshu_change points = points[-1:] else: points = points[1:] return points, zhongshu, zhongshu_change, interval
def decode_rect(dct): return Rect(x0=dct["x0"], y0=dct["y0"], x1=dct["x1"], y1=dct["y1"])
def acc_one(self, entity_id, df: pd.DataFrame, acc_df: pd.DataFrame, state: dict) -> (pd.DataFrame, dict): self.logger.info(f'acc_one:{entity_id}') if pd_is_not_null(acc_df): df = df[df.index > acc_df.index[-1]] if pd_is_not_null(df): self.logger.info(f'compute from {df.iloc[0]["timestamp"]}') # 遍历的开始位置 start_index = len(acc_df) acc_df = pd.concat([acc_df, df]) zen_state = state acc_df = acc_df.reset_index(drop=True) else: self.logger.info('no need to compute') return acc_df, state else: acc_df = df # 笔的底 acc_df['bi_di'] = False # 笔的顶 acc_df['bi_ding'] = False # 记录笔顶/底分型的值,bi_di取low,bi_ding取high,其他为None,绘图时取有值的连线即为 笔 acc_df['bi_value'] = np.NAN # 记录临时分型,不变 acc_df['tmp_ding'] = False acc_df['tmp_di'] = False # 分型的力度 acc_df['fenxing_power'] = np.NAN acc_df['duan_state'] = 'yi' # 段的底 acc_df['duan_di'] = False # 段的顶 acc_df['duan_ding'] = False # 记录段顶/底的值,为duan_di时取low,为duan_ding时取high,其他为None,绘图时取有值的连线即为 段 acc_df['duan_value'] = np.NAN # 记录在确定中枢的最后一个段的终点x1,值为Rect(x0,y0,x1,y1) acc_df['zhongshu'] = np.NAN acc_df = acc_df.reset_index(drop=True) zen_state = ZenState( dict(fenxing_list=[], direction=None, can_fenxing=None, can_fenxing_index=None, opposite_count=0, current_duan_state='yi', duans=[], pre_bi=None, pre_duan=None)) zen_state.fenxing_list: List[Fenxing] = [] # 取前11条k线,至多出现一个顶分型+底分型 # 注:只是一种方便的确定第一个分型的办法,有了第一个分型,后面的处理就比较统一 # start_index 为遍历开始的位置 # direction为一个确定分型后的方向,即顶分型后为:down,底分型后为:up fenxing, start_index, direction = handle_first_fenxing(acc_df, step=11) if not fenxing: return None, None zen_state.fenxing_list.append(fenxing) zen_state.direction = direction # list of (timestamp,value) zen_state.duans = [] pre_kdata = acc_df.iloc[start_index - 1] pre_index = start_index - 1 tmp_direction = zen_state.direction for index, kdata in acc_df.iloc[start_index:].iterrows(): # print(f'timestamp: {kdata.timestamp}') # 临时方向 tmp_direction = get_direction(kdata, pre_kdata, current=tmp_direction) # 处理包含关系 handle_including(one_df=acc_df, index=index, kdata=kdata, pre_index=pre_index, pre_kdata=pre_kdata, tmp_direction=tmp_direction) # 根据方向,寻找对应的分型 和 段 if zen_state.direction == Direction.up: tmp_fenxing_col = 'tmp_ding' fenxing_col = 'bi_ding' else: tmp_fenxing_col = 'tmp_di' fenxing_col = 'bi_di' # 方向一致,延续中 if tmp_direction == zen_state.direction: zen_state.opposite_count = 0 # 反向,寻找反 分型 else: zen_state.opposite_count = zen_state.opposite_count + 1 # 第一次反向 if zen_state.opposite_count == 1: acc_df.loc[pre_index, tmp_fenxing_col] = True acc_df.loc[pre_index, 'fenxing_power'] = fenxing_power( acc_df.loc[pre_index - 1], pre_kdata, kdata, fenxing=tmp_fenxing_col) if pd_is_not_null(zen_state.can_fenxing): # 候选底分型 if tmp_direction == Direction.up: # 取小的 if pre_kdata['low'] <= zen_state.can_fenxing['low']: zen_state.can_fenxing = pre_kdata zen_state.can_fenxing_index = pre_index # 候选顶分型 else: # 取大的 if pre_kdata['high'] >= zen_state.can_fenxing[ 'high']: zen_state.can_fenxing = pre_kdata zen_state.can_fenxing_index = pre_index else: zen_state.can_fenxing = pre_kdata zen_state.can_fenxing_index = pre_index # 分型确立 if pd_is_not_null(zen_state.can_fenxing): if zen_state.opposite_count >= 4 or ( index - zen_state.can_fenxing_index >= 8): acc_df.loc[zen_state.can_fenxing_index, fenxing_col] = True # 记录笔的值 if fenxing_col == 'bi_ding': bi_value = acc_df.loc[zen_state.can_fenxing_index, 'high'] else: bi_value = acc_df.loc[zen_state.can_fenxing_index, 'low'] acc_df.loc[zen_state.can_fenxing_index, 'bi_value'] = bi_value zen_state.pre_bi = (zen_state.can_fenxing_index, bi_value) zen_state.opposite_count = 0 zen_state.direction = zen_state.direction.opposite() zen_state.can_fenxing = None # 确定第一个段 if zen_state.fenxing_list != None: zen_state.fenxing_list.append( Fenxing(state=fenxing_col, kdata=acc_df.loc[ zen_state.can_fenxing_index, ['open', 'close', 'high', 'low']], index=zen_state.can_fenxing_index)) if len(zen_state.fenxing_list) == 4: duan_state = handle_duan( fenxing_list=zen_state.fenxing_list, pre_duan_state=zen_state.current_duan_state ) change = duan_state != zen_state.current_duan_state if change: zen_state.current_duan_state = duan_state # 确定状态 acc_df.loc[ zen_state.fenxing_list[0]. index:zen_state.fenxing_list[-1].index, 'duan_state'] = zen_state.current_duan_state duan_index = zen_state.fenxing_list[ 0].index if zen_state.current_duan_state == 'up': acc_df.loc[duan_index, 'duan_di'] = True duan_value = acc_df.loc[duan_index, 'low'] else: duan_index = zen_state.fenxing_list[ 0].index acc_df.loc[duan_index, 'duan_ding'] = True duan_value = acc_df.loc[duan_index, 'high'] # 记录段的值 acc_df.loc[duan_index, 'duan_value'] = duan_value # 记录用于计算中枢的段 zen_state.duans.append( (acc_df.loc[duan_index, 'timestamp'], duan_value)) # 计算中枢 if len(zen_state.duans) == 4: x1 = zen_state.duans[0][0] x2 = zen_state.duans[3][0] if zen_state.duans[0][ 1] < zen_state.duans[1][1]: # 向下段 range = intersect( (zen_state.duans[0][1], zen_state.duans[1][1]), (zen_state.duans[2][1], zen_state.duans[3][1])) if range: y1, y2 = range # 记录中枢 acc_df.loc[duan_index, 'zhongshu'] = Rect( x0=x1, x1=x2, y0=y1, y1=y2) zen_state.duans = zen_state.duans[ -1:] else: zen_state.duans = zen_state.duans[ 1:] else: # 向上段 range = intersect( (zen_state.duans[1][1], zen_state.duans[0][1]), (zen_state.duans[3][1], zen_state.duans[2][1])) if range: y1, y2 = range # 记录中枢 acc_df.loc[duan_index, 'zhongshu'] = Rect( x0=x1, x1=x2, y0=y1, y1=y2) zen_state.duans = zen_state.duans[ -1:] else: zen_state.duans = zen_state.duans[ 1:] # 只留最后一个 zen_state.fenxing_list = zen_state.fenxing_list[ -1:] else: # 保持之前的状态并踢出候选 acc_df.loc[ zen_state.fenxing_list[0].index, 'duan_state'] = zen_state.current_duan_state zen_state.fenxing_list = zen_state.fenxing_list[ 1:] pre_kdata = kdata pre_index = index acc_df = acc_df.set_index('timestamp', drop=False) return acc_df, zen_state
def decode_rect(dct): return Rect(x0=dct['x0'], y0=dct['y0'], x1=dct['x1'], y1=dct['y1'])
def do_compute(self): super().do_compute() one_df = self.factor_df # annotation_df format: # value flag color # entity_id timestamp # 处理分型 bi_ding = one_df[one_df.bi_ding][['timestamp', 'high']] bi_di = one_df[one_df.bi_di][['timestamp', 'low']] df1 = bi_ding.rename(columns={"high": "value"}) df1['flag'] = '顶分型' df2 = bi_di.rename(columns={"low": "value"}) df2['flag'] = '底分型' flag_df: pd.DataFrame = pd.concat([df1, df2]) flag_df = flag_df.sort_values(by=['timestamp']) flag_df['entity_id'] = self.entity_ids[0] flag_df = flag_df.set_index(['entity_id', 'timestamp']) # 处理段 up = one_df[one_df.duan_di][['timestamp', 'low']] down = one_df[one_df.duan_ding][['timestamp', 'high']] df1 = up.rename(columns={"low": "value"}) df2 = down.rename(columns={"high": "value"}) duan_df: pd.DataFrame = pd.concat([df1, df2]) duan_df = duan_df.sort_values(by=['timestamp']) duan_df['entity_id'] = self.entity_ids[0] duan_df = duan_df.set_index(['entity_id', 'timestamp']) # 处理中枢 rects: List[Rect] = [] # list of (timestamp,value) duans = [] for index, item in duan_df.iterrows(): duans.append((index[1], item.value)) if len(duans) == 4: x1 = duans[0][0] x2 = duans[3][0] if duans[0][1] < duans[1][1]: # 向下段 range = intersect((duans[0][1], duans[1][1]), (duans[2][1], duans[3][1])) if range: y1, y2 = range else: duans = duans[1:] continue else: # 向上段 range = intersect((duans[1][1], duans[0][1]), (duans[3][1], duans[2][1])) if range: y1, y2 = range else: duans = duans[1:] continue rects.append(Rect(x0=x1, x1=x2, y0=y1, y1=y2)) duans = duans[-1:] self.fenxing_value_df = flag_df self.duan_value_df = duan_df self.zhongshu_rects = rects
def transform_one(self, entity_id, df: pd.DataFrame) -> pd.DataFrame: # 记录段区间 if entity_id not in self.entity_duan_intervals: self.entity_duan_intervals[entity_id] = [] df = df.reset_index(drop=True) # 笔的底 df['bi_di'] = False # 笔的顶 df['bi_ding'] = False # 记录临时分型,不变 df['tmp_ding'] = False df['tmp_di'] = False df['duan_state'] = 'yi' # 段的底 df['duan_di'] = False # 段的顶 df['duan_ding'] = False # 记录段顶/底的值,为duan_di时取low,为duan_ding时取high,其他为None,绘图时取有值的连线即为 段 df['duan_value'] = np.NAN # 记录在确定中枢的最后一个段的终点x1,值为Rect(x0,y0,x1,y1) df['zhongshu'] = None fenxing_list: List[Fenxing] = [] # 取前11条k线,至多出现一个顶分型+底分型 # 注:只是一种方便的确定第一个分型的办法,有了第一个分型,后面的处理就比较统一 # start_index 为遍历开始的位置 # direction为一个确定分型后的方向,即顶分型后为:down,底分型后为:up fenxing, start_index, direction = handle_first_fenxing(df, step=11) fenxing_list.append(fenxing) # 临时方向 tmp_direction = direction # 候选分型(candidate) can_fenxing = None can_fenxing_index = None # 正向count count = 0 # 反方向count opposite_count = 0 # 目前段的方向 current_duan_state = 'yi' pre_kdata = df.iloc[start_index - 1] pre_index = start_index - 1 # list of (timestamp,value) duans = [] for index, kdata in df.iloc[start_index:].iterrows(): # print(f'timestamp: {kdata.timestamp}') # 临时方向 tmp_direction = get_direction(kdata, pre_kdata, current=tmp_direction) # 处理包含关系 handle_including(one_df=df, index=index, kdata=kdata, pre_index=pre_index, pre_kdata=pre_kdata, tmp_direction=tmp_direction) # 根据方向,寻找对应的分型 和 段 if direction == Direction.up: tmp_fenxing_col = 'tmp_ding' fenxing_col = 'bi_ding' else: tmp_fenxing_col = 'tmp_di' fenxing_col = 'bi_di' # 方向一致,延续中 if tmp_direction == direction: opposite_count = 0 # 反向,寻找反 分型 else: opposite_count = opposite_count + 1 # 第一次反向 if opposite_count == 1: df.loc[pre_index, tmp_fenxing_col] = True if pd_is_not_null(can_fenxing): # 候选底分型 if tmp_direction == Direction.up: # 取小的 if pre_kdata['low'] <= can_fenxing['low']: can_fenxing = pre_kdata can_fenxing_index = pre_index # 候选顶分型 else: # 取大的 if pre_kdata['high'] >= can_fenxing['high']: can_fenxing = pre_kdata can_fenxing_index = pre_index else: can_fenxing = pre_kdata can_fenxing_index = pre_index # 分型确立 if pd_is_not_null(can_fenxing): if opposite_count >= 4 or (index - can_fenxing_index >= 8): df.loc[can_fenxing_index, fenxing_col] = True # 记录笔的值 if fenxing_col == 'bi_ding': df.loc[can_fenxing_index, 'bi_value'] = df.loc[can_fenxing_index, 'high'] else: df.loc[can_fenxing_index, 'bi_value'] = df.loc[can_fenxing_index, 'low'] opposite_count = 0 direction = direction.opposite() can_fenxing = None # 确定第一个段 if fenxing_list != None: fenxing_list.append( Fenxing(state=fenxing_col, kdata=df.loc[can_fenxing_index], index=can_fenxing_index)) if len(fenxing_list) == 4: duan_state = handle_duan( fenxing_list=fenxing_list, pre_duan_state=current_duan_state) change = duan_state != current_duan_state if change: current_duan_state = duan_state # 确定状态 df.loc[fenxing_list[0]. index:fenxing_list[-1].index, 'duan_state'] = current_duan_state duan_index = fenxing_list[0].index if current_duan_state == 'up': df.loc[duan_index, 'duan_di'] = True duan_value = df.loc[duan_index, 'low'] else: duan_index = fenxing_list[0].index df.loc[duan_index, 'duan_ding'] = True duan_value = df.loc[duan_index, 'high'] # 记录段的值 df.loc[duan_index, 'duan_value'] = duan_value # 记录用于计算中枢的段 duans.append( (df.loc[duan_index, 'timestamp'], duan_value)) # 计算中枢 if len(duans) == 4: x1 = duans[0][0] x2 = duans[3][0] if duans[0][1] < duans[1][1]: # 向下段 range = intersect( (duans[0][1], duans[1][1]), (duans[2][1], duans[3][1])) if range: y1, y2 = range # 记录中枢 df.loc[duan_index, 'zhongshu'] = Rect( x0=x1, x1=x2, y0=y1, y1=y2) duans = duans[-1:] else: duans = duans[1:] else: # 向上段 range = intersect( (duans[1][1], duans[0][1]), (duans[3][1], duans[2][1])) if range: y1, y2 = range # 记录中枢 df.loc[duan_index, 'zhongshu'] = Rect( x0=x1, x1=x2, y0=y1, y1=y2) duans = duans[-1:] else: duans = duans[1:] # 只留最后一个 fenxing_list = fenxing_list[-1:] else: # 保持之前的状态并踢出候选 df.loc[fenxing_list[0].index, 'duan_state'] = current_duan_state fenxing_list = fenxing_list[1:] pre_kdata = kdata pre_index = index df = df.set_index('timestamp') return df