You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Highstock中添加多指标?无blacklabel插件实现蜡烛图及多指标展示

嘿,这事儿不难!不用依赖blacklabel插件,咱们直接用Highstock原生的多面板(pane)功能就能实现你要的效果——顶部蜡烛图+成交量,下面依次排列RSI、MACD、ADX这些指标。我给你整理了完整的实现代码和关键细节,你直接拿去用就行:

核心实现思路
  • 用Highstock的panes配置多个独立图表面板,每个面板对应一类数据/指标
  • 手动计算RSI、MACD、ADX这些技术指标的数值(毕竟不用插件,得自己处理数据逻辑)
  • 通过series的pane和yAxis属性,把不同数据绑定到对应面板
完整可运行代码
(function () {
    // 计算RSI指标(默认14周期)
    function calculateRSI(data, period = 14) {
        const rsi = [];
        const gains = [];
        const losses = [];

        // 计算每日涨跌额
        for (let i = 1; i < data.length; i++) {
            const change = data[i][4] - data[i - 1][4];
            gains.push(Math.max(change, 0));
            losses.push(Math.max(-change, 0));
        }

        // 初始平均涨跌幅
        let avgGain = gains.slice(0, period).reduce((a, b) => a + b, 0) / period;
        let avgLoss = losses.slice(0, period).reduce((a, b) => a + b, 0) / period;

        // 计算第一个RSI值
        let rs = avgGain / avgLoss;
        rsi.push([data[period][0], 100 - (100 / (1 + rs))]);

        // 迭代计算后续RSI
        for (let i = period; i < data.length - 1; i++) {
            avgGain = (avgGain * (period - 1) + gains[i]) / period;
            avgLoss = (avgLoss * (period - 1) + losses[i]) / period;
            rs = avgGain / avgLoss;
            rsi.push([data[i + 1][0], 100 - (100 / (1 + rs))]);
        }
        return rsi;
    }

    // 计算MACD指标(默认12/26/9周期)
    function calculateMACD(data, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
        const emaFast = [];
        const emaSlow = [];
        const macdLine = [];
        const signalLine = [];
        const macdHistogram = [];

        // 计算快速EMA
        const kFast = 2 / (fastPeriod + 1);
        emaFast.push(data[0][4]);
        for (let i = 1; i < data.length; i++) {
            emaFast.push(data[i][4] * kFast + emaFast[i - 1] * (1 - kFast));
        }

        // 计算慢速EMA
        const kSlow = 2 / (slowPeriod + 1);
        emaSlow.push(data[0][4]);
        for (let i = 1; i < data.length; i++) {
            emaSlow.push(data[i][4] * kSlow + emaSlow[i - 1] * (1 - kSlow));
        }

        // 计算MACD线
        for (let i = 0; i < data.length; i++) {
            macdLine.push([data[i][0], emaFast[i] - emaSlow[i]]);
        }

        // 计算信号线(MACD的EMA)
        const kSignal = 2 / (signalPeriod + 1);
        signalLine.push([macdLine[0][0], macdLine[0][1]]);
        for (let i = 1; i < macdLine.length; i++) {
            signalLine.push([macdLine[i][0], macdLine[i][1] * kSignal + signalLine[i - 1][1] * (1 - kSignal)]);
        }

        // 计算MACD柱状图
        for (let i = 0; i < macdLine.length; i++) {
            macdHistogram.push([macdLine[i][0], macdLine[i][1] - signalLine[i][1]]);
        }

        return { macdLine, signalLine, macdHistogram };
    }

    // 计算ADX指标(默认14周期)
    function calculateADX(data, period = 14) {
        const tr = [];
        const dmPlus = [];
        const dmMinus = [];
        const trSmooth = [];
        const dmPlusSmooth = [];
        const dmMinusSmooth = [];
        const diPlus = [];
        const diMinus = [];
        const dx = [];
        const adx = [];

        // 计算真实波幅TR和动向值DM+/-
        for (let i = 1; i < data.length; i++) {
            const high = data[i][2];
            const low = data[i][3];
            const prevHigh = data[i - 1][2];
            const prevLow = data[i - 1][3];
            const close = data[i - 1][4];

            // 真实波幅TR
            const tr1 = high - low;
            const tr2 = Math.abs(high - close);
            const tr3 = Math.abs(low - close);
            tr.push(Math.max(tr1, tr2, tr3));

            // 动向值DM+/-
            const upMove = high - prevHigh;
            const downMove = prevLow - low;
            dmPlus.push(upMove > downMove && upMove > 0 ? upMove : 0);
            dmMinus.push(downMove > upMove && downMove > 0 ? downMove : 0);
        }

        // 平滑处理TR、DM+、DM-
        trSmooth.push(tr.slice(0, period).reduce((a, b) => a + b, 0));
        dmPlusSmooth.push(dmPlus.slice(0, period).reduce((a, b) => a + b, 0));
        dmMinusSmooth.push(dmMinus.slice(0, period).reduce((a, b) => a + b, 0));

        for (let i = period; i < tr.length; i++) {
            trSmooth.push(trSmooth[i - period] - trSmooth[i - period] / period + tr[i]);
            dmPlusSmooth.push(dmPlusSmooth[i - period] - dmPlusSmooth[i - period] / period + dmPlus[i]);
            dmMinusSmooth.push(dmMinusSmooth[i - period] - dmMinusSmooth[i - period] / period + dmMinus[i]);
        }

        // 计算DI+、DI-
        for (let i = 0; i < trSmooth.length; i++) {
            diPlus.push([data[i + period][0], (dmPlusSmooth[i] / trSmooth[i]) * 100]);
            diMinus.push([data[i + period][0], (dmMinusSmooth[i] / trSmooth[i]) * 100]);
        }

        // 计算DX
        for (let i = 0; i < diPlus.length; i++) {
            const diff = Math.abs(diPlus[i][1] - diMinus[i][1]);
            const sum = diPlus[i][1] + diMinus[i][1];
            dx.push([diPlus[i][0], (diff / sum) * 100]);
        }

        // 计算ADX
        adx.push([dx[period - 1][0], dx.slice(0, period).reduce((a, b) => a + b[1], 0) / period]);
        for (let i = period; i < dx.length; i++) {
            adx.push([dx[i][0], (adx[i - period][1] * (period - 1) + dx[i][1]) / period]);
        }

        return adx;
    }

    $.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-ohlcv.json&callback=?', function (data) {
        // 将数据集拆分为ohlc和成交量数据
        const ohlc = [];
        const volume = [];
        const dataLength = data.length;

        // 处理原始数据
        for (let i = 0; i < dataLength; i++) {
            ohlc.push([
                data[i][0], // 时间戳
                data[i][1], // 开盘价
                data[i][2], // 最高价
                data[i][3], // 最低价
                data[i][4]  // 收盘价
            ]);
            volume.push([
                data[i][0], // 时间戳
                data[i][5]  // 成交量
            ]);
        }

        // 计算各指标数据
        const rsiData = calculateRSI(data);
        const { macdLine, signalLine, macdHistogram } = calculateMACD(data);
        const adxData = calculateADX(data);

        // 初始化Highstock图表
        Highcharts.stockChart('container', {
            title: {
                text: 'AAPL 股票分析'
            },
            rangeSelector: {
                selected: 1
            },
            // 配置多面板
            panes: [
                {
                    height: '60%',
                    spacingBottom: 20
                },
                {
                    height: '15%',
                    spacingBottom: 10
                },
                {
                    height: '15%',
                    spacingBottom: 10
                },
                {
                    height: '10%'
                }
            ],
            // 对应每个面板的Y轴
            yAxis: [
                {
                    title: { text: '价格' },
                    height: '60%',
                    lineWidth: 2,
                    pane: 0
                },
                {
                    title: { text: '成交量' },
                    top: '60%',
                    height: '10%',
                    offset: 0,
                    lineWidth: 2,
                    pane: 0
                },
                {
                    title: { text: 'RSI' },
                    top: '70%',
                    height: '15%',
                    offset: 0,
                    lineWidth: 2,
                    pane: 1,
                    plotLines: [
                        {
                            value: 70,
                            color: 'red',
                            dashStyle: 'shortdash',
                            width: 1,
                            label: { text: '超买' }
                        },
                        {
                            value: 30,
                            color: 'green',
                            dashStyle: 'shortdash',
                            width: 1,
                            label: { text: '超卖' }
                        }
                    ]
                },
                {
                    title: { text: 'MACD' },
                    top: '85%',
                    height: '15%',
                    offset: 0,
                    lineWidth: 2,
                    pane: 2
                },
                {
                    title: { text: 'ADX' },
                    top: '100%',
                    height: '10%',
                    offset: 0,
                    lineWidth: 2,
                    pane: 3
                }
            ],
            // 各系列数据配置
            series: [
                {
                    type: 'candlestick',
                    name: 'AAPL',
                    data: ohlc,
                    yAxis: 0,
                    pane: 0
                },
                {
                    type: 'column',
                    name: '成交量',
                    data: volume,
                    yAxis: 1,
                    pane: 0
                },
                {
                    type: 'line',
                    name: 'RSI (14)',
                    data: rsiData,
                    yAxis: 2,
                    pane: 1
                },
                {
                    type: 'line',
                    name: 'MACD',
                    data: macdLine,
                    yAxis: 3,
                    pane: 2,
                    color: '#0070C0'
                },
                {
                    type: 'line',
                    name: '信号线',
                    data: signalLine,
                    yAxis: 3,
                    pane: 2,
                    color: '#FF0000'
                },
                {
                    type: 'column',
                    name: 'MACD柱状图',
                    data: macdHistogram,
                    yAxis: 3,
                    pane: 2,
                    color: '#548235'
                },
                {
                    type: 'line',
                    name: 'ADX (14)',
                    data: adxData,
                    yAxis: 4,
                    pane: 3,
                    color: '#FFC000'
                }
            ]
        });
    });
}());
关键细节说明
  • 多面板布局:通过panes数组定义每个面板的高度和间距,再用yAxis的top和height属性对应到面板位置
  • 指标计算:所有技术指标都是基于原始OHLCV数据手动计算的,你可以根据需求调整周期参数(比如RSI的14周期、MACD的12/26/9周期)
  • 系列绑定:每个series通过pane和yAxis属性明确指定属于哪个面板和哪个Y轴,避免数据错乱
  • 交互优化:Highstock原生支持缩放、拖拽等交互操作,多面板会同步联动,不用额外配置

内容的提问来源于stack exchange,提问作者Dani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:13:29