当前位置: 首页 > article >正文

一个Python实现的K线图表程序:从数据计算到可视化渲染的完整实践

1. 为什么我们需要自己实现K线图表程序第一次接触量化交易的朋友可能会有疑问市面上已经有那么多成熟的股票软件为什么还要自己写K线图表程序我刚开始做量化时也这么想直到真正开始策略开发才发现现成工具的限制。最直接的痛点就是指标定制化。以常见的MACD指标为例不同平台的计算公式可能略有差异。我在测试一个策略时发现某商业软件和Python计算的MACD值竟然有0.1%左右的偏差。更麻烦的是当你想测试自己改进的指标变体时商业软件根本不支持。另一个关键需求是多维度数据叠加。去年我开发一个结合量价关系的策略时需要在K线图上同时显示自定义计算的支撑压力位机器学习模型输出的买卖信号点传统技术指标成交量热力图现有软件要么无法实现这种自由组合要么需要复杂的插件开发。这就是为什么我们需要一个能完全掌控的K线图表程序。2. 程序架构设计2.1 核心模块划分经过多个版本的迭代我总结出一个高可用的K线图表程序应该包含以下模块数据层原始K线数据加载支持CSV、数据库等指标计算引擎内置常见指标外部指标数据接口配置层YAML/JSON格式的配置文件图表布局定义指标组合规则回调函数注册渲染层PySide6基础窗口自定义绘图组件K线、均线等多图表联动控制扩展层插件式指标系统策略信号标记交互式工具2.2 关键技术选型在Python生态中可视化方案很多但适合金融图表的却有限。经过对比测试我选择了以下技术栈GUI框架PySide6Qt for Python相比Tkinter有更好的绘图性能成熟的跨平台支持丰富的图形组件绘图引擎直接使用QPainter避免Matplotlib的性能瓶颈像素级绘制控制支持硬件加速配置管理YAML文件比JSON更易读的层次结构支持注释与Python无缝集成3. 从原始数据到K线图3.1 数据准备与清洗假设我们有一个包含历史K线数据的CSV文件格式如下timestamp,open,high,low,close,volume 1614556800,3500.25,3521.30,3498.50,3510.80,14250 1614643200,3512.40,3530.20,3505.60,3525.30,15680我们需要先将其转换为程序可用的数据结构class KLine: def __init__(self, timestamp, open, high, low, close, volume): self.time timestamp self.open float(open) self.high float(high) self.low float(low) self.close float(close) self.volume int(volume) def load_kline_data(filepath): klines [] with open(filepath) as f: next(f) # skip header for line in f: parts line.strip().split(,) klines.append(KLine(*parts)) return klines3.2 K线绘制原理K线的核心绘制逻辑其实很简单主要处理三种情况阳线收盘开盘实体部分用红色/绿色填充阴线收盘开盘实体部分用绿色/红色填充十字线收盘开盘只画横线用QPainter实现的代码示例def draw_candle(painter, x, open, high, low, close, width): # 确定颜色 if close open: painter.setBrush(Qt.red) painter.setPen(Qt.red) body_top close body_bottom open else: painter.setBrush(Qt.green) painter.setPen(Qt.green) body_top open body_bottom close # 绘制影线 painter.drawLine(QPointF(x, high), QPointF(x, low)) # 绘制实体 if close ! open: painter.drawRect(QRectF(x - width/2, body_top, width, body_bottom - body_top)) else: painter.drawLine(QPointF(x - width/2, close), QPointF(x width/2, close))4. 技术指标的计算与集成4.1 内置指标实现以移动平均线(MA)为例我们需要一个能动态计算的类class MovingAverage: def __init__(self, window): self.window window self.values [] def input(self, value): self.values.append(value) if len(self.values) self.window: self.values.pop(0) property def value(self): if len(self.values) self.window: return None return sum(self.values) / len(self.values)使用时只需要连续输入价格数据ma20 MovingAverage(20) for kline in klines: ma20.input(kline.close) print(f当前MA20值: {ma20.value})4.2 外部指标集成对于复杂指标如MACD可以从专业软件导出计算结果。假设我们有MACD数据文件timestamp,dif,dea,macd 1614556800,12.34,11.25,0.55 1614643200,12.78,11.89,0.89加载后可以直接用于绘图def load_macd_data(filepath): macd_items [] with open(filepath) as f: next(f) # skip header for line in f: ts, dif, dea, macd line.strip().split(,) macd_items.append({ time: int(ts), dif: float(dif), dea: float(dea), macd: float(macd) }) return macd_items5. 多图表联动与布局5.1 主图与副图配置通过YAML配置文件定义图表布局plots: - type: main height: 0 # 0表示自动填充剩余空间 items: - type: candle data: data/klines.csv - type: line data: callback:calc_ma20 color: #FF9900 width: 2 - type: sub height: 120 items: - type: macd data: data/macd.csv - type: sub height: 120 items: - type: volume data: data/klines.csv5.2 实现图表联动关键是要同步所有图表的X轴范围class ChartView(QtWidgets.QGraphicsView): def __init__(self, parentNone): super().__init__(parent) self.setRenderHint(QtGui.QPainter.Antialiasing) self.scene QtWidgets.QGraphicsScene() self.setScene(self.scene) # 存储所有可滚动的图表 self.linked_views [] def wheelEvent(self, event): # 处理缩放事件 factor 1.2 if event.angleDelta().y() 0 else 1/1.2 self.scale(factor, 1) # 同步所有关联视图 for view in self.linked_views: if view ! self: view.setTransform(self.transform())6. 性能优化技巧6.1 绘图性能瓶颈在测试万级K线数据时我遇到了严重的卡顿问题。通过性能分析发现主要瓶颈在过多的QGraphicsItem对象频繁的绘图指令提交不必要的抗锯齿优化后的解决方案class CandleItem(QtWidgets.QGraphicsItem): def __init__(self, data): super().__init__() self.data data # 批量数据 self.picture QtGui.QPicture() self._draw_all() def _draw_all(self): painter QtGui.QPainter(self.picture) painter.setRenderHint(QtGui.QPainter.Antialiasing, False) for i, bar in enumerate(self.data): draw_candle(painter, i, bar.open, bar.high, bar.low, bar.close, 0.8) painter.end() def paint(self, painter, option, widget): painter.drawPicture(0, 0, self.picture) def boundingRect(self): return QtCore.QRectF(self.picture.boundingRect())6.2 内存管理当处理长时间周期数据时需要实现动态加载class DataLoader: def __init__(self, filepath, chunk_size1000): self.filepath filepath self.chunk_size chunk_size self.current_chunk 0 self.total_chunks self._calculate_chunks() def _calculate_chunks(self): with open(self.filepath) as f: return sum(1 for _ in f) // self.chunk_size def load_chunk(self, chunk_num): start chunk_num * self.chunk_size end start self.chunk_size klines [] with open(self.filepath) as f: for i, line in enumerate(f): if start i end: klines.append(parse_kline(line)) return klines7. 扩展功能实现7.1 买卖信号标记在策略回测中可视化买卖点非常重要。我们可以扩展基础K线图来支持信号标记class SignalItem(QtWidgets.QGraphicsItem): def __init__(self, x, y, signal_type): super().__init__() self.x x self.y y self.signal_type signal_type # buy or sell def paint(self, painter, option, widget): painter.setPen(Qt.NoPen) if self.signal_type buy: painter.setBrush(Qt.green) path QtGui.QPainterPath() path.moveTo(self.x, self.y - 10) path.lineTo(self.x - 8, self.y 5) path.lineTo(self.x 8, self.y 5) path.closeSubpath() else: painter.setBrush(Qt.red) path QtGui.QPainterPath() path.moveTo(self.x, self.y 10) path.lineTo(self.x - 8, self.y - 5) path.lineTo(self.x 8, self.y - 5) path.closeSubpath() painter.drawPath(path) def boundingRect(self): return QtCore.QRectF(self.x - 10, self.y - 10, 20, 20)7.2 交互式工具实现一个简单的十字线工具class CrosshairTool: def __init__(self, view): self.view view self.h_line QtWidgets.QGraphicsLineItem() self.v_line QtWidgets.QGraphicsLineItem() self.text_item QtWidgets.QGraphicsTextItem() # 添加到场景 view.scene().addItem(self.h_line) view.scene().addItem(self.v_line) view.scene().addItem(self.text_item) # 样式设置 pen QtGui.QPen(Qt.gray, 1, Qt.DashLine) self.h_line.setPen(pen) self.v_line.setPen(pen) self.text_item.setDefaultTextColor(Qt.white) self.text_item.setFont(QtGui.QFont(Arial, 8)) # 事件绑定 view.scene().sceneRectChanged.connect(self.update_lines) view.mouseMoveEvent self.on_mouse_move def update_lines(self): rect self.view.scene().sceneRect() self.h_line.setLine(rect.left(), self.last_y, rect.right(), self.last_y) self.v_line.setLine(self.last_x, rect.top(), self.last_x, rect.bottom()) def on_mouse_move(self, event): pos self.view.mapToScene(event.pos()) self.last_x, self.last_y pos.x(), pos.y() self.update_lines() # 更新坐标文本 self.text_item.setPlainText(f({pos.x():.2f}, {pos.y():.2f})) self.text_item.setPos(pos.x() 10, pos.y() 10) QtWidgets.QGraphicsView.mouseMoveEvent(self.view, event)

