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

Next.js中Highcharts自定义指标集成问题及替代方案咨询

问题

我正在开发一个外汇经纪商项目,尝试在Next.js中使用Highcharts库集成自定义指标,但没找到相关文档。之前用Trading View,但集成指标需要付费,成本太高,想知道怎么用Highcharts实现这个需求,或者有哪些适合股票/外汇数据的替代库。

以下是当前代码:

import HighchartsReact from 'highcharts-react-official'
import Highcharts from "highcharts/highstock";
import HighchartsExporting from 'highcharts/modules/exporting'
import patternFill from "highcharts/modules/pattern-fill";


const fetchHighchartData = async () => {
        setchartData({
            data: [],
            data_volume: [],
            show_data: false
        })
        const data = await fetch(
            'https://demo-live-data.highcharts.com/aapl-ohlcv.json'
        ).then(response => response.json());
        // split the data set into ohlc and volume
        const ohlc = [],
            volume = [],
            dataLength = data.length;

        for (let i = 0; i < dataLength; i += 1) {
            ohlc.push([
                data[i][0], // the date
                data[i][1], // open
                data[i][2], // high
                data[i][3], // low
                data[i][4] // close
            ]);

            volume.push([
                data[i][0], // the date
                data[i][5] // the volume
            ]);
        }
        setchartData({
            data: ohlc,
            data_volume: volume,
            show_data: true
        })

        console.log(this)
    }


    useLayoutEffect(() => {
        
        fetchHighchartData()
       
    }, [])

    const options = {
        chart:{
            width:'1000',
            height:'600'
        },
           
        title: {
            text: 'My chart',
            
        },

        yAxis: [{
            height: '75%',
            width:'100%',
            labels: {
              align: 'right',
              x: -3
            },
            title: {
              text: 'AAPL'
            }
          }, {
            top: '75%',
            height: '25%',
            labels: {
              align: 'right',
              x: -3
            },
            offset: 0,
            title: {
              text: 'MACD'
            }
          }],
        

        series: [{
            type:'candlestick',
            id: 'aapl',
            name: 'AAPL',
            data: chartData.data,
            
        },
        {
            type:'line',
            id: 'volume',
            name: 'Volume',
            data: chartData.data_volume,
            yAxis: 1
        }
        ]
    }
    console.log(options)
    



    return (
        <>
            {authData.logged_in ?
                <Hero>
                    <main className={'bg-[#0B1215] lg:w-[100`enter code here`%] lg:h-[120vh]  max-xl:h-[100vh] lg:overflow-x-hidden md:h-[150vh] md:w-[100%] max-md:h-[100vh] max-md:w-[100%] '}>

                        <div className={'flex lg:w-full lg:h-[100%] md:h-full lg:flex-row p-2'}>
                            <aside className={' lg:flex lg:w-[25%] lg:h-[full] md:h-full p-5 md:hidden sm:hidden max-sm:hidden'}>
                                <Rates handleGraphChange={handleGraphChange} />
                            </aside>

                            <div className={'flex lg:flex-row p-0 lg:w-[100%] lg:h-full md:w-[100%] md:h-[100%] sm:w-[100%] sm:h-[100%] max-sm:w-[100%] max-sm:h-[100%]  border-white bg-[#101720] max-md:flex-col max-xl:flex-col md:flex-col'}>
                                <div className='flex flex-col w-[100%] h-[100%] p-2'>

                                    <div className='p-0 m-0 w-[100%] lg:h-[10%] flex justify-center items-center'>
                                        <FlipClockCountdown

                                            // to={new Date(expiry).getTime() + 24 * 3600 * 1000 + 5000}
                                            to={'2024-09-12'}
                                            className='h-full' title='Count-Down'
                                            labels={['DAYS', 'HOURS', 'MINUTES', 'SECONDS']}

                                            digitBlockStyle={{ height: 45, width: 25, backgroundColor: 'white', color: 'bg-[#0B1215]' }}
                                            // dividerStyle={{ color: 'white', height: 1 }}
                                            //  separatorStyle={{ color: 'red', size: '6px' }}
                                            labelStyle={{ fontSize: 15, fontWeight: 500, textTransform: 'uppercase', color: 'white', marginTop: '10%' }}
                                        />

                                    </div>


                                    {/* 
                                    <div className='w-[100%] lg:h-[20%] md:h-[40%] sm:h-[50%] max-sm:h-[70%] p-2 grid lg:grid-cols-3 md:grid-cols-2 sm:grid-cols-2 max-sm:grid-cols-2  place-items-center' >
                                        <Filter />
                                    </div> */}
                                    <div   className='p-0 flex overflow-y-hidden justify-center items-center lg:w-[100%] lg:h-[90%] max-lg:w-[100%] max-lg:h-[70%] md:w-[100%] md:h-[70%] max-md:h-[100%] sm:w-[100%] sm:h-[100%] max-sm:w-[100%] max-sm:h-[100%]  '}>
                                        {chartData.show_data ?
                                        
                                            <HighchartsReact
                                                highcharts={ Highcharts }
                                                options={options}
                                                constructorType={'stockChart'}
                                                className="[w-100%] h-[100%]"
                                                
                                            />
                                            
                                            :
                                            <span className="loading loading-bars text-white loading-lg"></span>

                                            
                                        }


                                    </div>
                                </div>



                            </div>

                        </div>

                    </main>
                </Hero>

                :
                router.push('/')

            }


        </>
    )
