├── 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 |
--------------------------------------------------------------------------------