相关文章:

一个Python实现的K线图表程序:从数据计算到可视化渲染的完整实践

1. 为什么我们需要自己实现K线图表程序? 第一次接触量化交易的朋友可能会有疑问:市面上已经有那么多成熟的股票软件,为什么还要自己写K线图表程序?我刚开始做量化时也这么想,直到真正开始策略开发才发现现成工具的限制…...

Equalizer APO终极指南:Windows系统级音频均衡器完整教程

Equalizer APO终极指南:Windows系统级音频均衡器完整教程 【免费下载链接】equalizerapo Equalizer APO mirror 项目地址: https://gitcode.com/gh_mirrors/eq/equalizerapo 你知道吗?Windows系统自带的音频处理其实很基础,无法满足音…...

Windows批处理脚本实战:处理含感叹号、百分号的文本替换,保姆级避坑指南

Windows批处理脚本实战:处理含感叹号、百分号的文本替换,保姆级避坑指南 在Windows自动化运维和数据清洗中,批处理脚本(.bat)是工程师们的老朋友。但当遇到包含感叹号(!)、百分号(%)等特殊字符的文本处理时&#xff0c…...

BetterNCM安装器:三步打造个性化网易云音乐体验

BetterNCM安装器:三步打造个性化网易云音乐体验 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer BetterNCM安装器是一款专为网易云音乐PC客户端设计的插件管理工具&#xff…...