解决方案

一、用Highcharts实现自定义指标

Highcharts Stock(你当前使用的Highstock)支持通过自定义计算逻辑添加技术指标,核心是基于OHLC数据算出指标数值,再作为新系列添加到图表中。以你代码里提到的MACD为例,步骤如下:

1. 计算指标数据

在fetchHighchartData函数中,拿到OHLC数据后添加MACD的计算逻辑(以标准参数:12日EMA、26日EMA、9日信号线为例):

// 计算EMA的工具函数
const calculateEMA = (data, period) => {
  const ema = [];
  const multiplier = 2 / (period + 1);
  // 初始EMA用前period个收盘价的平均值
  let sum = 0;
  for (let i = 0; i < period; i++) {
    sum += data[i][4];
  }
  ema.push(sum / period);
  // 后续EMA递推计算
  for (let i = period; i < data.length; i++) {
    ema.push((data[i][4] - ema[i - 1]) * multiplier + ema[i - 1]);
  }
  return ema;
};

// 在fetchHighchartData的循环结束后添加:
const closePrices = data.map(item => item[4]);
const ema12 = calculateEMA(data, 12);
const ema26 = calculateEMA(data, 26);

// 计算DIF、DEA和MACD柱状图
const dif = [];
const dea = [];
const macdHistogram = [];
for (let i = 25; i < data.length; i++) {
  const currentDif = ema12[i] - ema26[i];
  dif.push(currentDif);
  // 初始DEA等于第一个DIF
  dea.push(i === 25 ? currentDif : (currentDif - dea[i - 26]) * (2 / 10) + dea[i - 26]);
  macdHistogram.push(currentDif - dea[i - 25]);
}

// 整理成Highcharts需要的[时间戳, 数值]格式
const macdDifData = [];
const macdDeaData = [];
const macdHistogramData = [];
for (let i = 25; i < data.length; i++) {
  const timestamp = data[i][0];
  macdDifData.push([timestamp, dif[i - 25]]);
  macdDeaData.push([timestamp, dea[i - 25]]);
  macdHistogramData.push([timestamp, macdHistogram[i - 25]]);
}

// 更新chartData,加入MACD数据
setchartData({
  data: ohlc,
  data_volume: volume,
  macdDif: macdDifData,
  macdDea: macdDeaData,
  macdHistogram: macdHistogramData,
  show_data: true
});

2. 在图表配置中添加指标系列

修改options的series数组,新增MACD相关系列,同时调整y轴布局(给成交量单独分配一个轴):

// 调整yAxis配置
yAxis: [{
  height: '60%',
  width:'100%',
  labels: {
    align: 'right',
    x: -3
  },
  title: {
    text: '价格'
  }
}, {
  top: '60%',
  height: '20%',
  labels: {
    align: 'right',
    x: -3
  },
  offset: 0,
  title: {
    text: 'MACD'
  }
}, {
  top: '80%',
  height: '20%',
  labels: {
    align: 'right',
    x: -3
  },
  offset: 0,
  title: {
    text: '成交量'
  }
}]

// 调整series配置
series: [{
  type:'candlestick',
  id: 'aapl',
  name: 'AAPL',
  data: chartData.data,
},
{
  type:'column',
  name: 'MACD 柱状图',
  data: chartData.macdHistogram,
  yAxis: 1,
  color: '#2ecc71'
},
{
  type:'line',
  name: 'MACD DIF',
  data: chartData.macdDif,
  yAxis: 1,
  color: '#e74c3c',
  marker: { enabled: false }
},
{
  type:'line',
  name: 'MACD DEA',
  data: chartData.macdDea,
  yAxis: 1,
  color: '#3498db',
  marker: { enabled: false }
},
{
  type:'column',
  id: 'volume',
  name: 'Volume',
  data: chartData.data_volume,
  yAxis: 2
}]

3. 其他指标扩展逻辑

如果要添加RSI、BOLL等其他指标,逻辑完全一致:先写对应指标的计算函数,生成[时间戳, 数值]格式的数据,再添加为新的series即可。

二、适合股票/外汇数据的替代库

  • Lightweight Charts:TradingView开源的轻量级图表库,体积小、性能优异,原生支持自定义指标,API文档清晰,完全免费开源,非常适合外汇/股票K线场景。
  • ECharts:百度开源的全功能图表库,有专门的金融图表模块,内置K线、MACD、RSI等常见指标,配置灵活,文档齐全,无使用成本。
  • Chart.js + chartjs-chart-financial:基础Chart.js配合金融插件可实现K线图,自定义指标需自行编写计算逻辑,优点是轻量、生态完善。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:43:10