因为缠论文章都是博客形式,并无很规范的写作格式与篇章结构,自己理解起来着实不易,每次读都感悟不同,程序也是改了又改。
下文对于缠论的理解以及程序的处理都是个人粗浅的理解,还望对缠论有很深造诣的前辈指出不足之处。
详情见研究模块!
(代码中发现些许问题,因为分享之后的研究无法替换,所以将修改后的代码我放在评论区了。)
因为缠论文章都是博客形式,并无很规范的写作格式与篇章结构,自己理解起来着实不易,每次读都感悟不同,程序也是改了又改。
下文对于缠论的理解以及程序的处理都是个人粗浅的理解,还望对缠论有很深造诣的前辈指出不足之处。
研究模块中实现了“缠论”的分型,笔,线段。
开始本想实现维克多交易法则中的维克多交易法则,维克多123法则和2B法则是判断趋势变动的最基本法则。思考如何实现对于趋势"图"的识别,想到了缠论中关于分型,笔以及线段的描述。
其中对简单的1-2-3准则的进行简单总结:
趋势线被突破。价格穿越绘制的趋势线
上升趋势不再创新高,或下降趋势不再创新低。
在下降趋势中,价格向上穿越先前的短期反弹高点;或在上升趋势中,价格向下穿越先前的短期回档低点。
示意图如下所示:
维克多交易规则具体的学习还是要到《专业投机原理》一书中深刻领会,在这里仅仅是一个概括。
我们可以将维克多的趋势看为缠论的一个线段,维克多的趋势破坏即可认为是缠论中的线段被破坏,如下图中9所示,触发交易信号。下面介绍一下缠论之分型、笔、线段。
下面的定义与图,都适合任何周期的 K 线图。先看图中的第 1、2,图中的小线段代表的是 K 线,这里不分阳线阴线,只看 K 线高低点。
像图1这种,第二K线高点是相邻三K线高点中最高的,而低点也是相邻三K线低点中最高的,定义其顶分型;图2这种第二K线低点是相邻三K线低点中最低的,而高点也是相邻三K线高点中最低的,定义为底分型。看不明白定义的,看图就明白了。
顶分型的最高点叫该分型的顶,底分型的最低点叫该分型的底,由于顶分型的底和底分型的顶是没有意义的,所以顶分型的顶和底分型的底就可以简称为顶和低。也就是说,当我们以后说顶和底时,就分别是说顶分型的顶和底分型的底。
两个相邻的顶和底之间构成一笔,所谓笔,就是顶和底之间的其他波动,都可以忽略不算,但注意,一定是相邻的顶和底,隔了几个就不是了。而所谓的线段,就是至少由三笔组成。但这里有一个细微的地方要分清楚,因为结合律是必须遵守的,像图3这种,顶和底之间必须共用一个K线,这就违反结合律了,所以这不算一笔,而图4,就光是顶和底了,中间没有其他K线,一般来说,也最好不算一笔,而图5,是一笔的最基本的图形,顶和底之间还有一根K线。在实际分析中,都必须要求顶和底之间都至少有一K线当成一笔的最基本要求。
当然,实际图形里,有些复杂的关系会出现,就是相邻两K线可以出现如图6这种包含关系,也就是一K线的高低点全在另一K线的范围里,这种情况下,可以这样处理,在向上时,把两K线的最高点当高点,而两K线低点中的较高者当成低点,这样就把两K线合并成一新的K线;反之,当向下时,把两K线的最低点当低点,而两K线高点中的较低者当成高点,这样就把两K线合并成一新的K线。经过这样的处理,所有K线图都可以处理成没有包含关系的图形。在我的处理中,将下方这些形式都进行了包含关系的处理。
而图7,就给出了经过以上处理,没有包含关系的图形中,三相邻K线之间可能组合的一个完全分类,其中的二、四,就是分别是顶分型和底分型,一可以叫上升K线,三可以叫下降K线。所以,上升的一笔,由结合律,就一定是底分型+上升K线+顶分型;下降的一笔,就是顶分型+下降K线+底分型。注意,这里的上升、下降K线,不一定都是3根,可以无数根,只要一直保持这定义就可以。当然,简单的,也可以是1、2根,这只要不违反结合律和定义就可以。
至于图8,就是线段的最基本形态,而图9,就是线段破坏,也就是两线段组合的其中一种形态。
有人可能要说,这怎么有点像波浪理论,缠论作者认为这不奇怪,作者认为缠论的理论可以严格地推论出波浪理论的所有结论,而且还可以指出他理论的所有不足,波浪理论和缠论的理论一点可比性都没有。不仅是波浪理论,所有关于股市的理论,只要是关系到“图形”的,缠论的理论都可以严格推论,因为缠论的理论是关于走势图形最基础的理论,谁都逃不掉。
缠论中根据可操作性定义了不同显微级别的,对于中枢和走势类型,也就有了关于不同级别的图形的研究。进而,就有了不同级别显微镜的比喻。而实际上,一般能得到的图,最多也就是 1 分钟级别的,因此,可以从这个图入手。当然,也可以从 5 分钟,甚至更高入手,但这就等于把显微镜倍数弄小了,看到的东西自然没有 1 分钟的多且清楚。再次强调,什么级别的图和什么级别的中枢没有任何必然关系,走势类型以及中枢就如同显微镜下的观察物,是客观存在的,其存在性由上面所说最原始的递归定义保证,而级别的图,就如同显微镜,不同倍数的看这客观的图就看到不同的精细程度,如此而已。所以,不能把显微镜和显微镜观察的东西混在一起了。
如果我们首先确立了显微镜的倍数,也就是说,例如我们把 1 分钟图作为最基本的图,那么就可以开始定义上一课程说的分型、笔、线段等等。有了线段,就可以定义 1 分钟的中枢,然后就是 1 分钟的走势类型,然后按照递归的方法,可以逐步定义 5 分钟、30 分钟、日、周、月、季度、年的中枢和走势类型。而有的人总是不明白,例如总是在问,5 分钟图怎么看,30 分钟怎么看,其实,如果你选择 5 分钟或 30 分钟为最基本的图,那么和 1 分钟的看法一样,只不过你的显微镜倍数比较小,看起来比较粗糙而已。而如果你已经选择 1 分钟作为最基本的图,也就是选定了 1 分钟这个倍数的显微镜,那么看 1 分钟图就可以。
所以程序中也定义了换算不同分钟级别的函数get_Fnk,根据需求可获得不同级别的分钟数据。
另外,鄙人对于分型的寻找,如果一个底分型之后遇到一个顶分型,其中底分型的底高于顶分型的顶,如下图中一所示,则上一个底分型不被确立,跳过该顶分型,接着寻找一个下一个更低的底分型或者顶高于该底分型的顶分型。(话着实有些绕,抱歉抱歉!看图您就明白了。)
缠论具体细则可参考《教你炒股票-缠中说禅》,其中关于“分型,笔,线段”的内容可参考第62-65课的内容。
用缠论分型处理之后的图形如下,符合维克多上升趋势:
因为思绪混乱,程序更改多次,看着也许会有些混乱;
判断包含关系、找寻顶底的程序没有写成函数;
因为要实现维克多交易规则,程序还要判断准则还需更改,所以暂时并未没有实现,下一步计划实现维克多1-2-3与维克多2B交易规则。
def get_Fnk(security, start, end, n=5):''' 获得k分钟k线函数 '''import pandas as pdk_data = get_price(security, start_date=start, end_date=end, frequency='minute', fields=['open','close','high', 'low'])# 去除9:00与13:00的数据for i in range(len(k_data)/242):team = list(k_data.index)x = [s.strftime("%Y-%m-%d %H:%M:%S") for s in team]y = filter(lambda t : "09:31:00" in t, x)k_data= k_data.drop(k_data.index[x.index(y[0])])del x[x.index(y[0])]y = filter(lambda t : "13:01:00" in t, x)k_data= k_data.drop(k_data.index[x.index(y[0])])del x[x.index(y[0])]# 计算n分钟K线Fnk = pd.DataFrame()for i in xrange(n,len(k_data)+1,n):temp = k_data[i-n : i]temp_open = temp.open[0]temp_high = max(temp.high)temp_low = min(temp.low)temp_k = temp[-1:]temp_k.open = temp_opentemp_k.high = temp_hightemp_k.low = temp_lowFnk = pd.concat([Fnk,temp_k],axis = 0)return Fnkdef middle_num(k_data):# 鸡肋函数,完全的强迫症所为,只为下面画图时candle图中折线时好看而已 - -!# k_data 为DataFrame格式plot_data=[]for i in xrange(len(k_data)):temp_y = (k_data.high[i]+k_data.low[i])/2.0plot_data.append(temp_y)return plot_data
import numpy as npimport pandas as pdimport matplotlib as mplimport matplotlib.pyplot as pltimport matplotlib.finance as mpfk_data = get_Fnk(n=5,security = '000001.XSHE',start = '2015-12-02',end = '2015-12-05')## 判断包含关系after_fenxing = pd.DataFrame()temp_data = k_data[:1]zoushi = [3] # 3-持平 4-向下 5-向上for i in xrange(len(k_data)):case1_1 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] < k_data.low[i]# 第1根包含第2根case1_2 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] == k_data.low[i]# 第1根包含第2根case1_3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] < k_data.low[i]# 第1根包含第2根case2_1 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] > k_data.low[i] # 第2根包含第1根case2_2 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] == k_data.low[i] # 第2根包含第1根case2_3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] > k_data.low[i] # 第2根包含第1根case3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] == k_data.low[i] # 第1根等于第2根case4 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] > k_data.low[i] # 向下趋势case5 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] < k_data.low[i] # 向上趋势if case1_1 or case1_2 or case1_3:if zoushi[-1] == 4:temp_data.high[-1] = k_data.high[i]else:temp_data.low[-1] = k_data.low[i]elif case2_1 or case2_2 or case2_3:temp_temp = temp_data[-1:]temp_data = k_data[i:i+1]if zoushi[-1] == 4:temp_data.high[-1] = temp_temp.high[0]else:temp_data.low[-1] = temp_temp.low[0]elif case3:zoushi.append(3)passelif case4:zoushi.append(4)after_fenxing = pd.concat([after_fenxing,temp_data],axis = 0)temp_data = k_data[i:i+1]elif case5:zoushi.append(5)after_fenxing = pd.concat([after_fenxing,temp_data],axis = 0)temp_data = k_data[i:i+1]# after_fenxing.head()
/opt/conda/envs/python2/lib/python2.7/site-packages/pandas/core/generic.py:2177: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the the c*eats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy self[name] = value /opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/interactiveshell.py:3066: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the the c*eats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy exec(code_obj, self.user_global_ns, self.user_ns)
## 因为使用candlestick2函数,要求输入open、close、high、low。为了美观,处理k线的最大最小值、开盘收盘价,之后k线不显示影线。for i in xrange(len(after_fenxing)):if after_fenxing.open[i] > after_fenxing.close[i]:after_fenxing.open[i] = after_fenxing.high[i]after_fenxing.close[i] = after_fenxing.low[i]else:after_fenxing.open[i] = after_fenxing.low[i]after_fenxing.close[i] = after_fenxing.high[i]## 画出k线图stock_middle_num = middle_num(after_fenxing)fig, ax = plt.subplots(figsize = (50,20))fig.subplots_adjust(bottom=0.2)mpf.candlestick2(ax, list(after_fenxing.open),list(after_fenxing.close),list(after_fenxing.high),list(after_fenxing.low), width=0.6, colorup='r', colordown='b',alpha=0.75 )plt.grid(True)dates = after_fenxing.indexax.set_xticklabels(dates) # Label x-axis with dates# ax.autoscale_view()plt.plot(stock_middle_num,'k', lw=1)plt.plot(stock_middle_num,'ko')plt.setp(plt.gca().get_xticklabels(), rotation=30)
/opt/conda/envs/python2/lib/python2.7/site-packages/matplotlib/finance.py:1306: MatplotlibDeprecationWarning: This function has been deprecated in 1.4 in f*or of `candlestick2_ochl`, which maintains the original argument order, or `candlestick2_ohlc`, which uses the open-high-low-close order. This function will be removed in 1.5 mplDeprecation)
[None, None, None, None, None, None, None, None, None, None]
/opt/conda/envs/python2/lib/python2.7/site-packages/matplotlib/collections.py:590: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison if self._edgecolors == str('face'):
## 找出顶和底temp_num = 0 #上一个顶或底的位置temp_high = 0 #上一个顶的high值temp_low = 0 #上一个底的low值temp_type = 0 # 上一个记录位置的类型i = 1fenxing_type = [] # 记录分型点的类型,1为顶分型,-1为底分型fenxing_time = [] # 记录分型点的时间fenxing_plot = [] # 记录点的数值,为顶分型去high值,为底分型去low值fenxing_data = pd.DataFrame() # 分型点的DataFrame值while (i < len(after_fenxing)-1):case1 = after_fenxing.high[i-1]<after_fenxing.high[i] and after_fenxing.high[i]>after_fenxing.high[i+1] #顶分型case2 = after_fenxing.low[i-1]>after_fenxing.low[i] and after_fenxing.low[i]<after_fenxing.low[i+1] #底分型if case1:if temp_type == 1: # 如果上一个分型为顶分型,则进行比较,选取高点更高的分型 if after_fenxing.high[i] <= temp_high:i += 1# continueelse:temp_high = after_fenxing.high[i]temp_num = itemp_type = 1i += 4elif temp_type == 2: # 如果上一个分型为底分型,则记录上一个分型,用当前分型与后面的分型比较,选取同向更极端的分型if temp_low >= after_fenxing.high[i]: # 如果上一个底分型的底比当前顶分型的顶高,则跳过当前顶分型。i += 1else:fenxing_type.append(-1)fenxing_time.append(after_fenxing.index[temp_num].strftime("%Y-%m-%d %H:%M:%S"))fenxing_data = pd.concat([fenxing_data,after_fenxing[temp_num:temp_num+1]],axis = 0)fenxing_plot.append(after_fenxing.high[i])temp_high = after_fenxing.high[i]temp_num = itemp_type = 1i += 4else:temp_high = after_fenxing.high[i]temp_num = itemp_type = 1i += 4elif case2:if temp_type == 2: # 如果上一个分型为底分型,则进行比较,选取低点更低的分型 if after_fenxing.low[i] >= temp_low:i += 1# continueelse:temp_low = after_fenxing.low[i]temp_num = itemp_type = 2i += 4elif temp_type == 1: # 如果上一个分型为顶分型,则记录上一个分型,用当前分型与后面的分型比较,选取同向更极端的分型if temp_high <= after_fenxing.low[i]: # 如果上一个顶分型的底比当前底分型的底低,则跳过当前底分型。i += 1else:fenxing_type.append(1)fenxing_time.append(after_fenxing.index[temp_num].strftime("%Y-%m-%d %H:%M:%S"))fenxing_data = pd.concat([fenxing_data,after_fenxing[temp_num:temp_num+1]],axis = 0)fenxing_plot.append(after_fenxing.low[i])temp_low = after_fenxing.low[i]temp_num = itemp_type = 2i += 4else:temp_low = after_fenxing.low[i]temp_num = itemp_type = 2i += 4else:i += 1
print fenxing_typeprint fenxing_timeprint fenxing_plotfenxing_data
[-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1] ['2015-12-02 09:55:00', '2015-12-02 10:35:00', '2015-12-02 11:20:00', '2015-12-02 13:35:00', '2015-12-02 14:05:00', '2015-12-02 14:30:00', '2015-12-03 09:50:00', '2015-12-03 11:05:00', '2015-12-03 13:30:00', '2015-12-03 14:30:00', '2015-12-04 11:20:00', '2015-12-04 13:25:00'] [12.35, 11.949999999999999, 12.119999999999999, 12.109999999999999, 12.59, 12.25, 12.75, 12.43, 12.699999999999999, 12.26, 12.300000000000001, 12.09]
open | close | high | low | |
---|---|---|---|---|
2015-12-02 09:55:00 | 11.70 | 11.74 | 11.74 | 11.70 |
2015-12-02 10:35:00 | 12.23 | 12.35 | 12.35 | 12.23 |
2015-12-02 11:20:00 | 11.95 | 12.00 | 12.00 | 11.95 |
2015-12-02 13:35:00 | 12.12 | 12.09 | 12.12 | 12.09 |
2015-12-02 14:05:00 | 12.11 | 12.15 | 12.15 | 12.11 |
2015-12-02 14:30:00 | 12.59 | 12.47 | 12.59 | 12.47 |
2015-12-03 09:50:00 | 12.33 | 12.25 | 12.33 | 12.25 |
2015-12-03 11:05:00 | 12.66 | 12.75 | 12.75 | 12.66 |
2015-12-03 13:30:00 | 12.43 | 12.50 | 12.50 | 12.43 |
2015-12-03 14:30:00 | 12.58 | 12.70 | 12.70 | 12.58 |
2015-12-04 11:20:00 | 12.15 | 12.19 | 12.19 | 12.15 |
2015-12-04 13:25:00 | 12.24 | 12.30 | 12.30 | 12.24 |
下面画出识别分型之后的走势图!
fig, ax = plt.subplots(figsize = (20,5))dates = fenxing_data.indexax.set_xticklabels(dates) # Label x-axis with datesax.autoscale_view()plt.plot(fenxing_plot,'k', lw=1)plt.plot(fenxing_plot,'o')plt.grid(True)plt.setp(plt.gca().get_xticklabels(), rotation=30)
[None, None, None, None, None, None, None, None]
识别完分型的candle图如下:
其中黑框为底分型,黄框为顶分型,椭圆为记录的位置,用以跟之后的k线进行比对。
用缠论处理之后,上图符合维克多交易法则上升趋势:
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...