OpenHarmony开发板到手后,这5个HDC命令帮你快速上手调试(DAYU200/RK3568实战)

OpenHarmony开发板实战:5个HDC命令快速上手调试 刚拿到OpenHarmony开发板时,很多开发者都会感到既兴奋又迷茫。DAYU200/RK3568作为当前热门的开发平台,其强大的性能与OpenHarmony系统的开放性为创新提供了无限可能。但面对全新的开发环境&…...

手把手教你用ChatAll和360AI浏览器,一次搞定所有主流AI模型(含免费方案)

多模型AI协同作战指南:ChatAll与360AI浏览器的高效整合方案 当你在不同AI模型间频繁切换,只为找到最适合当前任务的工具时,是否想过有一种更优雅的解决方案?本文将带你探索如何通过开源工具ChatAll和360AI浏览器的巧妙组合&#x…...

Java的java.util.random测试使用

Java随机数生成实战:探索java.util.Random的奥秘在软件开发中,随机数生成是不可或缺的功能,无论是游戏开发、密码学还是模拟测试,都需要可靠的随机数支持。Java提供了强大的java.util.Random类,它不仅是生成随机数的利…...

思源黑体TTF实战指南:多语言字体渲染优化的终极解决方案

思源黑体TTF实战指南:多语言字体渲染优化的终极解决方案 【免费下载链接】source-han-sans-ttf A (hinted!) version of Source Han Sans 项目地址: https://gitcode.com/gh_mirrors/so/source-han-sans-ttf 思源黑体TTF是一款基于Adobe和Google合作的思源黑…...

别再只用Ctrl+C/V了!这10个OneNote快捷键,让你在Windows上记笔记效率翻倍

