python股票量化交易(13)---使用pyqt5构建股票交易K线形态

简介: python股票量化交易(13)---使用pyqt5构建股票交易K线形态

talib提供给我们的K线形态


在前面的博文中,我们介绍了talib提供给我们的6种K形态。不过,那只是博主通过讲解一部分,让大家认识如何使用talib区分K线,其实talib提供给我们的K线形态函数一共44个。那么如果通过软件进行标记呢?


其实在众多的股票交易软件中,并不会主动给我们标记K线形态数据,而且K线形态这么多,哪怕程序员记下来恐怕也无能为力。所以,我们需要使用pyqt5设计界面给我们标记K线形态,并提示使用者那种K线预示涨,哪些K线预示跌。


这里,我们首先需要使用python的反射来完成用户的切换,不然通过ifelse语句一句一句去区分调用,完全是重复的代码劳动,得不偿失。具体反射使用以及K线绘图方式如下:

import talib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import mpl_finance as mpf
from matplotlib import gridspec
class KMplCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        plt.rcParams['font.sans-serif'] = ['SimHei']
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        FigureCanvas.__init__(self, self.fig)
        spec = gridspec.GridSpec(4, 1, height_ratios=[3, 1, 1, 1])
        self.ax1 = self.fig.add_subplot(spec[0])
        self.ax2 = self.fig.add_subplot(spec[1])
        self.ax3 = self.fig.add_subplot(spec[2])
        self.ax4 = self.fig.add_subplot(spec[3])
        self.setParent(parent)
        self.k_text = ['十字星', '两只乌鸦', '三只乌鸦', '三内部上涨和下跌', '三线打击',
                       '三外部上涨和下跌', '南方三星', '三个白兵', '弃婴', '大敌当前',
                       '捉腰带线', '脱离', '收盘缺影线', '藏婴吞没', '反击线'
            , '乌云压顶', '蜻蜓十字/T形十字', '吞噬模式', '十字暮星', '暮星',
                       '向上/下跳空并列阳线', '墓碑十字/倒T十字', '锤头', '上吊线', '母子线',
                       '十字孕线', '风高浪大线', '陷阱', '修正陷阱', '家鸽',
                       '三胞胎乌鸦', '颈内线', '倒锤头', '反冲形态', '由较长缺影线决定的反冲形态',
                       '停顿形态', '条形三明治', '探水竿', '跳空并列阴阳线', '插入',
                       '三星', '奇特三河床', '向上跳空的两只乌鸦', '上升/下降跳空三法']
        FigureCanvas.updateGeometry(self)
    def start_staict_plot(self, df, method="CDLDOJISTAR", numb=0):
        self.ax1.clear()
        self.ax2.clear()
        self.ax3.clear()
        self.ax4.clear()
        self.fig.canvas.draw_idle()
        mytalib = talib
        f = getattr(mytalib, method)
        df['date'] = pd.to_datetime(df['date'])
        df['date'] = df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))
        mpf.candlestick2_ochl(self.ax1, df["open"], df["close"], df["high"], df["low"], width=0.6, colorup='r',
                              colordown='green',
                              alpha=1.0)
        df['star'] = f(df['open'].values, df['high'].values, df['low'].values, df['close'].values)
        pattern = df[(df['star'] == 100) | (df['star'] == -100)]
        for key, val in df.items():
            for index, today in pattern.iterrows():
                x_posit = df.index.get_loc(index)
                self.ax1.annotate("{}\n{}".format(self.k_text[numb], today["date"]), xy=(x_posit, today["high"]),
                                  xytext=(0, pattern["close"].mean()), xycoords="data",
                                  fontsize=8, textcoords="offset points",
                                  arrowprops=dict(arrowstyle="simple", color="r"))
        df["SMA5"] = df["close"].rolling(5).mean()
        df["SMA10"] = df["close"].rolling(10).mean()
        df["SMA30"] = df["close"].rolling(30).mean()
        df["SMA60"] = df["close"].rolling(60).mean()
        self.ax1.plot(np.arange(0, len(df)), df['SMA5'], label="5日均线")  # 绘制5日均线
        self.ax1.plot(np.arange(0, len(df)), df['SMA10'], label="10日均线")  # 绘制10日均线
        self.ax1.plot(np.arange(0, len(df)), df['SMA30'], label="30日均线")  # 绘制30日均线
        self.ax1.plot(np.arange(0, len(df)), df['SMA60'], label="60日均线")  # 绘制30日均线
        self.ax1.legend()
        red_pred = np.where(df["close"] > df["open"], df["volume"], 0)
        blue_pred = np.where(df["close"] < df["open"], df["volume"], 0)
        self.ax2.bar(np.arange(0, len(df)), red_pred, facecolor="red")
        self.ax2.bar(np.arange(0, len(df)), blue_pred, facecolor="blue")
        self.ax2.set(ylabel=u"成交量")
        low_list = df["close"].rolling(9, min_periods=1).min()
        high_list = df["high"].rolling(9, min_periods=1).max()
        rsv = (df["close"] - low_list) / (high_list - low_list) * 100
        df["K"] = rsv.ewm(com=2, adjust=False).mean()
        df["D"] = df["K"].ewm(com=2, adjust=False).mean()
        df["J"] = 3 * df["K"] - 2 * df["D"]
        self.ax3.plot(df["date"], df["K"], label="K")
        self.ax3.plot(df["date"], df["D"], label="D")
        self.ax3.plot(df["date"], df["J"], label="J")
        self.ax3.legend()
        self.ax3.set(ylabel=u"KDJ")
        EMA1 = df["close"].ewm(span=12, adjust=False).mean()
        EMA2 = df["close"].ewm(span=26, adjust=False).mean()
        DIF = EMA1 - EMA2
        DEA = DIF.ewm(span=9, adjust=False).mean()
        BAR = 2 * (DIF - DEA)
        red_bar = np.where(BAR > 0, BAR, 0)
        blue_bar = np.where(BAR < 0, BAR, 0)
        self.ax4.plot(np.arange(0, len(df)), DIF)
        self.ax4.plot(np.arange(0, len(df)), DEA)
        self.ax4.bar(np.arange(0, len(df)), red_bar, color="red")
        self.ax4.bar(np.arange(0, len(df)), blue_bar, color="blue")
        self.ax4.set(ylabel=u"MACD")
        self.ax1.xaxis.set_major_locator(ticker.MaxNLocator(9))
        def format_date(x, pos=None):
            if x < 0 or x > len(df['date']) - 1:
                return ''
            return df['date'][int(x)]
        self.ax1.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
        self.ax1.grid(True)
        plt.setp(self.ax1.get_xticklabels(), visible=True)
        plt.setp(self.ax2.get_xticklabels(), visible=False)
        plt.setp(self.ax3.get_xticklabels(), visible=False)
        plt.setp(self.ax4.get_xticklabels(), visible=False)
        plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')


