如何调整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和成交量,完全避免遮挡:
- 首先关闭自带的成交量绘制:
renderer.setDrawVolume(false);
- 新增方法构造成交量数据集:
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; }
- 在
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
相关产品推荐
相关产品推荐