别再只用CtrlC/V了!这10个OneNote快捷键,让你在Windows上记笔记效率翻倍 每次打开OneNote,你是不是还在用最基础的复制粘贴?作为微软生态中最强大的笔记工具,OneNote其实藏着许多能让你效率翻倍的快捷键组合。今天我们…...

抖音无水印下载器终极指南:三步搞定视频批量下载与去水印

抖音无水印下载器终极指南:三步搞定视频批量下载与去水印 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…...

如何通过开源微信小程序预约系统实现服务数字化升级?

如何通过开源微信小程序预约系统实现服务数字化升级? 【免费下载链接】xiaochengxu-appointment 小程序开发-预约 项目地址: https://gitcode.com/gh_mirrors/xia/xiaochengxu-appointment 在传统服务行业中,预约管理常常面临人工记录易错、高峰期…...

别再只看FLOPs了!从ShuffleNetV2的4条设计准则,聊聊移动端CNN模型怎么才算真的‘快’

移动端CNN模型效率优化:超越FLOPs的实战设计思维 在移动设备上部署卷积神经网络时,许多开发者都曾遇到过这样的困惑:为什么FLOPs更低的模型在实际推理中反而跑得更慢?这个看似矛盾的现象背后,隐藏着模型效率评估的深层…...

DataX新手入门:5分钟搞定你的第一个数据同步任务(StreamReader到StreamWriter实战)

DataX极简实战:从零完成内存数据同步任务 第一次接触DataX时,我被它简洁的设计哲学所吸引——用插件化架构解决异构数据源同步的复杂问题。作为阿里巴巴开源的离线数据同步工具,DataX通过Reader和Writer插件的组合,让数据流动变得…...

从AutoCAD到Revit:手把手教你用AutoLISP脚本批量导出天正墙体数据

从AutoCAD到Revit:天正墙体数据自动化迁移实战指南 在建筑信息模型(BIM)工作流中,数据在不同平台间的无缝迁移一直是行业痛点。许多设计师习惯在天正建筑(TArch)中完成初步设计,却需要在Revit等…...

SSC工具详解:从ESI文件生成到CiA402伺服驱动从站配置实战

SSC工具实战:从ESI文件生成到CiA402伺服驱动从站配置全解析 在工业自动化领域,EtherCAT凭借其高速、实时的特性已成为运动控制系统的首选协议之一。对于开发者而言,如何快速构建符合CiA402标准的伺服驱动从站是一个既基础又关键的技术挑战。本…...

InfiAgent:从智能体到基础模型的架构跃迁与实战解析

1. 项目概述:从“智能体”到“基础模型”的范式跃迁最近在AI社区里,一个名为“InfiAgent”的项目热度持续攀升。乍一看这个名字,很多人可能会联想到“智能体”(Agent),毕竟当前AI领域最火热的趋势之一就是构…...

MT4 EA避坑指南:从Nerve Knife策略看如何设计‘永不爆仓’的风控模块

MT4 EA风控设计实战:从策略逻辑到代码落地的避坑指南 在量化交易领域,风控模块的设计质量往往决定一个EA的生死存亡。许多看似完美的策略在实盘中折戟沉沙,90%的问题都出在风险控制的薄弱环节。本文将从一个专业开发者的视角,解剖…...