这里,我们通过getattr函数,将talib库赋值给它。然后,只需要通过方法名就可以切换K线形态数据。这里博主为了简便,没有将文本数据单独设置为全局变量,在实际的开发中,还是要将其独立,免得重复copy造成代码混乱。


pyqt5绘制K线图


如上面代码所示,我们不仅仅绘制了K线图,而且还绘制了成交量,KDJ,以及MACD,这里对比起来看某个股票往往更具有参考价值。那么界面的代码如下所示:

class MyFrom(QMainWindow):
    # K线模块
    def init_kTab(self):
        self.grid_k = QGridLayout()
        self.grid_k.setSpacing(5)
        k_text = ['十字星', '两只乌鸦', '三只乌鸦', '三内部上涨和下跌', '三线打击',
                  '三外部上涨和下跌', '南方三星', '三个白兵', '弃婴', '大敌当前',
                  '捉腰带线', '脱离', '收盘缺影线', '藏婴吞没', '反击线'
            , '乌云压顶', '蜻蜓十字/T形十字', '吞噬模式', '十字暮星', '暮星',
                  '向上/下跳空并列阳线', '墓碑十字/倒T十字', '锤头', '上吊线', '母子线',
                  '十字孕线', '风高浪大线', '陷阱', '修正陷阱', '家鸽',
                  '三胞胎乌鸦', '颈内线', '倒锤头', '反冲形态', '由较长缺影线决定的反冲形态',
                  '停顿形态', '条形三明治', '探水竿', '跳空并列阴阳线', '插入',
                  '三星', '奇特三河床', '向上跳空的两只乌鸦', '上升/下降跳空三法']
        self.k_content = ['预示着当前趋势反转', '预示股价下跌', '预示股价下跌', '预示着股价上涨', '预示股价下跌',
                          '预示着股价上涨', '预示下跌趋势反转,股价上升', '预示股价上升', '预示趋势反转,发生在顶部下跌,底部上涨', '预示股价下跌'
            , '收盘价接近最高价,预示价格上涨', '预示价格上涨', '预示着趋势持续', '预示着底部反转', '预示趋势反转'
            , '预示着股价下跌', '预示趋势反转', '预示趋势反转', '预示顶部反转', '预示顶部反转',
                          '趋势持续', '预示底部反转', '处于下跌趋势底部,预示反转', '处于上升趋势的顶部,预示着趋势反转', '预示趋势反转,股价上升',
                          '预示着趋势反转', '预示着趋势反转', '趋势继续', '趋势继续', '预示着趋势反转',
                          '预示价格下跌', '预示着下跌继续', '在下跌趋势底部,预示着趋势反转', '存在跳空缺口', '与反冲形态类似,较长缺影线决定价格的涨跌',
                          '预示着上涨结束', '预示着股价上涨', '预示趋势反转', '上升趋势持续', '预示着趋势持续',
                          '预示着趋势反转', '收盘价不高于第二日收盘价,预示着反转,第二日下影线越长可能性越大', '预示股价下跌', '收盘价高于第一日收盘价,预示股价上升']
        self.K_method = ['CDLDOJISTAR', 'CDL2CROWS', 'CDL3BLACKCROWS', 'CDL3INSIDE', 'CDL3LINESTRIKE',
                         'CDL3OUTSIDE', 'CDL3STARSINSOUTH', 'CDL3WHITESOLDIERS', 'CDLABANDONEDBABY', 'CDLADVANCEBLOCK',
                         'CDLBELTHOLD', 'CDLBREAKAWAY', 'CDLCLOSINGMARUBOZU', 'CDLCONCEALBABYSWALL', 'CDLCOUNTERATTACK',
                         'CDLDARKCLOUDCOVER', 'CDLDRAGONFLYDOJI', 'CDLENGULFING', 'CDLEVENINGDOJISTAR',
                         'CDLEVENINGSTAR',
                         'CDLGAPSIDESIDEWHITE', 'CDLGRAVESTONEDOJI', 'CDLHAMMER', 'CDLHANGINGMAN', 'CDLHARAMI',
                         'CDLHARAMICROSS', 'CDLHIGHWAVE', 'CDLHIKKAKE', 'CDLHIKKAKEMOD', 'CDLHOMINGPIGEON',
                         'CDLIDENTICAL3CROWS', 'CDLINNECK', 'CDLINVERTEDHAMMER', 'CDLKICKING', 'CDLKICKINGBYLENGTH',
                         'CDLSTALLEDPATTERN', 'CDLSTICKSANDWICH', 'CDLTAKURI', 'CDLTASUKIGAP', 'CDLTHRUSTING',
                         'CDLTRISTAR', 'CDLUNIQUE3RIVER', 'CDLUPSIDEGAP2CROWS', 'CDLXSIDEGAP3METHODS']
        self.cb = QComboBox()
        self.cb.addItems(k_text)
        self.cb.currentIndexChanged.connect(self.selectionchange)
        self.cb_label = QLabel("预示着当前趋势反转")
        self.k_label = QLabel("选择K线图的形态:")
        self.grid_k.addWidget(self.k_label, 0, 0, 1, 1)
        self.grid_k.addWidget(self.cb, 0, 2, 1, 2)
        self.grid_k.addWidget(self.cb_label, 0, 5, 1, 5)
        self.kTab2.setLayout(self.grid_k)
        self.kLineThread = KLineThread()
        self.kLineThread.setValue("sh600690")
        self.kLineThread._signal.connect(self.kLineThread_callbacklog)
        self.kLineThread.start()
    def kLineThread_callbacklog(self, df):
        self.df = df
        self.mplK = KMplCanvas(self, width=5, height=4, dpi=100)
        self.mplK.start_staict_plot(df)
        mpl_ntb = NavigationToolbar(self.mplK, self)
        mpl_ntb.setStyleSheet("background-color:white;color:black")
        self.grid_k.addWidget(self.mplK, 2, 0, 13, 12)
        self.grid_k.addWidget(mpl_ntb, 2, 0, 1, 5)
    def selectionchange(self, i):
        self.cb_label.setText(self.k_content[i])
        self.mplK.start_staict_plot(self.df, self.K_method[i], i)


