简介:这份资源面向微信小程序开发者与股票行情应用爱好者,提供沪深/港股K线图、走势图的完整实现方案,并支持通达信语法解析,适合具备一定前端基础、希望在小程序内搭建专业行情图表的开发者参考。压缩包共72个文件,约1.14MB,以js逻辑脚本、png图表素材、html与css样式页面为主,另含json配置、wxss/wxml小程序页面文件及字体资源,覆盖行情模块用例、历史与分时图表、指标公式解析等模块。项目围绕数据获取、格式转换、图表渲染与手势交互等关键环节展开,可帮助读者理解K线蜡烛图与折线走势图的绘制流程,以及通达信技术指标公式的复用思路。目前已有1078人学习下载,适合作为小程序股票图表开发与行情可视化实践的参考素材。
1. 从一次行情页翻车说起:这套小程序 K 线方案到底能不能接
去年帮一个做量化工具的朋友改小程序,需求很明确:沪深和港股都要看 K 线,还得支持均线、MACD、成交量副图,最好能直接复用他们后端那套通达信公式。我第一反应是找现成的图表库,结果试了三个方案,两个在港股数据上直接白屏,一个副图切换时卡到掉帧。后来翻到这套 HQChart 的小程序版本,才算把坑填上。
这份资源本质上是一套跑在微信小程序里的金融图表渲染方案,核心能力有三块:一是沪深和港股的多周期 K 线绘制,二是走势图(分时)和副图指标联动,三是内置了一套通达信语法的解析引擎,意味着你后端如果已经在用通达信公式算指标,前端不用重写逻辑。适合谁?做股票类小程序的前端、需要快速搭行情页的全栈,以及手里有通达信公式资产想搬到移动端的团队。不适合谁?只想静态展示一张 K 线图、不做交互的极简场景,那用轻量库更省事。
2. 拆开 HQChart 小程序包:目录结构、渲染链路与选型理由
2.1 包内到底有什么,先看目录再动手
拿到压缩包后别急着往项目里塞,先解压看结构。这套资源的典型目录长这样(不同版本略有差异,以实际为准):
HQChart-master/ ├── umychart/ # 核心渲染引擎 │ ├── umychart.js # 主入口,K线绘制逻辑 │ ├── umychartdata.js # 数据适配层 │ └── umychartstyle.js # 样式配置 ├── pages/ │ └── kline/ # 小程序页面示例 │ ├── kline.js │ ├── kline.wxml │ └── kline.wxss ├── utils/ │ └── stockdata.js # 模拟数据与请求封装 └── app.json核心是umychart目录,它不依赖任何第三方图表库,自己用 canvas 2D 画的。这一点很关键:小程序里用 echarts 那类库,包体积和渲染性能都是问题,HQChart 走的是自绘路线,包体可控。
2.2 为什么选 canvas 2D 而不是 web-view 嵌 H5
常见做法有两种:一是 web-view 嵌一个 H5 图表页,二是原生 canvas 绘制。前者开发快,但小程序对 web-view 的限制越来越多,通信靠 postMessage,港股数据量大时延迟明显,而且用户滑动时容易和原生页面手势冲突。HQChart 选的是后者,直接用小程序 canvas 2D 接口。
选型理由很实在:K 线图本质是大量矩形和线段的绘制,canvas 2D 在小程序里已经支持离屏渲染和requestAnimationFrame,帧率能稳住。更重要的是,通达信公式解析需要频繁重算指标,放在 JS 层做比跨 web-view 通信少一层开销。
2.3 渲染链路:从数据到屏幕经过了什么
一次完整的 K 线绘制,链路是这样的:
- 页面
onLoad里初始化图表实例,传入 canvas 节点和配置项; - 调用数据接口拿到 OHLCV 数组(开高低收量);
- 数据适配层把不同来源的字段名统一成内部格式;
- 指标引擎根据配置的通达信公式计算均线、MACD 等;
- 渲染引擎按当前可视区域计算坐标,绘制蜡烛、均线、副图;
- 手势事件(滑动、缩放)触发重绘。
这里有个容易忽略的点:第 3 步的字段映射。沪深接口常见返回open/close/high/low,港股有些接口返回o/c/h/l,如果适配层没做兼容,图表会画出一堆 NaN。我一般会在适配层加一个字段别名表,后面避坑章节会细说。
2.4 最小可运行示例:把 K 线跑起来
先在小程序里建一个页面,wxml 里放 canvas:
<!-- pages/kline/kline.wxml --> <canvas type="2d" id="klineCanvas" style="width: 100%; height: 600rpx;" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd" ></canvas>然后在 js 里初始化:
// pages/kline/kline.js const HQChart = require('../../umychart/umychart.js'); Page({ onReady() { const query = wx.createSelectorQuery(); query.select('#klineCanvas') .fields({ node: true, size: true }) .exec((res) => { const canvas = res[0].node; const ctx = canvas.getContext('2d'); // 处理高清屏,避免模糊 const dpr = wx.getSystemInfoSync().pixelRatio; canvas.width = res[0].width * dpr; canvas.height = res[0].height * dpr; ctx.scale(dpr, dpr); // 初始化图表实例 this.chart = new HQChart.Chart(canvas, ctx, { type: 'kline', // kline 表示蜡烛图,分时用 minute market: 'sh', // sh 沪深,hk 港股 period: 1, // 周期,1 日线,5 五分钟 indicators: ['MA', 'MACD', 'VOL'] // 主图均线 + 副图 }); this.loadData(); }); }, loadData() { // 这里替换成你自己的接口 const data = this.getMockData(); this.chart.setData(data); this.chart.render(); }, getMockData() { // 模拟一组 OHLCV,实际从后端拉 const list = []; let base = 100; for (let i = 0; i < 200; i++) { const open = base + Math.random() * 2 - 1; const close = open + Math.random() * 2 - 1; const high = Math.max(open, close) + Math.random(); const low = Math.min(open, close) - Math.random(); list.push({ date: `2024-01-${(i % 28) + 1}`, open, close, high, low, volume: Math.floor(Math.random() * 100000) }); base = close; } return list; } });逻辑说明:type决定画蜡烛还是分时线,market影响交易时段和涨跌颜色(港股和沪深在颜色习惯上可能不同,配置里可改)。indicators数组里,第一个通常画在主图,后面的画在副图。setData接收的是标准 OHLCV 数组,字段名要和适配层约定一致。
参数说明:period为 1 时是日线,5 是五分钟线,60 是小时线,具体支持哪些周期看引擎实现。dpr缩放那几行别省,否则在高分屏上线条发虚,这是 canvas 绘图的通用坑。
3. 通达信语法接入:公式解析、指标计算与港股适配
3.1 通达信公式在小程序里怎么跑
通达信公式的语法特点是函数式表达,比如MA(CLOSE, 5)表示五日均线,EMA(CLOSE, 12)是指数移动平均。HQChart 内置了一个解析器,把这类字符串转成可执行的指标计算逻辑。
接入方式一般是在配置里传公式字符串:
// 在图表配置里追加自定义指标 this.chart.addIndicator({ name: 'MY_MA', formula: 'MA(CLOSE, 5)', // 通达信语法 target: 'main', // main 主图,sub 副图 color: '#ff9900', lineWidth: 1 });逻辑说明:formula里CLOSE是内置变量,对应每根 K 线的收盘价。解析器会逐根计算,把结果数组交给渲染层。target决定画在主图还是副图,主图叠加在蜡烛上,副图单独占一块区域。
参数说明:color和lineWidth是样式,不传有默认值。如果公式里用了REF、HHV、LLV这类带周期参数的函数,注意周期不能超过数据长度,否则前面几根会返回空值,渲染时要跳过。
3.2 港股数据接入的三个差异点
沪深和港股虽然都是 OHLCV,但实际对接时有三个地方要改:
| 差异点 | 沪深常见情况 | 港股常见情况 | 处理方式 |
|---|---|---|---|
| 交易时段 | 上午下午各两小时 | 上午下午时段不同,还有半日市 | 分时图要按市场配置时段 |
| 涨跌颜色 | 红涨绿跌 | 部分接口红涨绿跌,部分相反 | 配置项里可切换 |
| 货币单位 | 人民币 | 港币 | 展示时加单位标识 |
分时图的时段配置尤其重要。如果直接把沪深的分时逻辑套到港股,遇到半日市或者节假日,X 轴会画歪。常见做法是在数据适配层根据market字段加载不同的时段表。
3.3 副图指标联动与重算时机
副图指标(MACD、KDJ 等)和主图共享同一份 OHLCV 数据,但计算逻辑独立。联动体现在两点:一是缩放时主副图 X 轴同步,二是十字光标移动时主副图同时显示对应值。
重算时机要控制好。每次手势缩放都全量重算 MACD 会很卡,我一般这样做:
// 只在数据变化时重算指标,缩放只重绘 this.chart.on('dataChange', () => { this.chart.recalcIndicators(); // 重算所有指标 }); this.chart.on('zoom', () => { this.chart.render(); // 只重绘,不重算 });逻辑说明:dataChange在setData后触发,此时指标需要重新计算。zoom和pan只是改变可视区域,指标值本身没变,重绘即可。这样能把滑动时的帧率稳住。
参数说明:如果指标公式里包含未来函数(比如某些自定义公式引用了后面的数据),重算逻辑要特别处理,否则会出现「指标值随缩放变化」的玄学现象。通达信语法里REF是引用历史,REFX才是引用未来,接入前先确认公式里没有REFX。
3.4 一个完整的指标配置示例
把主图均线和副图 MACD 一起配上:
const chartConfig = { type: 'kline', market: 'hk', period: 1, indicators: [ { name: 'MA5', formula: 'MA(CLOSE, 5)', target: 'main', color: '#ffffff' }, { name: 'MA10', formula: 'MA(CLOSE, 10)', target: 'main', color: '#ffff00' }, { name: 'MA20', formula: 'MA(CLOSE, 20)', target: 'main', color: '#ff00ff' }, { name: 'MACD', formula: 'MACD(12, 26, 9)', target: 'sub' } ], subHeight: 120, // 副图高度,单位 px candleWidth: 6, // 蜡烛宽度 gap: 2 // 蜡烛间距 }; this.chart.setConfig(chartConfig);逻辑说明:主图三条均线用不同颜色区分,副图 MACD 是内置复合公式,解析器会展开成 DIF、DEA、柱状图三部分。subHeight控制副图占用的高度,太小会看不清柱状图,太大主图被压缩。
参数说明:candleWidth和gap影响可视区域能显示多少根 K 线。日线场景下,宽度 6 间距 2 大约一屏能看 60 根左右。如果用户习惯看更多,可以调小这两个值,但太小会糊成一片。
4. 避坑与排查:那些让我加班到凌晨的细节
4.1 港股数据白屏,控制台报 NaN
现象:沪深数据正常,切到港股后图表区域全白,控制台没有明显报错,但 canvas 上什么都没画。
原因:港股接口返回的字段名和沪深不一致,比如用o/c/h/l而不是open/close/high/low,适配层没做映射,计算坐标时得到 NaN,绘制指令被静默跳过。
解决:在数据适配层加字段别名表,统一转成内部格式。我一般这样写:
function normalizeBar(raw) { return { date: raw.date || raw.time || raw.t, open: raw.open ?? raw.o, close: raw.close ?? raw.c, high: raw.high ?? raw.h, low: raw.low ?? raw.l, volume: raw.volume ?? raw.vol ?? raw.v }; }注意??和||的区别:如果字段值是 0,||会误判成空,用??更安全。
4.2 滑动时卡顿,帧率掉到 20 以下
现象:K 线数量超过 500 根后,左右滑动明显卡顿,副图越多越严重。
原因:每次touchmove都触发了全量重绘,包括指标重算。指标计算是 O(n) 的,500 根数据每帧算一遍 MACD,JS 线程扛不住。
解决:把重算和重绘分离,滑动时只重绘不重算(见 3.3 节)。另外可以加一个节流,touchmove里用requestAnimationFrame包一层,避免一帧内多次触发。
4.3 分时图 X 轴错位,港股半日市画歪
现象:港股遇到半日市(比如某些节假日前),分时图后半段空白或者时间轴对不上。
原因:分时图的 X 轴是按固定时段均分的,沪深和港股时段不同,半日市更特殊。如果时段表写死,就会错位。
解决:把时段配置抽成独立模块,按market和日期动态加载。常见做法是维护一个时段表,分时图初始化时传入当天的实际交易时段。
4.4 通达信公式报错但无提示
现象:配置了自定义公式后,指标线不显示,控制台也没有报错。
原因:公式解析器对语法错误做了静默处理,返回空数组,渲染层跳过。常见错误包括括号不匹配、函数名拼错、参数个数不对。
解决:在addIndicator后加一个校验,检查返回的指标数组长度是否和数据长度一致:
const result = this.chart.addIndicator({ formula: 'MA(CLOSE, 5)', target: 'main' }); if (!result || result.length !== this.chart.data.length) { console.warn('指标计算异常,检查公式语法:', result); }4.5 高清屏线条发虚
现象:在部分机型上 K 线边缘模糊,像蒙了一层雾。
原因:canvas 的物理像素和 CSS 像素没对齐,没有按pixelRatio缩放。
解决:初始化时按dpr设置 canvas 宽高并ctx.scale(dpr, dpr),见 2.4 节代码。这个坑在 canvas 绘图里几乎每次都会遇到,养成习惯就好。
5. 进阶技巧:把指标计算搬到 Worker 里
当 K 线数量到几千根、副图指标十几个的时候,主线程计算指标会明显拖慢交互。我后来把指标计算挪到了 Worker 里,主线程只负责绘制。
小程序支持 Worker,但要注意 Worker 里不能直接操作 canvas,只能做纯计算。思路是:主线程把 OHLCV 数据发给 Worker,Worker 算完指标回传,主线程拿到结果后渲染。
// worker/indicator.js worker.onMessage((msg) => { const { data, formulas } = msg; const results = {}; formulas.forEach((f) => { results[f.name] = calcFormula(data, f.formula); // 纯计算 }); worker.postMessage({ results }); });主线程这边:
// pages/kline/kline.js const worker = wx.createWorker('worker/indicator.js'); worker.onMessage((res) => { this.chart.setIndicators(res.results); // 只更新指标数据 this.chart.render(); }); // 数据变化时发给 Worker this.chart.on('dataChange', () => { worker.postMessage({ data: this.chart.data, formulas: this.chartConfig.indicators }); });逻辑说明:Worker 负责重计算,主线程负责渲染,两者通过消息通信。这样滑动时主线程不会被指标计算阻塞,帧率能稳住。
参数说明:Worker 的创建有开销,不要每次数据变化都新建,页面onLoad时建一次,onUnload时销毁。另外 Worker 和主线程之间传大数据有序列化成本,如果 OHLCV 超过一万根,可以考虑只传增量。
验证方法:在开发者工具的 Performance 面板里看主线程的脚本执行时间,如果指标计算占比明显下降,说明 Worker 生效了。我一般会对比开启前后的滑动帧率,从 20 多帧提到 50 帧以上才算达标。
从那以后我每次接行情类小程序,都会先把数据适配层和指标计算这两块单独拎出来测一遍,确认字段映射和公式解析没问题再往页面里塞。希望帮到你。
本文还有配套的精品资源,点击获取