快速索引

  • 加载数据
  • 数据加载过程和调用关系
  • 辨别顶底分型并在K线图中进行标识

加载数据

    bars = database_manager.load_bar_data("IF888",exchange = Exchange.CFFEX,interval=Interval.MINUTE,start=datetime(2019, 1, 1),end=datetime(2019, 1, 17))

从本地数据库(vnpy运行目录下的.db数据库文件)读取沪深300主力指数合约分钟线数据,存入bars,bars为list,每个元素均为BarData数据结构。

 widget = NewChartWidget()widget.add_plot("candle", hide_x_axis=True)widget.add_plot("volume", maximum_height=200)widget.add_item(CandleItem, "candle", "candle")widget.add_item(VolumeItem, "volume", "volume")widget.add_item(TopBottomPattern, "topbottom", "candle")widget.add_cursor()n = len(bars)history = bars[:n]new_data = bars[n:]widget.update_history(history)

NewChartWidget继承了Widget类,此处与Widget类的区别可忽略。add_plot方法是在窗体中创建绘图区,add_item方法是向指定绘图区中加入ChartItem对象。例如,widget.add_item(CandleItem, “candle”, “candle”) 即是将一个名为candle的CandleItem对象,加载到名为candle的绘图区中。add_item的入参依次为,ChartItem类,对象名称item_name, 绘图区名称plot_name。

上例中,history即为bars的全部数据(1/1至1/17期货指数分钟线)。

widget.update_history(history) 为加载数据的语句,接下来看具体的加载过程和调用关系。

数据加载过程和调用关系

查看Widget类的update_history方法:

    def update_history(self, history: List[BarData]) -> None:"""Update a list of bar data."""self._manager.update_history(history)for item in self._items.values():item.update_history(history)self._update_plot_limits()self.move_to_right()

入参为BarData组成的list,本例中即为history(全部数据)。该方法实际上调用了self._manager的update_history方法。self._manager是Widget类内部定义的BarManager对象:

self._manager: BarManager = BarManager()

继续查看BarManager类的update_history方法:

    def update_history(self, history: List[BarData]) -> None:"""Update a list of bar data."""# Put all new bars into dictfor bar in history:self._bars[bar.datetime] = bar# Sort bars dict according to bar.datetimeself._bars = dict(sorted(self._bars.items(), key=lambda tp: tp[0]))# Update map relationishipix_list = range(len(self._bars))dt_list = self._bars.keys()self._datetime_index_map = dict(zip(dt_list, ix_list))self._index_datetime_map = dict(zip(ix_list, dt_list))# Clear data range cacheself._clear_cache()

入参为history,仍为BarData组成的list。

注意self._bars为BarManager类内部定义的字典,其键为K线的时间戳(datatime格式),值为该时间对应的K先BarData。

上段代码中的for循环,即通过遍历history(全部BarData数据),建立_bars字典。ix_list为通过range(len(self._bars))建立的正数list,其值为[0, 1, 2, … , n-1],其中n为history中BarData数据的个数,即K线的根数。dt_list取了self._bars的键值,也就是时间戳创建list。

有了ix_list和dt_list后,通过dict(zip())函数创建了ix表和dt表的映射字典。其中,_datetime_index_map的键是时间,值是ix,_index_datetime_map的键是ix,值是时间。

这样一来即将一组K线数据(BarData构成的list)的特征值提取出来,按每根K线的时间戳为序,依次对应0, 1, 2, 3 …的正数ix下标,该下标将用作后续PyQt绘图的水平坐标。

BarManager的update_history调用完毕后,widget的update_history继续通过一个for循环,调用了_items.values()中各项的update_history方法:

for item in self._items.values():item.update_history(history)

其中self._items是widget类内部的一个字典属性:

self._items: Dict[str, ChartItem] = {}

可以看到该字典的是ChartItem的键-值映射,其.values()即为所有当前加载的ChartItem类。则上述for方法调用的是各个ChartItem类下的update_history方法。

以CandleItem为例,查看CandleItem.update_history(history):

    def update_history(self, history: List[BarData]) -> BarData:"""Update a list of bar data."""self._bar_picutures.clear()bars = self._manager.get_all_bars()for ix, bar in enumerate(bars):bar_picture = self._draw_bar_picture(ix, bar)self._bar_picutures[ix] = bar_pictureself.update()

可以看到,入参history(全部数据)传入CandleItem的update_history方法后,程序实际使用的数据并非history,而是通过self._manager.get_all_bars()方法重新获取了当前全部的BarData数据list。由于BarManager的update_history的调用在先,此处可以确保get_all_bars()获取的是全部的数据。

获取全部数据bars后,通过遍历bars,调用_draw_bar_picture()方法,完成绘图。_draw_bar_picture()的入参分别问ix和bar,即每一根K线的ix坐标值和实际的BarData数据。

总结,widget.update_history() 调用 >> BarManager.update_history() 调用 >> 各个ChartItem类的update_history() 方法 >> 逐根K线绘图,调用_draw_bar_picture()方法。