用Unity 2D复刻经典:如何为你的“Ruby‘s Adventure”添加完整的任务系统与NPC对话(含C#脚本详解)

用Unity 2D构建可扩展任务系统:从Rubys Adventure到RPG游戏开发实战 在独立游戏开发领域,叙事与玩法机制的融合一直是提升玩家沉浸感的关键。Unity官方教程项目Rubys Adventure作为2D游戏开发的经典入门案例,虽然展示了基础交互的实现&#x…...

机器学习数据预处理实战:20+技巧提升模型效果

1. 机器学习数据预处理全景指南刚入行机器学习时,我最常犯的错误就是直接拿原始数据往模型里塞。直到某次参加Kaggle比赛,发现冠军方案中80%的工作量都在数据预处理环节,才真正明白"Garbage in, garbage out"的含义。本文将系统梳理…...

FigmaCN:3分钟让Figma界面变中文,设计师工作效率提升50%

FigmaCN:3分钟让Figma界面变中文,设计师工作效率提升50% 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 你是否曾因Figma的全英文界面而感到困惑?是否…...

Oumuamua-7b-RP开源大模型部署教程:Mistral-7B架构日语RP优化实操手册

Oumuamua-7b-RP开源大模型部署教程:Mistral-7B架构日语RP优化实操手册 1. 项目概述 Oumuamua-7b-RP 是一个基于Mistral-7B架构的日语角色扮演专用大语言模型Web界面。这个开源项目专为打造沉浸式日语角色对话体验而设计,特别适合日语学习者和角色扮演爱…...

如何用闲鱼自动化采集系统解决电商数据监控难题:3个实战场景与配置技巧

如何用闲鱼自动化采集系统解决电商数据监控难题:3个实战场景与配置技巧 【免费下载链接】idlefish_xianyu_spider-crawler-sender 闲鱼自动抓取/筛选/发送系统,xianyu spider crawler blablabla 项目地址: https://gitcode.com/gh_mirrors/id/idlefish…...

Zotero文献管理高效去重:智能合并重复条目的终极解决方案

Zotero文献管理高效去重:智能合并重复条目的终极解决方案 【免费下载链接】ZoteroDuplicatesMerger A zotero plugin to automatically merge duplicate items 项目地址: https://gitcode.com/gh_mirrors/zo/ZoteroDuplicatesMerger 在学术研究和文献管理过程…...

智能合约安全实践指南:从漏洞防御到全流程开发

1. 项目概述与核心价值最近在整理内部安全审计的文档时,我翻出了几年前参与的一个大型DeFi项目安全评估的笔记。当时,项目方在合约上线前,我们团队花了近一个月的时间进行“黑盒白盒”的渗透测试,最终发现了几个非常隐蔽的逻辑漏洞…...

如何在Windows上实现本地实时语音识别?TMSpeech完整教程帮你轻松搞定

如何在Windows上实现本地实时语音识别?TMSpeech完整教程帮你轻松搞定 【免费下载链接】TMSpeech 腾讯会议摸鱼工具 项目地址: https://gitcode.com/gh_mirrors/tm/TMSpeech 还在为会议记录手忙脚乱吗?还在为视频字幕制作耗费数小时吗?…...

Zotero SciPDF插件:3步实现学术文献PDF自动下载的完整指南

Zotero SciPDF插件:3步实现学术文献PDF自动下载的完整指南 【免费下载链接】zotero-scipdf Download PDF from Sci-Hub automatically For Zotero7 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-scipdf 在学术研究工作中,文献管理是每个研…...

突破容器systemctl限制:从D-Bus错误到特权模式实战解析

1. 容器中systemctl失效的根源探析 第一次在容器里敲下systemctl命令却看到"Failed to get D-Bus connection"报错时,我和大多数运维人一样满头问号。这背后其实藏着容器技术与传统系统管理的根本差异——想象你住进酒店公寓时,前台给你房门卡…...

为什么92%的医疗SaaS团队还在手动校验FHIR资源?(VSCode一键式语义校验工作流首次公开)

更多请点击: https://intelliparadigm.com 第一章:FHIR语义校验的临床意义与工程困境 FHIR(Fast Healthcare Interoperability Resources)作为现代医疗互操作标准,其资源模型虽具备结构化优势,但仅依赖JSO…...

从NTU RGB+D到NTU RGB+D 120:骨架行为识别数据集的演进与动作标签全景解析

1. 骨架行为识别数据集的演进背景 骨架行为识别是计算机视觉领域的重要研究方向,它通过分析人体关节点的运动轨迹来识别和理解人类行为。在这个领域中,高质量的数据集是算法研发和性能评估的基础。NTU RGBD系列数据集作为该领域的标杆性资源,…...

快速上手SPIRAN ART SUMMONER:沉浸式UI界面与基础功能详解

快速上手SPIRAN ART SUMMONER:沉浸式UI界面与基础功能详解 1. 初识SPIRAN ART SUMMONER SPIRAN ART SUMMONER是一款融合了顶尖图像生成技术与《最终幻想10》美学风格的视觉创作平台。它不仅仅是一个AI图像生成工具,更是一个充满仪式感的数字艺术创作空…...