├── README.md ├── auto_find_starter_demo.py └── chan_lun_util.py /README.md: -------------------------------------------------------------------------------- 1 | # chan_lun_util_py 2 | A personal Python implementation of Chan-Lun, which is popular among Chinese stock investors. Just for fun. 3 | 4 | For more detail: https://www.joinquant.com/post/4739 5 | 6 | chan_lun_util.py 在joinquant上使用分笔功能的demo: 7 | 8 | ```python 9 | 10 | from chan_lun_util import * 11 | import matplotlib as mat 12 | import numpy as np 13 | import datetime as dt 14 | import matplotlib.pyplot as plt 15 | import time 16 | 17 | start_date='2016-02-05' 18 | end_date='2017-02-07' 19 | stock_code = '601318.XSHG' 20 | df = get_price(stock_code, start_date, end_date, frequency='daily', fields=['open','close','high', 'low'],skip_paused=False,fq='pre') 21 | 22 | date_list = df.index.tolist() 23 | data_per_day = df.values.tolist() 24 | 25 | k_line_list = [] 26 |    ''' 将dataframe数据组装进入KLineDTO的列表中 ''' 27 | for index in range(len(date_list)): 28 | date_time = date_list[index] 29 | open_price = data_per_day[index][0] 30 | close_price = data_per_day[index][1] 31 | high_price = data_per_day[index][2] 32 | low_price = data_per_day[index][3] 33 | k_line_dto = KLineDTO(date_time, 34 | date_time, 35 | date_time, 36 | open_price, high_price, low_price, close_price) 37 | k_line_list.append(k_line_dto) 38 | 39 | len(k_line_list) 40 | 41 |    '''1.K线合并,确定顶分型和底分型,得出合并K线列表merge_line_list ''' 42 | merge_line_list = find_peak_and_bottom(k_line_list, "down") 43 | 44 | '''2.分笔''' 45 | fenbi_result,final_result_array,fenbi_seq_list = fen_bi(merge_line_list) 46 | 47 | 48 | ``` 49 | 50 | ------------------------------------------------ 51 | 其中:
52 | 1. fenbi_result为boolean,True的话就是分笔成功了;False就是分笔失败后面的final_result_array和fenbi_seq_list都不用看了。
53 | 2. final_result_array,fenbi_seq_list:如果final_result_array[i]为True,则对于merge_line_list来说,merge_line_list[fenbi_seq_list[i]]就为最终顶或者底对应的合并K线dto
54 | -------------------------------------------------------------------------------- /auto_find_starter_demo.py: -------------------------------------------------------------------------------- 1 | from chan_lun_util import * 2 | from k_line_dto import * 3 | import matplotlib as mat 4 | import numpy as np 5 | import datetime as dt 6 | import matplotlib.pyplot as plt 7 | import time 8 | 9 | stock_code = '600527.XSHG' 10 | start_date = '2016-09-01' 11 | end_date = '2017-03-17' 12 | initial_trend = "down" 13 | 14 | quotes = get_price(stock_code, start_date, end_date, frequency='daily',skip_paused=False,fq='pre') 15 | quotes[quotes['volume']==0]=np.nan 16 | quotes= quotes.dropna() 17 | Close=quotes['close'] 18 | Open=quotes['open'] 19 | High=quotes['high'] 20 | Low=quotes['low'] 21 | T0 = quotes.index.values 22 | 23 | length=len(Close) 24 | 25 | fig = plt.figure(figsize=(16, 8)) 26 | ax1 = plt.subplot2grid((10,4),(0,0),rowspan=10,colspan=4) 27 | #fig = plt.figure() 28 | #ax1 = plt.axes([0,0,3,2]) 29 | 30 | X=np.array(range(0, length)) 31 | pad_nan=X+nan 32 | 33 | #计算上 下影线 34 | max_clop=Close.copy() 35 | max_clop[CloseOpen]=Open[Close>Open] 38 | 39 | #上影线 40 | line_up=np.array([High,max_clop,pad_nan]) 41 | line_up=np.ravel(line_up,'F') 42 | #下影线 43 | line_down=np.array([Low,min_clop,pad_nan]) 44 | line_down=np.ravel(line_down,'F') 45 | 46 | #计算上下影线对应的X坐标 47 | pad_nan=nan+X 48 | pad_X=np.array([X,X,X]) 49 | pad_X=np.ravel(pad_X,'F') 50 | 51 | 52 | #画出实体部分,先画收盘价在上的部分 53 | up_cl=Close.copy() 54 | up_cl[Close<=Open]=nan 55 | up_op=Open.copy() 56 | up_op[Close<=Open]=nan 57 | 58 | down_cl=Close.copy() 59 | down_cl[Open<=Close]=nan 60 | down_op=Open.copy() 61 | down_op[Open<=Close]=nan 62 | 63 | 64 | even=Close.copy() 65 | even[Close!=Open]=nan 66 | 67 | #画出收红的实体部分 68 | pad_box_up=np.array([up_op,up_op,up_cl,up_cl,pad_nan]) 69 | pad_box_up=np.ravel(pad_box_up,'F') 70 | pad_box_down=np.array([down_cl,down_cl,down_op,down_op,pad_nan]) 71 | pad_box_down=np.ravel(pad_box_down,'F') 72 | pad_box_even=np.array([even,even,even,even,pad_nan]) 73 | pad_box_even=np.ravel(pad_box_even,'F') 74 | 75 | #X的nan可以不用与y一一对应 76 | X_left=X-0.25 77 | X_right=X+0.25 78 | box_X=np.array([X_left,X_right,X_right,X_left,pad_nan]) 79 | box_X=np.ravel(box_X,'F') 80 | 81 | #Close_handle=plt.plot(pad_X,line_up,color='k') 82 | 83 | vertices_up=array([box_X,pad_box_up]).T 84 | vertices_down=array([box_X,pad_box_down]).T 85 | vertices_even=array([box_X,pad_box_even]).T 86 | 87 | handle_box_up=mat.patches.Polygon(vertices_up,color='r',zorder=1) 88 | handle_box_down=mat.patches.Polygon(vertices_down,color='g',zorder=1) 89 | handle_box_even=mat.patches.Polygon(vertices_even,color='k',zorder=1) 90 | 91 | ax1.add_patch(handle_box_up) 92 | ax1.add_patch(handle_box_down) 93 | ax1.add_patch(handle_box_even) 94 | 95 | handle_line_up=mat.lines.Line2D(pad_X,line_up,color='k',linestyle='solid',zorder=0) 96 | handle_line_down=mat.lines.Line2D(pad_X,line_down,color='k',linestyle='solid',zorder=0) 97 | 98 | ax1.add_line(handle_line_up) 99 | ax1.add_line(handle_line_down) 100 | 101 | v=[0,length,Open.min()-0.5,Open.max()+0.5] 102 | plt.axis(v) 103 | 104 | T1 = T0[-len(T0):].astype(dt.date)/1000000000 105 | Ti=[] 106 | for i in range(len(T0)/5): 107 | a=i*5 108 | d = dt.date.fromtimestamp(T1[a]) 109 | #print d 110 | T2=d.strftime('$%Y-%m-%d$') 111 | Ti.append(T2) 112 | #print tab 113 | d1= dt.date.fromtimestamp(T1[len(T0)-1]) 114 | d2=d1.strftime('$%Y-%m-%d$') 115 | Ti.append(d2) 116 | 117 | ax1.set_xticks(np.linspace(-2,len(Close)+2,len(Ti))) 118 | 119 | ll=Low.min()*0.97 120 | hh=High.max()*1.03 121 | ax1.set_ylim(ll,hh) 122 | 123 | ax1.set_xticklabels(Ti) 124 | 125 | plt.grid(True) 126 | plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right') 127 | 128 | # 处理以上分笔结果,组织成实际上图的点 129 | k_line_list = [] 130 | date_list = quotes.index.tolist() 131 | data_per_day = quotes.values.tolist() 132 | x_date_list = quotes.index.values.tolist() 133 | 134 | for index in range(len(date_list)): 135 | date_time = date_list[index] 136 | open_price = data_per_day[index][0] 137 | close_price = data_per_day[index][1] 138 | high_price = data_per_day[index][2] 139 | low_price = data_per_day[index][3] 140 | k_line_dto = KLineDTO(date_time, 141 | date_time, 142 | date_time, 143 | open_price, high_price, low_price, close_price) 144 | k_line_list.append(k_line_dto) 145 | 146 | #选择最高或者最低点,和走势此后的方向(向上up或者向下down) 147 | min_low = min(Low) 148 | max_high = max(High) 149 | initial_index = 0 150 | for i in range(len(k_line_list)): 151 | k_line_dto = k_line_list[i] 152 | if min_low == k_line_dto.low: 153 | initial_trend = 'up' 154 | initial_index = i 155 | print(k_line_dto.begin_time.strftime('%Y-%m-%d %H:%M:%S')) 156 | break 157 | if max_high == k_line_dto.high: 158 | initial_trend = 'down' 159 | initial_index = i 160 | print(k_line_dto.begin_time.strftime('%Y-%m-%d %H:%M:%S')) 161 | break 162 | 163 | # 确定需要划分的K线范围,进行截取 164 | input_k_line_list = [] 165 | if initial_index == 0: 166 | input_k_line_list = k_line_list 167 | else: 168 | input_k_line_list = k_line_list[initial_index-1:] 169 | 170 | # 1.K线合并,并且确定顶底分型 171 | merge_line_list = find_peak_and_bottom(input_k_line_list, initial_trend) 172 | 173 | # 将第一个合并K线单位置为顶/底 174 | m_line_dto = merge_line_list[0] 175 | if initial_trend == "up": 176 | m_line_dto.is_bottom = "Y" 177 | elif initial_trend == "down": 178 | m_line_dto.is_peak = "Y" 179 | 180 | # 2.分笔 181 | fenbi_result,final_result_array,fenbi_seq_list = fen_bi(merge_line_list) 182 | 183 | # 3.得到分笔结果,计算坐标显示 184 | x_fenbi_seq = [] 185 | y_fenbi_seq = [] 186 | for i in range(len(final_result_array)): 187 | if final_result_array[i]: 188 | m_line_dto = merge_line_list[fenbi_seq_list[i]] 189 | if m_line_dto.is_peak == 'Y': 190 | peak_time = None 191 | for k_line_dto in m_line_dto.member_list[::-1]: 192 | if k_line_dto.high == m_line_dto.high: 193 | # get_price返回的日期,默认时间是08:00:00 194 | peak_time = k_line_dto.begin_time.strftime('%Y-%m-%d') +' 08:00:00' 195 | break 196 | x_fenbi_seq.append(x_date_list.index(long(time.mktime(datetime.strptime(peak_time, "%Y-%m-%d %H:%M:%S").timetuple())*1000000000))) 197 | y_fenbi_seq.append(m_line_dto.high) 198 | if m_line_dto.is_bottom == 'Y': 199 | bottom_time = None 200 | for k_line_dto in m_line_dto.member_list[::-1]: 201 | if k_line_dto.low == m_line_dto.low: 202 | # get_price返回的日期,默认时间是08:00:00 203 | bottom_time = k_line_dto.begin_time.strftime('%Y-%m-%d') +' 08:00:00' 204 | break 205 | x_fenbi_seq.append(x_date_list.index(long(time.mktime(datetime.strptime(bottom_time, "%Y-%m-%d %H:%M:%S").timetuple())*1000000000))) 206 | y_fenbi_seq.append(m_line_dto.low) 207 | 208 | # 在原图基础上添加分笔蓝线 209 | plt.plot(x_fenbi_seq,y_fenbi_seq) 210 | 211 | plt.show() 212 | -------------------------------------------------------------------------------- /chan_lun_util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from datetime import datetime 3 | 4 | # from merge_line_dto import MergeLineDTO 5 | # from k_line_dto import KLineDTO 6 | # from sql_lite_util import * 7 | __author__ = 'imspzero' 8 | 9 | 10 | # K线DTO 11 | class KLineDTO(object): 12 | day = datetime.now() 13 | begin_time = datetime.now() 14 | end_time = datetime.now() 15 | open = 0.0 16 | high = 0.0 17 | low = 0.0 18 | close = 0.0 19 | 20 | def __init__(self, day, begin_time, end_time, open, high, low, close): 21 | self.day = day 22 | self.begin_time = begin_time 23 | self.end_time = end_time 24 | self.open = open 25 | self.high = high 26 | self.low = low 27 | self.close = close 28 | 29 | def __str__(self): 30 | return "(" + self.day.strftime('%Y-%m-%d %H:%M:%S') + ", " \ 31 | + self.begin_time.strftime('%Y-%m-%d %H:%M:%S') + ", " \ 32 | + self.end_time.strftime('%Y-%m-%d %H:%M:%S') + ")" 33 | 34 | 35 | # -------------------------------- 36 | 37 | # 合并后的K线DTO 38 | class MergeLineDTO(object): 39 | memberList = [] 40 | stick_num = 0 41 | begin_time = datetime.now() 42 | end_time = datetime.now() 43 | high = 0.0 44 | low = 0.0 45 | is_peak = 'N' 46 | is_bottom = 'N' 47 | member_list = [] # KLineDTO[] 48 | 49 | def __init__(self, stick_num, begin_time, end_time, high, low, is_peak, is_bottom): 50 | self.stick_num = stick_num 51 | self.begin_time = begin_time 52 | self.end_time = end_time 53 | self.high = high 54 | self.low = low 55 | self.is_peak = is_peak 56 | self.is_bottom = is_bottom 57 | 58 | def __str__(self): 59 | return "(" + self.begin_time.strftime('%Y-%m-%d %H:%M:%S') + ", " \ 60 | + self.end_time.strftime('%Y-%m-%d %H:%M:%S') + ")" 61 | 62 | 63 | # -------------------------------- 64 | 65 | def set_peak_and_bottom_flag(merge_line_list): 66 | # 标记顶和底 67 | # []MergeLineDTO 68 | 69 | if len(merge_line_list) < 3: 70 | return 71 | 72 | # 顶和底,暂不考虑是否公用k线 73 | 74 | i = 1 75 | while i < len(merge_line_list) - 1: 76 | first_dto = merge_line_list[i - 1] 77 | middle_dto = merge_line_list[i] 78 | last_dto = merge_line_list[i + 1] 79 | if middle_dto.high > max(first_dto.high, last_dto.high) \ 80 | and middle_dto.low > max(first_dto.low, last_dto.low): 81 | middle_dto.is_peak = 'Y' 82 | 83 | if middle_dto.high < min(first_dto.high, last_dto.high) \ 84 | and middle_dto.low < min(first_dto.low, last_dto.low): 85 | middle_dto.is_bottom = 'Y' 86 | 87 | i += 1 88 | 89 | 90 | def is_inclusive(merge_line_dto, high_price, low_price): 91 | # 判断是否存在包含关系 92 | # MergeLineDTO, float, float 93 | if (merge_line_dto.high >= high_price and merge_line_dto.low <= low_price) \ 94 | or (merge_line_dto.high <= high_price and merge_line_dto.low >= low_price): 95 | return True 96 | return False 97 | 98 | 99 | def is_down(merge_line_dto, high_price, low_price): 100 | # 是否方向向下 101 | # MergeLineDTO, float, float 102 | if merge_line_dto.high > high_price and merge_line_dto.low > low_price: 103 | return True 104 | return False 105 | 106 | 107 | def is_up(merge_line_dto, high_price, low_price): 108 | # 是否方向向上 109 | # MergeLineDTO, float, float 110 | if merge_line_dto.high < high_price and merge_line_dto.low < low_price: 111 | return True 112 | return False 113 | 114 | 115 | def merge_k_line(merge_line_dto, k_line_dto, trend): 116 | # 合并K线 117 | # MergeLineDTO, KLineDTO, string 118 | if trend == 'up': 119 | merge_line_dto.high = max(merge_line_dto.high, k_line_dto.high) 120 | merge_line_dto.low = max(merge_line_dto.low, k_line_dto.low) 121 | merge_line_dto.end_time = k_line_dto.end_time 122 | if trend == 'down': 123 | merge_line_dto.high = min(merge_line_dto.high, k_line_dto.high) 124 | merge_line_dto.low = min(merge_line_dto.low, k_line_dto.low) 125 | merge_line_dto.end_time = k_line_dto.end_time 126 | merge_line_dto.end_time = k_line_dto.end_time 127 | merge_line_dto.member_list.append(k_line_dto) 128 | merge_line_dto.stick_num += 1 129 | 130 | 131 | def find_peak_and_bottom(k_line_list, begin_trend): # []KLineDTO 132 | # 寻找真正的顶和底 133 | # []KLineDTO, string 134 | k_line_dto = k_line_list[0] 135 | 136 | # init for the first mergeLine 137 | merge_line_dto = MergeLineDTO(1, k_line_dto.begin_time, k_line_dto.end_time, 138 | k_line_dto.high, k_line_dto.low, 'N', 'N') 139 | merge_line_dto.member_list = [] 140 | merge_line_dto.member_list.append(k_line_dto) 141 | 142 | # new merge_line_list, and this is the return result 143 | merge_line_list = [merge_line_dto] 144 | trend = begin_trend 145 | 146 | i = 1 147 | while i < len(k_line_list): 148 | 149 | today_k_line_dto = k_line_list[i] 150 | last_m_line_dto = merge_line_list[len(merge_line_list) - 1] 151 | if is_inclusive(last_m_line_dto, today_k_line_dto.high, today_k_line_dto.low): 152 | # 假如存在包含关系,合并K线 153 | merge_k_line(last_m_line_dto, today_k_line_dto, trend) 154 | else: 155 | if is_up(last_m_line_dto, today_k_line_dto.high, today_k_line_dto.low): 156 | trend = "up" 157 | elif is_down(last_m_line_dto, today_k_line_dto.high, today_k_line_dto.low): 158 | trend = "down" 159 | 160 | this_mline_dto = MergeLineDTO(1, today_k_line_dto.begin_time, today_k_line_dto.end_time, 161 | today_k_line_dto.high, today_k_line_dto.low, 'N', 'N') 162 | this_mline_dto.member_list = [] 163 | this_mline_dto.member_list.append(today_k_line_dto) 164 | merge_line_list.append(this_mline_dto) 165 | 166 | # 处理顶底分型 167 | set_peak_and_bottom_flag(merge_line_list) 168 | i += 1 169 | 170 | # print(merge_line_list) 171 | # 输出检查 172 | ''' 173 | for m_line_dto in merge_line_list: 174 | print(m_line_dto.begin_time.strftime('%Y-%m-%d %H:%M:%S') + " -- " + 175 | m_line_dto.end_time.strftime('%Y-%m-%d %H:%M:%S') + "**" + 176 | m_line_dto.is_peak + "**" + m_line_dto.is_bottom + "**" + 177 | str(m_line_dto.stick_num)) 178 | ''' 179 | return merge_line_list 180 | 181 | 182 | def fen_bi(merge_line_list): 183 | # 分笔 184 | # MergeLineDTO[] 185 | point_flag_list = [False] * len(merge_line_list) 186 | # print(str(point_flag_list[0])+" " + str(point_flag_list[4])) 187 | 188 | # 1.预处理,处理后相邻的都是非同一种分型 189 | last_point_m_line_dto = None 190 | 191 | for index in range(len(merge_line_list)): 192 | this_m_line_dto = merge_line_list[index] 193 | if this_m_line_dto.is_peak == 'N' \ 194 | and this_m_line_dto.is_bottom == 'N': 195 | continue 196 | 197 | if last_point_m_line_dto is None: 198 | last_point_m_line_dto = this_m_line_dto 199 | point_flag_list[index] = True 200 | continue 201 | 202 | if last_point_m_line_dto.is_peak == 'Y' and this_m_line_dto.is_peak == 'Y': 203 | # 同为顶,取最高的 204 | if this_m_line_dto.high >= last_point_m_line_dto.high: 205 | last_point_m_line_dto = this_m_line_dto 206 | point_flag_list[index] = True 207 | elif last_point_m_line_dto.is_bottom == 'Y' and this_m_line_dto.is_bottom == 'Y': 208 | # 同为底,取最低的 209 | if this_m_line_dto.low <= last_point_m_line_dto.low: 210 | last_point_m_line_dto = this_m_line_dto 211 | point_flag_list[index] = True 212 | else: 213 | last_point_m_line_dto = this_m_line_dto 214 | point_flag_list[index] = True 215 | 216 | # 2.动态规划,找出任意[k,k+i]是否能成一笔 217 | point_index_list = [] 218 | for index in range(len(point_flag_list)): 219 | if point_flag_list[index]: 220 | point_index_list.append(index) 221 | 222 | point_index_matrix = [[False] * len(point_index_list) for i in range(len(point_index_list))] 223 | # print(str(point_index_matrix[0][0]) + " " + 224 | # str(point_index_matrix[len(point_index_list)-1][len(point_index_list)-1])) 225 | 226 | find_valid_point_by_dp(merge_line_list, point_index_list, point_index_matrix) 227 | 228 | # 3.根据上一步得到的结果,得出最后合理的分型 229 | result_array = [False] * len(point_index_list) 230 | has_result = False 231 | index = len(point_index_list) - 1 232 | while index > 0: 233 | for result in result_array: 234 | result = False 235 | 236 | has_result = check_final_fen_bi(merge_line_list, point_index_list, 237 | point_index_matrix, result_array, index) 238 | 239 | if has_result: 240 | break 241 | 242 | index -= 1 243 | 244 | # 4.输出分笔结果 245 | print("分笔结果 : " + str(has_result)) 246 | if not has_result: 247 | print("按照目前的划分规则,没有找到分笔的结果.") 248 | 249 | for i in range(len(result_array)): 250 | if result_array[i]: 251 | m_line_dto = merge_line_list[point_index_list[i]] 252 | if m_line_dto.is_peak == 'Y': 253 | print(m_line_dto.begin_time.strftime('%Y-%m-%d %H:%M:%S') + "\t" + 254 | m_line_dto.end_time.strftime('%Y-%m-%d %H:%M:%S') + "\t" + 255 | "合并[" + str(m_line_dto.stick_num) + "]条K线" + "\t" + 256 | "顶[" + str(m_line_dto.low) + "][" + str(m_line_dto.high) + "]") 257 | if m_line_dto.is_bottom == 'Y': 258 | print(m_line_dto.begin_time.strftime('%Y-%m-%d %H:%M:%S') + "\t" + 259 | m_line_dto.end_time.strftime('%Y-%m-%d %H:%M:%S') + "\t" + 260 | "合并[" + str(m_line_dto.stick_num) + "]条K线" + "\t" + 261 | "底[" + str(m_line_dto.low) + "][" + str(m_line_dto.high) + "]") 262 | return has_result, result_array, point_index_list 263 | 264 | 265 | def check_final_fen_bi(merge_line_list, point_index_list, 266 | point_index_matrix, result_array, end_index): 267 | # 查看最终正确的笔划分 268 | # MergeLineDTO[], boolean[], boolean[][],boolean[],integer 269 | return search_final_fen_bi(merge_line_list, point_index_list, 270 | point_index_matrix, result_array, 271 | 0, end_index) 272 | 273 | 274 | def search_final_fen_bi(merge_line_list, point_index_list, 275 | point_index_matrix, result_array, index, end_index): 276 | # 递归查找查看最终正确的笔划分 277 | # MergeLineDTO[], boolean[], boolean[][],boolean[],integer,integer 278 | if index == end_index: 279 | return True 280 | else: 281 | i = index + 1 282 | while i <= end_index: 283 | if point_index_matrix[index][i]: 284 | result_array[index] = True 285 | result_array[i] = True 286 | if search_final_fen_bi(merge_line_list, point_index_list, 287 | point_index_matrix, result_array, 288 | i, end_index): 289 | return True 290 | else: 291 | result_array[index] = False 292 | result_array[i] = False 293 | i += 1 294 | return False 295 | 296 | 297 | def find_valid_point_by_dp(merge_line_list, point_index_list, point_index_matrix): 298 | # 通过动态规划寻找有效的分型 299 | # 通过动态规划,查找局部解,结果在pointIndexMatrix中 300 | # MergeLineDTO[], boolean[], boolean[][] 301 | distance = 1 302 | while distance < len(point_index_list): 303 | # 取奇数,经过之前第一阶段的预处理,间隔为偶数的都是同类分型 304 | process_by_distance(merge_line_list, point_index_list, point_index_matrix, distance) 305 | distance += 2 306 | 307 | 308 | def process_by_distance(merge_line_list, point_index_list, point_index_matrix, distance): 309 | # 处理间隔为dist的分型组合,是否能成一笔 310 | # MergeLineDTO[], boolean[], boolean[][], integer 311 | 312 | index = 0 313 | while index < len(point_index_list) - distance: 314 | check_result = check_2point_is_multi_line(merge_line_list, 315 | point_index_list, 316 | point_index_matrix, 317 | index, index + distance) 318 | 319 | if check_result: 320 | point_index_matrix[index][index + distance] = False 321 | else: 322 | if validate_peak_and_bottom(merge_line_list, 323 | point_index_list[index], 324 | point_index_list[index + distance]): 325 | point_index_matrix[index][index + distance] = True 326 | else: 327 | point_index_matrix[index][index + distance] = False 328 | index += 1 329 | 330 | 331 | def check_2point_is_multi_line(merge_line_list, point_index_list, 332 | point_index_matrix, start_index, end_index): 333 | # 递归处理,逐步检查[startIndex,endIndex]是否能划分成多笔 334 | # MergeLineDTO[], boolean[], boolean[][], integer, integer 335 | if start_index == end_index: 336 | return True 337 | else: 338 | index = start_index + 1 339 | while index <= end_index: 340 | if point_index_matrix[start_index][index]: 341 | boolean_result = check_2point_is_multi_line(merge_line_list, 342 | point_index_list, 343 | point_index_matrix, 344 | index, end_index) 345 | if boolean_result: 346 | return True 347 | index += 1 348 | return False 349 | 350 | 351 | def validate_peak_and_bottom(merge_line_list, start_index, end_index): 352 | # 校验是否满足一笔 353 | # MergeLineDTO[], integer, integer 354 | start_m_line_dto = merge_line_list[start_index] 355 | end_m_line_dto = merge_line_list[end_index] 356 | 357 | # 1.不满足顶必须接着底、或底必须接着顶 358 | if start_index == 0: 359 | if end_m_line_dto.is_peak != 'N' and end_m_line_dto.is_bottom != 'N': 360 | return False 361 | elif (start_m_line_dto.is_peak == 'Y' and end_m_line_dto.is_peak == 'Y') \ 362 | or (start_m_line_dto.is_bottom == 'Y' and end_m_line_dto.is_bottom == 'Y'): 363 | return False 364 | 365 | # 2.顶分型与底分型经过包含处理后,不允许共用K线 366 | if end_index - start_index < 3: 367 | return False 368 | 369 | # 3.顶分型中最高K线和底分型的最低K线之间(不包括这两K线),不考虑包含关系,至少有3根(包括3根)以上K线 370 | k_line_number = 0 371 | for index in range(len(start_m_line_dto.member_list)): 372 | k_line_dto = start_m_line_dto.member_list[index] 373 | if start_m_line_dto.is_peak == 'Y' and start_m_line_dto.high == k_line_dto.high: 374 | # 顶,并且是顶元素 375 | k_line_number += (len(start_m_line_dto.member_list) - index - 1) 376 | break 377 | elif start_m_line_dto.is_bottom == 'Y' and start_m_line_dto.low == k_line_dto.low: 378 | # 底,并且是底元素 379 | k_line_number += (len(start_m_line_dto.member_list) - index - 1) 380 | break 381 | 382 | for index in range(len(end_m_line_dto.member_list)): 383 | k_line_dto = end_m_line_dto.member_list[index] 384 | if end_m_line_dto.is_bottom == 'Y' and end_m_line_dto.low == k_line_dto.low: 385 | k_line_number += index 386 | break 387 | elif end_m_line_dto.is_peak == 'Y' and end_m_line_dto.high == k_line_dto.high: 388 | k_line_number += index 389 | break 390 | # 分型中间元素的k线合计 391 | index = start_index + 1 392 | while index < end_index: 393 | m_line_dto = merge_line_list[index] 394 | k_line_number += m_line_dto.stick_num 395 | index += 1 396 | 397 | if k_line_number < 3: 398 | return False 399 | 400 | # 4.顶底分别是笔中(包括组成分型的元素)的最高和最低 401 | peak_dto = None 402 | bottom_dto = None 403 | if start_m_line_dto.is_peak == 'Y': 404 | peak_dto = start_m_line_dto 405 | bottom_dto = end_m_line_dto 406 | else: 407 | peak_dto = end_m_line_dto 408 | bottom_dto = start_m_line_dto 409 | 410 | index = 0 if start_index == 0 else start_index - 1 411 | while index <= end_index + 1: 412 | m_line_dto = merge_line_list[index] 413 | 414 | # 存在更高的点位 415 | if m_line_dto.high > peak_dto.high \ 416 | and m_line_dto.begin_time != peak_dto.begin_time: 417 | return False 418 | 419 | if m_line_dto.low < bottom_dto.low \ 420 | and m_line_dto.begin_time != bottom_dto.begin_time: 421 | return False 422 | 423 | index += 1 424 | 425 | # 5.不允许中间有其他的顶和底 426 | # 6.或许还需要判断顶底的区间是否不能重叠 427 | return True 428 | 429 | 430 | ''' 431 | def run_test(): 432 | # 测试 433 | # 取原始数据 434 | # k_line_list = get_stock_30min_data_by_time("601318", "2015-12-21 10:00:00", "2016-04-02 13:30:00") 435 | 436 | k_line_list = get_stock_week_data_by_time("999999", "2009-07-17", "2015-05-15") 437 | 438 | print(len(k_line_list)) 439 | # k_line_list = get_stock_30min_data_by_time("999999", "2015-03-10", "2015-05-16") 440 | 441 | print("---------------------------") 442 | # 分型 443 | merge_line_list = find_peak_and_bottom(k_line_list, "down") 444 | 445 | fen_bi(merge_line_list) 446 | ''' 447 | # run_test() 448 | --------------------------------------------------------------------------------