辨别顶底分型并在K线图中进行标识

目标:在给定的数据集中,辨别并标识缠论定义的顶底分型结构(顶分型:三根相邻不包含的K线,其中中间一根K线的高点为三者高点之最高,低点为三者低点之最高;底分型:三根相邻不包含的K线,其中中间一根K线的低点为三者低点之最低,高点为三者高点之最低)。

思路:定义TopBottomPattern类,继承CandleItem类,通过改写_draw_bar_picture()方法,获取当前K先左右相邻的两根K线。对三根K线进行处理,判断是否满足顶底分型条件,满足则画一个矩形将这三根K先框住。

实现:首先,定义TopBottomPattern类,并重写_draw_bar_picture()以获取相邻三根K线:

class TopBottomPattern(CandleItem):""""""def __init__(self, manager: BarManager):""""""super().__init__(manager)self.blue_pen: QtGui.QPen = pg.mkPen(color=(0, 255, 255), width=3)self.pink_pen: QtGui.QPen = pg.mkPen(color=(255, 20, 147), width=3)self.TopPattern = Falseself.BottomPattern = False

blue_pen用于标记底分型;pink_pen用于标记顶分型。

获取相邻三根K线:

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:""""""bars = []n = self._manager.get_count()if ix < 1 or ix > n-2:passelse:last_bar = self._manager.get_bar(ix - 1)this_bar = self._manager.get_bar(ix)next_bar = self._manager.get_bar(ix + 1)bars = [last_bar, this_bar, next_bar]

ix = 0 或 n-1,即第一根和最后一根K线,没有左或右相邻K线,不做处理。其他情况,通过_manager.get_bar()方法获得相邻三根K线,并建立bars储存为list。

判断相邻三根K先是否存在包含关系:

    def not_included(self, bars: List[BarData]):return (((bars[1].high_price > bars[0].high_price andbars[1].low_price > bars[0].low_price) or(bars[1].high_price < bars[0].high_price andbars[1].low_price < bars[0].low_price))and((bars[2].high_price > bars[1].high_price andbars[2].low_price > bars[1].low_price) or(bars[2].high_price < bars[1].high_price andbars[2].low_price < bars[1].low_price)))

左中右三根K线分别为bars[0], bars[1] 和 bars[2],左K线和中K线不存在包含关系,同时中K线和右K线不存在包含关系,则三根K线不存在包含关系,not_included()方法返回True。

判断顶底分型:

   def identify_pattern(self, bars: List[BarData]):if (self.not_included(bars) and(bars[1].high_price > bars[0].high_price and bars[1].high_price > bars[2].high_price)and(bars[1].low_price > bars[0].low_price and bars[1].low_price > bars[2].low_price)):#print("Top Pattern Identified")self.TopPattern = Trueelse:passif (self.not_included(bars) and(bars[1].high_price < bars[0].high_price and bars[1].high_price < bars[2].high_price)and(bars[1].low_price < bars[0].low_price and bars[1].low_price < bars[2].low_price)):#print("Bottom Pattern Identified")self.BottomPattern = Trueelse:pass

顶分型判断为真的三个条件:1)三根K线不存在包含关系;2)中K线的最高价为三根K线最高价之最高;3)中K线的最低价为三根K线最低价之最高。同理,底分型判断为真的三个条件:1)三根K线不存在包含关系;2)中K线的最低价为三根K线最低价之最低;3)中K线的最高价为三根K线最高价之最低。

绘图:

   if len(bars) != 3:passelse:self.TopPattern = Falseself.BottomPattern = Falseself.identify_pattern(bars)if (self.TopPattern == True):yLower = min(bars[0].low_price, bars[2].low_price)rect = QtCore.QRectF(ix-1 - BAR_WIDTH,yLower,BAR_WIDTH * 2 * 3.5,bars[1].high_price - yLower)painter.setPen(self.pink_pen)painter.drawRect(rect)if (self.BottomPattern == True):yUpper = max(bars[0].high_price, bars[2].high_price)rect = QtCore.QRectF(ix-1 - BAR_WIDTH,bars[1].low_price,BAR_WIDTH * 2 * 3.5,yUpper - bars[1].low_price)painter.setPen(self.blue_pen)painter.drawRect(rect)# Finishpainter.end()return picture

代码比较容易理解,注意的是QtCore.QtRectF()方法绘制矩形的四个入参,分别为:1)矩形左下角点水平坐标;2)矩形左下角点纵向坐标;3)矩形宽;4)矩形高。

至此,每当TopBottomPattern的update_history()方法被调用时(实际为父类的对应方法被调用),_draw_bar_picture()将获取当前K线及与其相邻的两根K线,若这三根K线满足顶底分型,则绘制矩形框将此三根K线标识出来,顶分型为粉色框,底分型为蓝色框。运行结果如下:


这是初步的工作,上图中可以看到,有的顶分型和底分型重合了,这种情况在缠论的定义下是不允许发生的。接下来将进一步完善,待续。

