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

如何调整DefaultOHLCDataset中成交量缩放比例避免遮挡OHLC蜡烛图

问题原因

默认CandlestickRenderer开启setDrawVolume(true)后,成交量会和OHLC蜡烛图共用同一个数值轴,若成交量数值远高于价格区间,就会出现大面积遮挡的问题。


方案1:缩放成交量数值(适配你要控制在指定线下方的需求)

直接预处理成交量数据,将其按比例缩放到你期望的展示区间内,无需改动渲染逻辑,修改成本最低。
修改你代码中的getData方法即可:

protected OHLCDataItem[] getData(List<Candlestick> candlesticks) {
    List<OHLCDataItem> dataItems = new ArrayList<>();
    // 先遍历一次统计价格、成交量极值
    double maxPrice = Double.MIN_VALUE;
    double minPrice = Double.MAX_VALUE;
    double maxVolume = Double.MIN_VALUE;
    for (Candlestick c : candlesticks) {
        double high = convertToDouble(c.getHigh());
        double low = convertToDouble(c.getLow());
        double volume = convertToDouble(c.getVolume());
        maxPrice = Math.max(maxPrice, high);
        minPrice = Math.min(minPrice, low);
        maxVolume = Math.max(maxVolume, volume);
    }
    // 你要控制成交量在黄线下方,直接把volUpperLimit设为黄线对应的价格即可
    // 示例为成交量限制在价格区间最低15%的位置
    double priceRange = maxPrice - minPrice;
    double volUpperLimit = minPrice + priceRange * 0.15;

    for (Candlestick c : candlesticks) {
        Date date = new Date(c.getOpenTime());
        double open = convertToDouble(c.getOpen());
        double high = convertToDouble(c.getHigh());
        double low = convertToDouble(c.getLow());
        double close = convertToDouble(c.getClose());
        double rawVolume = convertToDouble(c.getVolume());
        // 按比例缩放成交量到目标区间
        double scaledVolume = maxVolume == 0 ? 0 : (rawVolume / maxVolume) * (volUpperLimit - minPrice) + minPrice;

        OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, scaledVolume);
        dataItems.add(item);
    }
    return dataItems.toArray(new OHLCDataItem[0]);
}

如果不需要在Y轴展示成交量的真实数值,该方案可以完美满足需求,直接控制成交量的最高高度到你指定的线下方。


方案2:双Y轴分离展示(更规范的金融K线实现)

如果需要保留成交量的真实数值,推荐拆分数据集,用两个独立的Y轴分别展示OHLC和成交量,完全避免遮挡:

  1. 首先关闭自带的成交量绘制:
renderer.setDrawVolume(false);
  1. 新增方法构造成交量数据集:
private XYDataset createVolumeDataset(List<Candlestick> candlesticks) {
    DefaultXYDataset dataset = new DefaultXYDataset();
    double[][] volumeData = new double[2][candlesticks.size()];
    for (int i = 0; i < candlesticks.size(); i++) {
        Candlestick c = candlesticks.get(i);
        volumeData[0][i] = c.getOpenTime();
        volumeData[1][i] = convertToDouble(c.getVolume());
    }
    dataset.addSeries("成交量", volumeData);
    return dataset;
}
  1. 在candleStickRendering方法中新增第二轴配置:
public void candleStickRendering() {
    renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
    renderer.setDrawVolume(false); // 关闭自带成交量渲染

    plot = chart.getXYPlot();
    plot.setRenderer(renderer);
    plot.setRangeGridlinePaint(Color.lightGray);
    plot.setBackgroundPaint(Color.white);
    plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);

    // 新增成交量数据集和渲染器
    XYBarRenderer volumeRenderer = new XYBarRenderer(0.3); // 0.3为柱形宽度比例
    volumeRenderer.setDefaultPaint(Color.GRAY);
    plot.setDataset(1, createVolumeDataset(candles)); // 需把candles调整为类成员变量传入
    plot.setRenderer(1, volumeRenderer);

    // 配置独立的成交量Y轴,放在图表下方
    NumberAxis volumeAxis = new NumberAxis("成交量");
    volumeAxis.setAutoRange(true);
    volumeAxis.setLowerBound(0);
    plot.setRangeAxis(1, volumeAxis);
    plot.mapDatasetToRangeAxis(1, 1); // 第二数据集绑定第二Y轴
    // 调整两个轴的高度占比,让成交量区域只占整个图的20%高度
    plot.getRangeAxis().setFixedDimension(plot.getHeight() * 0.8);
    volumeAxis.setFixedDimension(plot.getHeight() * 0.2);

    setValueAxis();
    setTimeAxis();
}

该方案两个数据系列完全独立,不会互相遮挡,也能分别显示各自的真实数值,是行业通用的K线+成交量实现方式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:24:03