同样的,我们这里也需要通过线程获取K线图的基本数据,具体代码如下所示:

from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal
import pandas as pd
from pandas import DataFrame
class KLineThread(QtCore.QThread):
    _signal = pyqtSignal(DataFrame)
    def __init__(self):
        super(KLineThread, self).__init__()
    def setValue(self, shareNumber):
        self.share_num = shareNumber
    def run(self):
        df = pd.read_excel("海尔智家k.xlsx")
        self._signal.emit(df)


需要注意的是,如上篇博文说的一样,最好是先获取网络数据存储在xlsx中后,在获取详细数据,这样在非交易时间段不会造成延迟。后续,这里我们会通过数据库进行更改,暂时先这里处理。


运行之后,显示效果如下图所示:

在界面中,我们可以通过QComboBox控件进行切换K线图,同时图片也会标记符合K线图的数据,而且文字上面也会提示这种K线图代表什么,意味着什么。这是不是散户最想拥有的K线识别器呢?毕竟一般股票交易软件都需要付费才能这么玩。


软件资源代码下载地址:点击下载

相关文章
|
2月前
|
人工智能 JavaScript API
零基础构建MCP服务器:TypeScript/Python双语言实战指南
作为一名深耕技术领域多年的博主摘星,我深刻感受到了MCP(Model Context Protocol)协议在AI生态系统中的革命性意义。MCP作为Anthropic推出的开放标准,正在重新定义AI应用与外部系统的交互方式,它不仅解决了传统API集成的复杂性问题,更为开发者提供了一个统一、安全、高效的连接框架。在过去几个月的实践中,我发现许多开发者对MCP的概念理解透彻,但在实际动手构建MCP服务器时却遇到了各种技术壁垒。从环境配置的细节问题到SDK API的深度理解,从第一个Hello World程序的调试到生产环境的部署优化,每一个环节都可能成为初学者的绊脚石。因此,我决定撰写这篇全面的实
468 67
零基础构建MCP服务器:TypeScript/Python双语言实战指南
|
2月前
|
机器学习/深度学习 算法 量子技术
GQNN框架:让Python开发者轻松构建量子神经网络
为降低量子神经网络的研发门槛并提升其实用性,本文介绍一个名为GQNN(Generalized Quantum Neural Network)的Python开发框架。
52 4
GQNN框架:让Python开发者轻松构建量子神经网络
|
26天前
|
人工智能 自然语言处理 安全
Python构建MCP服务器:从工具封装到AI集成的全流程实践
MCP协议为AI提供标准化工具调用接口,助力模型高效操作现实世界。
297 1
|
3月前
|
数据采集 数据可视化 JavaScript
用Python采集CBC新闻:如何借助海外代理IP构建稳定采集方案
本文介绍了如何利用Python技术栈结合海外代理IP采集加拿大CBC新闻数据。内容涵盖使用海外代理IP的必要性、青果代理IP的优势、实战爬取流程、数据清洗与可视化分析方法,以及高效构建大规模新闻采集方案的建议。适用于需要获取国际政治经济动态信息的商业决策、市场预测及学术研究场景。
|
4月前
|
数据可视化 数据挖掘 数据安全/隐私保护
Python实现时间序列动量策略:波动率标准化让量化交易收益更平稳
时间序列动量策略(TSMOM)是一种基于资产价格趋势的量化交易方法,通过建立多头或空头头寸捕捉市场惯性。然而,传统TSMOM策略因风险敞口不稳定而面临收益波动问题。波动率调整技术通过动态调节头寸规模,维持恒定风险水平,优化了策略表现。本文系统分析了波动率调整TSMOM的原理、实施步骤及优势,强调其在现代量化投资中的重要地位,并探讨关键参数设定与实际应用考量,为投资者提供更平稳的风险管理体验。
151 4
Python实现时间序列动量策略:波动率标准化让量化交易收益更平稳
|
3月前
|
数据采集 Web App开发 自然语言处理
利用Python构建今日头条搜索结果的可视化图表
利用Python构建今日头条搜索结果的可视化图表
|
6月前
|
机器学习/深度学习 设计模式 API
Python 高级编程与实战:构建 RESTful API
本文深入探讨了使用 Python 构建 RESTful API 的方法,涵盖 Flask、Django REST Framework 和 FastAPI 三个主流框架。通过实战项目示例,详细讲解了如何处理 GET、POST 请求,并返回相应数据。学习这些技术将帮助你掌握构建高效、可靠的 Web API。
|
6月前
|
机器学习/深度学习 设计模式 测试技术
Python 高级编程与实战:构建自动化测试框架
本文深入探讨了Python中的自动化测试框架,包括unittest、pytest和nose2,并通过实战项目帮助读者掌握这些技术。文中详细介绍了各框架的基本用法和示例代码,助力开发者快速验证代码正确性,减少手动测试工作量。学习资源推荐包括Python官方文档及Real Python等网站。
|
6月前
|
机器学习/深度学习 设计模式 API
Python 高级编程与实战:构建微服务架构
本文深入探讨了 Python 中的微服务架构,介绍了 Flask、FastAPI 和 Nameko 三个常用框架,并通过实战项目帮助读者掌握这些技术。每个框架都提供了构建微服务的示例代码,包括简单的 API 接口实现。通过学习本文,读者将能够使用 Python 构建高效、独立的微服务。

热门文章

最新文章

推荐镜像

更多