vnpy+缠论测试笔记1: chart绘图标识顶底分型相关推荐

  1. 通达信缠论顶底分型选股公式(一笔优化版)

    在前文<缠论底分型选股公式,处理了包含关系>中介绍了缠论底分型,并编写了选股公式.底分型条件比较容易满足,因此产生的信号比较多.有热心网友提出,可以用顶底分型构成一笔过滤信号. 缠论一笔的 ...

  2. 《缠中说禅108课》82:分型结构的心理因素

    走势反映的是人的贪嗔痴疑慢,如果你能通过走势当下的呈现,而观照其中参与的心理呈现,就等于看穿了市场参与者的内心.心理,不是虚无飘渺的,最终必然要留下痕迹,也就是市场走势本身.而一些具有自相似性的结构, ...

  3. 《缠中说禅108课》62:分型、笔与线段

    在宾馆里闲着等着 10 点开始的腐败,半个小时,找个面首来面首有点时间紧张,还不如给各位写个主贴,来个课程,耗费一下各位周末腐败的时间. 瞧了一下,有位叫石猴的网友写了帖子来解释什么是线段,他的理解还 ...

  4. 软件质量保证与测试笔记——江湖救急版

    软件质量保证与测试笔记--江湖救急版 Powered by DZY 以下部分图片来源于老师课件,仅供学习交流使用,侵权致删! Ch1 软件质量与测试概念 软件质量的定义 软件质量是"反映实体 ...

  5. VC学习笔记:简单绘图

    VC学习笔记:简单绘图 SkySeraph Oct.29th 2009  HQU Email-zgzhaobo@gmail.com  QQ-452728574 Latest Modified Date ...

  6. RGMII_PHY测试笔记1 基于开发板MiS603-X25

    RGMII_PHY测试笔记1 基于开发板MiS603-X25 作者:汤金元 日期:20150817 公司:南京米联电子科技有限公司 博客:http://blog.chinaaet.com/detail ...

  7. 阿里p7大手子测试笔记:一线互联网大厂面试问题吃透,巧过面试关

    前言 金九银十刚过去,有一部分朋友在这期间肯定经历了一番大厂面试的洗礼,不知道大家是经受住了考验如愿以偿了,还是折戟沉沙无功而返呢? 身边已经有技术大佬顺利通过了阿里P6/P7的面试,在30岁之前成功 ...

  8. [在线挑战]【i春秋】渗透测试入门 —— 渗透测试笔记 --转

    [i春秋]渗透测试入门 -- 渗透测试笔记,原文 0x00 前言 本题算是一道较为综合的渗透题,要求对两个服务器系统进行渗透,第一个是基于齐博 CMS 的信息资讯平台 http://www.test. ...

  9. matlab学习笔记9 高级绘图命令_2 图形的高级控制_视点控制和图形旋转_色图和颜色映像_光照和着色

    一起来学matlab-matlab学习笔记9 高级绘图命令_2 图形的高级控制_视点控制和图形旋转_色图和颜色映像_光照和着色 觉得有用的话,欢迎一起讨论相互学习~ 参考书籍 <matlab 程 ...

最新文章

  1. Linux下Mysql的基本操作
  2. redis mysql 解决超卖_Redis 分布式锁解决超卖问题
  3. 二次创业成功人士的19个经验与教训
  4. Servlet的快速入门以及执行原理
  5. POJ 3181 Dollar Dayz DP
  6. 【Breadth-first Search 】103. Binary Tree Zigzag Level Order Traversal
  7. 使用 MacBook Pro 的硬件重置功能解决故障
  8. 洛谷 P2032 扫描
  9. Java:Stream三部曲(三):Stream流处理器
  10. 常见的影视cms及安装环境说明
  11. LC-3指令集 指令/状态码介绍
  12. 软件测试 - 功能测试Ⅱ
  13. JavaWeb框架(一):Web入门,Http的请求和响应,https介绍,Web实战自定义服务器
  14. 哆啦A梦的超级计算机,哆啦A梦的体内究竟有什么?其实你真的低估了这个蓝胖子...
  15. C/C++/SFML编写俄罗斯方块小程序 附代码和下载链接
  16. 微信小程序-实现删除指定列表项
  17. LuBan鲁班图片压缩工具
  18. liunx usb摄像头使用
  19. 传世单机 GM命令 查看所有GM命令 自定义游戏命令
  20. sofasofa—公共自行车使用量预测—参数调整、优化结果

热门文章

  1. LK光流金字塔算法原理及C++实现
  2. postgresql索引_PostgreSQL中的索引— 8(RUM)
  3. [转]国内地图服务可用性比较
  4. python中横向制表符_python中制表符是什么意思
  5. 数学物理方法的matlab解法及可视化(一)复变函数图形
  6. RTS/CTS机制以及RTS threshold
  7. 西班牙足球联赛体系介绍
  8. 将png图片背景色置为透明
  9. Java 文件输入输出流 实验题
  10. LeetCode 796. 旋转字符串