Files
quant/code/chan_series.py
2019-11-21 12:02:03 +08:00

465 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

def build(df_dr):
#合并 相关变量
group_no_last = 0 #最后的组号
group_master_n_last = 0 #最后的组长
ingroup_n_last = 0 #最后一个在组内的n
group_first_n = 0 #最后一个组的第一个n
chan_low_pre = None #chan_是指合并后的k的高低
chan_high_pre = None
df_dr['updown']= '' #K线是向上up 向下down 平flat
df_dr['group']= '' #是否在组内
df_dr['group_no']= '' #组的编号
df_dr['group_high']= '' #组的最高值
df_dr['group_low']= '' #组的最低值
df_dr['group_master']= '' #是否是组长
#分型 相关变量
fx_n_maybe_pre = 0 #前面可能是分型的n如果有方向则临时记录
fx_direction_pre = "flat" #平均值的方向
fx_high_direction_pre = "flat" #高点的方向
fx_low_direction_pre = "flat" #低点的方向
fx_chan_low_pre = None #chan_是指合并后的k的高低
fx_chan_high_pre = None
df_dr['fx']='' #分型的类型底bottom 顶top
#笔 相关变量
fx_n_pre = None
node_n_pre = None #node是前面确认的笔的节点
node_type_pre =''
node_high_pre = None
node_low_pre = None
df_dr['bi']='' #笔的类型底bottom 顶top
bi_count=0
bi_first_n=0 #第一个笔的n
bi_second_n=0 #第二个笔的n
bi_third_n=0 #第三个笔的n
#线段相关变量
dot_n_pre = None #dot是前面确认的线段的节点
dot_bi_count_pre = None #前一个dot是第几个笔
dot_next_bi_n_pre = None #前一个dot的后一笔的n 用于判断新线段反弹
dot_type_pre =''
dot_high_pre = None
dot_low_pre = None
df_dr['line']='' #线段的类型底bottom 顶top
#中枢相关变量
zs_no=0 #最后一个中枢号
zs_first_n_pre=0 #未结束的中枢的开始n
zs_end_n_pre=0 #前面已结束的中枢的结束n
zg=0
zd=0
gg=0
dd=0
start_direction=''
df_dr['zs_no']=0
df_dr['zg']=0
df_dr['zd']=0
df_dr['gg']=0
df_dr['dd']=0
df_dr['zs_direction']=''
df_dr['zs_confirm_time']=''
df_dr['zs_confirm_price']=''
#逐笔循环
for n, k in df_dr.iterrows():
if n%10000==0:
print('开始处理:',n,'/',len(df_dr))
open = k.open
close = k.close
low = k.low
high = k.high
###一、合并 #############################################################################
updown='flat' #升降
is_group=False #是否在组里
is_group_master=False #是否组长,组长是最高的
group_no=0
group_high=0
group_low=0
is_confirm_v_group = False #确定虚拟组包括单个不成组的K,即前面的K跟这个肯定不同组那么前面的虚拟组确认
is_confirm_v_group_n = 0 #已确定虚拟组的组长单个K就是这个K
if(chan_low_pre==None or chan_high_pre==None):
chan_low_pre = low
chan_high_pre = high
else:
#上一个原始K
k_pre = df_dr.iloc[n-1-1]
low_pre = k_pre.low
high_pre = k_pre.high
is_group_pre = k_pre.group
#上升下降
#上升(跟原始K比较平均高度)
if high_pre+low_pre < high+low:
updown='up'
#下降(跟原始K比较平均高度)
elif high_pre+low_pre > high+low:
updown='down'
elif open<close:
updown = 'up'
elif open<close:
updown = 'down'
else:
updown = 'flat'
#包含 #不能太多的包含,限制一组成员个数
if ((chan_high_pre<=high and chan_low_pre>=low) or (chan_high_pre>=high and chan_low_pre<=low)) and not (n>group_first_n+2 and ingroup_n_last==n-1):
#上一个本来在组内,这个合并到原来的组
if ingroup_n_last==n-1:
group_no=group_no_last
#新组
else:
group_no=group_no_last+1
group_first_n=n-1
group_no_last=group_no
#组长
if chan_high_pre<=high and chan_low_pre>=low:
is_group_master = True
group_master_n_last=n
elif chan_high_pre>=high and chan_low_pre<=low and ingroup_n_last!=n-1: #新组并且前面的高,需要设置前面的是组长
df_dr.at[n-1,'group_master']= True
group_master_n_last=n-1
group_high=max(high, chan_high_pre)
group_low=min(low, chan_low_pre)
chan_high_pre = group_high
chan_low_pre = group_low
is_group=True
ingroup_n_last=n
else: #不包含
chan_low_pre = low
chan_high_pre = high
is_confirm_v_group = True #这个与前面没有包含关系,则前面的确认
is_confirm_v_group_n = group_master_n_last if is_group_pre else n-1
#写标识值到表中
df_dr.at[n,'updown']= updown
df_dr.at[n,'group']= is_group
df_dr.at[n,'group_no']= group_no
df_dr.at[n,'group_high']= group_high
df_dr.at[n,'group_low']= group_low
df_dr.at[n,'group_master']= is_group_master
if is_group:
df_dr.at[n-1,'group']= is_group
df_dr.at[n-1,'group_no']= group_no
#刷新同组内的group_high and group_low
for j in range(group_first_n, n):
df_dr.at[j,'group_high']= group_high
df_dr.at[j,'group_low']= group_low
if is_group_master:
df_dr.at[j,'group_master']= False #踢掉原来的组长
###二、分型 #############################################################################
## 分型需要出现的k线或者组明确如果不确认是否被分组或者分组未结束即不确认组长的需要等确认后再确认分型
is_confirm_fx = False #确定分型,前一个组或者个体是分型,为顶分型
is_confirm_fx_n = 0 #已确定分型的分型顶点
fx_type = ''
fx_direction = "flat" #平均值的方向
fx_high_direction = "flat" #高点的方向
fx_low_direction = "flat" #低点的方向
if is_confirm_v_group:
last_group_high=df_dr.at[is_confirm_v_group_n,'high']
last_group_low=df_dr.at[is_confirm_v_group_n,'low']
if(fx_chan_low_pre==None or fx_chan_high_pre==None):
fx_chan_low_pre=last_group_low
fx_chan_high_pre=last_group_high
else:
#与前面的比较
if fx_chan_high_pre+fx_chan_low_pre<last_group_high+last_group_low:
fx_direction='up'
elif fx_chan_high_pre+fx_chan_low_pre>last_group_high+last_group_low:
fx_direction='down'
if last_group_high>fx_chan_high_pre:
fx_high_direction='up'
elif last_group_high<fx_chan_high_pre:
fx_high_direction='down'
if last_group_low>fx_chan_low_pre:
fx_low_direction='up'
elif last_group_low<fx_chan_low_pre:
fx_low_direction='down'
if fx_high_direction_pre=='up' and fx_high_direction=='down': #顶
is_confirm_fx=True
is_confirm_fx_n=fx_n_maybe_pre
fx_type='top'
elif fx_low_direction_pre=='down' and fx_low_direction=='up': #底
is_confirm_fx=True
is_confirm_fx_n=fx_n_maybe_pre
fx_type='bottom'
if fx_high_direction=='up' or fx_low_direction=='down' or fx_high_direction=='flat' or fx_low_direction=='flat':
fx_n_maybe_pre=is_confirm_v_group_n
if fx_direction!='flat':
fx_direction_pre=fx_direction
if fx_high_direction!='flat':
fx_high_direction_pre=fx_high_direction
if fx_low_direction!='flat':
fx_low_direction_pre=fx_low_direction
fx_chan_low_pre=last_group_low
fx_chan_high_pre=last_group_high
#分型写入表
if is_confirm_fx:
df_dr.at[is_confirm_fx_n,'fx']= fx_type
###三、笔 #############################################################################
##笔的确认是检查上面确认的分型的is_confirm_fx_n不是当前循环的k线n因为当前的k线n不可能确认分型
is_confirm_bi = False
is_confirm_bi_n = 0
is_bi_extend = False
if is_confirm_fx:
last_fx_high=df_dr.at[is_confirm_fx_n,'high']
last_fx_low=df_dr.at[is_confirm_fx_n,'low']
#第一个分型确定为笔的节点
if fx_n_pre==None:
is_confirm_bi=True
bi_count+=1
#与前节点类型相同且趋势延申删除上一个节点node
elif node_type_pre==fx_type and ((fx_type=='bottom' and last_fx_low<node_low_pre) or (fx_type=='top' and last_fx_high>node_high_pre)):
df_dr.at[node_n_pre,'bi']= ''
is_confirm_bi=True
is_bi_extend=True
#与前节点类型不同且超过3个差,是新笔
elif node_type_pre!=fx_type and is_confirm_fx_n-node_n_pre>3:
if (fx_type=='bottom' and last_fx_low<node_high_pre) or (fx_type=='top' and last_fx_high>node_low_pre): #顶底不能高低反
is_confirm_bi=True
bi_count+=1
fx_n_pre=is_confirm_fx_n
if is_confirm_bi:
node_n_pre=is_confirm_fx_n
node_type_pre=fx_type
node_high_pre=last_fx_high
node_low_pre=last_fx_low
is_confirm_bi_n=is_confirm_fx_n
df_dr.at[is_confirm_bi_n,'bi']= fx_type
if bi_count==1:
bi_first_n=is_confirm_bi_n
elif bi_count==2:
bi_second_n=is_confirm_bi_n
elif bi_count==3:
bi_third_n=is_confirm_bi_n
###三、线段 #############################################################################
###
is_confirm_line=False
is_extend_line=False
if is_confirm_bi:
last_bi_type=df_dr.at[is_confirm_bi_n,'bi']
last_bi_high=df_dr.at[is_confirm_bi_n,'high']
last_bi_low=df_dr.at[is_confirm_bi_n,'low']
#如果上一个笔确认了线段,那么需要记录相邻的下一个笔,用于判断反弹的新线段(是否超越这个笔)
if dot_bi_count_pre!=None and dot_bi_count_pre+1==bi_count:
dot_next_bi_n_pre=is_confirm_bi_n
#找第一个线段,第一个形成走势的三+笔(如果上升,第三+笔的结束点高于第一笔的结束点)
if dot_n_pre==None and bi_count>3:
bi_first2second_direction='up' if df_dr.at[bi_second_n,'bi']=='top' else 'down'
bi_second_high=df_dr.at[bi_second_n,'high']
bi_second_low=df_dr.at[bi_second_n,'low']
bi_third_high=df_dr.at[bi_third_n,'high']
bi_third_low=df_dr.at[bi_third_n,'low']
if last_bi_type=='top' and last_bi_high>bi_second_high and bi_first2second_direction=='up': #上升突破第二个笔节点
df_dr.at[bi_first_n,'line']='bottom'
df_dr.at[is_confirm_bi_n,'line']='top'
dot_n_pre=is_confirm_bi_n
dot_type_pre='top'
dot_bi_count_pre=bi_count
is_confirm_line=True
elif last_bi_type=='bottom' and last_bi_low<bi_second_low and bi_first2second_direction=='down': #下降突破第二个笔节点
df_dr.at[bi_first_n,'line']='top'
df_dr.at[is_confirm_bi_n,'line']='bottom'
dot_n_pre=is_confirm_bi_n
dot_type_pre='bottom'
dot_bi_count_pre=bi_count
is_confirm_line=True
elif last_bi_type=='top' and last_bi_high>bi_third_high and bi_first2second_direction=='down': #上升突破第三个笔节点
df_dr.at[bi_second_n,'line']='bottom'
df_dr.at[is_confirm_bi_n,'line']='top'
dot_n_pre=is_confirm_bi_n
dot_type_pre='top'
dot_bi_count_pre=bi_count
is_confirm_line=True
elif last_bi_type=='bottom' and last_bi_low<bi_third_low and bi_first2second_direction=='up': #下降突破第三个笔节点
df_dr.at[bi_second_n,'line']='top'
df_dr.at[is_confirm_bi_n,'line']='bottom'
dot_n_pre=is_confirm_bi_n
dot_type_pre='bottom'
dot_bi_count_pre=bi_count
is_confirm_line=True
#继续找线段,不确定延申还是反弹,一直往下找,找到能确定的点
if dot_type_pre=='top':
dot_high_pre=df_dr.at[dot_n_pre,'high']
dot_low_pre=df_dr.at[dot_n_pre,'low']
if last_bi_type=='top' and last_bi_high>dot_high_pre: #看是否突破延申
df_dr.at[dot_n_pre,'line']=''
df_dr.at[is_confirm_bi_n,'line']='top'
dot_n_pre=is_confirm_bi_n
dot_type_pre='top'
dot_bi_count_pre=bi_count
is_confirm_line=True
is_extend_line=True
elif last_bi_type=='bottom' and bi_count>dot_bi_count_pre+2 : #没有延申,反弹形成新的线段
df_dr.at[is_confirm_bi_n,'line']='bottom'
dot_n_pre=is_confirm_bi_n
dot_type_pre='bottom'
dot_bi_count_pre=bi_count
is_confirm_line=True
elif dot_type_pre=='bottom':
dot_high_pre=df_dr.at[dot_n_pre,'high']
dot_low_pre=df_dr.at[dot_n_pre,'low']
if last_bi_type=='bottom' and last_bi_low<dot_low_pre: #看是否突破延申
df_dr.at[dot_n_pre,'line']=''
df_dr.at[is_confirm_bi_n,'line']='bottom'
dot_n_pre=is_confirm_bi_n
dot_type_pre='bottom'
dot_bi_count_pre=bi_count
is_confirm_line=True
is_extend_line=True
elif last_bi_type=='top' and bi_count>dot_bi_count_pre+2 : #没有延申,反弹形成新的线段
df_dr.at[is_confirm_bi_n,'line']='top'
dot_n_pre=is_confirm_bi_n
dot_type_pre='top'
dot_bi_count_pre=bi_count
is_confirm_line=True
#修正线段中间的凹凸漏点,例如上升的线段中有笔的低点低于线段的开始点,需要将这个线段的开始点移到这个更低的点,反之亦然
#有时候突然下来一笔,但是不成线段就会遗漏,此处待验证合理性
if is_confirm_line:
df_dr_line=df_dr[df_dr.line!='']
last_line_n = dot_n_pre
last2_line_n = df_dr_line.index[-2]
last2_line_high = df_dr_line.iloc[-2].high
last2_line_low = df_dr_line.iloc[-2].low
last2_line_type = df_dr_line.iloc[-2].line
df_mod = df_dr.loc[last2_line_n:last_line_n][df_dr.bi!='']
mod_i=0
modified_n_pre=None
for mod_n, mod_k in df_mod.iterrows():
mod_high=mod_k.high
mod_low=mod_k.low
mod_line_type = df_mod.at[mod_n,'line']
if mod_line_type=='':
#移动不能使与后面小于三比差,即后面一个如果是线段点,就不处理这个笔点了
if mod_i>len(df_mod)-4:
break
#移动
if last2_line_type=='top' and mod_high>last2_line_high:
df_dr.at[last2_line_n,'line']=''
if modified_n_pre!=None:
df_dr.at[modified_n_pre,'line']=''
df_dr.at[mod_n,'line']='top'
modified_n_pre=mod_n
elif last2_line_type=='bottom' and mod_low<last2_line_low:
df_dr.at[last2_line_n,'line']=''
if modified_n_pre!=None:
df_dr.at[modified_n_pre,'line']=''
df_dr.at[mod_n,'line']='bottom'
modified_n_pre=mod_n
mod_i+=1
###四、中枢 #############################################################################
###
is_confirm_zs=False
if is_confirm_line:
df_dr_line=df_dr.loc[max(zs_first_n_pre,zs_end_n_pre):][df_dr.line!=''] #只取最后需要考虑的一段
#线段延申需要处理,上一个结束点到这个点正好是三个,是判断中枢结束的小尾巴点,小尾巴延申可能延长中枢
#但是线段的修正不会影响中枢因为可能影响的就是gg dd但是计算gg dd是计算到倒数第三个不包括刚修正的线段
if is_extend_line and len(df_dr_line)==3 and zs_end_n_pre>zs_first_n_pre:
dot_last_n=df_dr_line.index[-1] #最后一个线段dot
dot_last_type=df_dr_line.at[dot_last_n,'line']
dot_last_high=df_dr_line.at[dot_last_n,'high']
dot_last_low=df_dr_line.at[dot_last_n,'low']
if (dot_last_type=='top' and dot_last_high>zd) or (dot_last_type=='bottom' and dot_last_low<zg):
#把结束点放到上一个结束点去
zs_end_n_pre=0 if zs_no==0 else df_dr[df_dr.zs_no==zs_no].index[-1]
#print('线段延申导致中枢延申,取消上次结束点,继续延申下去')
#寻找新的中枢
if len(df_dr_line)>=6 and zs_first_n_pre<=zs_end_n_pre:
dot1_k_n=df_dr_line.index[-6] #可能的前导头
dot2_k_n=df_dr_line.index[-5] #可能的中枢第一个点
dot3_k_n=df_dr_line.index[-4]
dot4_k_n=df_dr_line.index[-3]
dot5_k_n=df_dr_line.index[-2]
dot6_k_n=df_dr_line.index[-1] #最后一个线段dot
dot1_high=df_dr_line.at[dot1_k_n,'high']
dot2_high=df_dr_line.at[dot2_k_n,'high']
dot3_high=df_dr_line.at[dot3_k_n,'high']
dot4_high=df_dr_line.at[dot4_k_n,'high']
dot5_high=df_dr_line.at[dot5_k_n,'high']
dot6_high=df_dr_line.at[dot6_k_n,'high']
dot1_low=df_dr_line.at[dot1_k_n,'low']
dot2_low=df_dr_line.at[dot2_k_n,'low']
dot3_low=df_dr_line.at[dot3_k_n,'low']
dot4_low=df_dr_line.at[dot4_k_n,'low']
dot5_low=df_dr_line.at[dot5_k_n,'low']
dot6_low=df_dr_line.at[dot6_k_n,'low']
if(dot1_k_n>=zs_end_n_pre):
#往前找三个点,如果不在中枢里,则判断是否是中枢的头部
start_direction='down' if df_dr_line.at[dot1_k_n,'line']=='top' else 'up' #前导点是top则是下降方向
if start_direction=='down':
if min(dot3_high,dot5_high)>max(dot2_low,dot4_low) and dot1_high>max(dot3_high,dot5_high) and dot6_high<min(dot3_high,dot5_high):
zs_first_n_pre=dot2_k_n #dot1是前导点这个点是中枢第一个点
zg=min(dot3_high,dot5_high)
zd=max(dot2_low,dot4_low)
gg=max(dot3_high,dot5_high)
dd=min(dot2_low,dot4_low)
zs_no+=1
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zs_no']=zs_no
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zg']=zg
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zd']=zd
#print('新中枢确立',zd,zg,zs_first_n_pre)
elif start_direction=='up':
if min(dot2_high,dot4_high)>max(dot3_low,dot5_low) and dot1_low<min(dot3_low,dot5_low) and dot6_low>max(dot3_low,dot5_low):
zs_first_n_pre=dot2_k_n #dot1是前导点这个点是中枢第一个点
zg=min(dot2_high,dot4_high)
zd=max(dot3_low,dot5_low)
gg=max(dot2_high,dot4_high)
dd=min(dot3_low,dot5_low)
zs_no+=1
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zs_no']=zs_no
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zg']=zg
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=dot5_k_n) & (df_dr.line!=''),'zd']=zd
#print('新中枢确立',zd,zg,zs_first_n_pre)
#在中枢里则看是否生长
elif len(df_dr_line)>5 and zs_first_n_pre>zs_end_n_pre:
dot_last_n=df_dr_line.index[-1] #最后一个线段dot
dot_last_type=df_dr_line.at[dot_last_n,'line']
dot_last_high=df_dr_line.at[dot_last_n,'high']
dot_last_low=df_dr_line.at[dot_last_n,'low']
dot_last3_n=df_dr_line.index[-3] #倒数第三个线段dot
dot_last3_type=df_dr_line.at[dot_last3_n,'line']
dot_last3_high=df_dr_line.at[dot_last3_n,'high']
dot_last3_low=df_dr_line.at[dot_last3_n,'low']
#刷新gg dd只算到倒数第三个确认中枢时正好为中枢结束点
if dot_last3_type=='top':
gg=max(gg,dot_last3_high)
elif dot_last3_type=='bottom':
dd=min(dd,dot_last3_low)
dot_last_trade_time=df_dr_line.at[dot_last_n,'trade_time']
dot_last_close=df_dr_line.at[dot_last_n,'close']
if (dot_last_type=='top' and dot_last_high<zd) or (dot_last_type=='bottom' and dot_last_low>zg):
#中枢完成(这时肯定已经两个点脱离,没有走回去),保存,退出,往后面继续找
# /\ -------------
# / or -------------
# ------------- \
# ------------- \/
#print('中枢完成',zg,zd,df_dr_line.index[-3])
is_confirm_zs=True
zs_end_n_pre=df_dr_line.index[-3] #中枢结束点是倒数第三个dot结束点不是后导点而开始点是前导点计算时前后衔接方便
end_direction='down' if dot_last_type=='top' else 'up' #小尾巴是top则是下降方向
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zs_no']=zs_no
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zg']=zg
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zd']=zd
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'gg']=gg
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'dd']=dd
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zs_direction']=start_direction+end_direction
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zs_confirm_time']=dot_last_trade_time
df_dr.at[(df_dr.index>=zs_first_n_pre) & (df_dr.index<=zs_end_n_pre) & (df_dr.line!=''),'zs_confirm_price']=dot_last_close
return df_dr