金融报表开发:jquick-pdf K 线图 PDF 可视化解决方案

29 金融报表开发:jquick-pdf K 线图 PDF 可视化解决方案

引入

投研日报需要在一份可归档的 PDF 里同时呈现交易日、开高低收行情和风险说明。K 线图把四个价格压缩成一根蜡烛,既能看清当日波动区间,也能按时间顺序观察形态。本文基于静态行情数据生成 K 线 SVG 并嵌入 PDF,不涉及实时刷新、指标叠加或交易接口。

行情能力来自 io.github.paohaijiao:jquick-pdf-svg:JCandlestick 承载蜡烛数据,JKChartsRenderer 负责渲染,分类轴承载交易日、值轴承载价格尺度。依赖坐标与模板基础语法见入门篇《01 jquick-pdf 超详细入门教程》,本文聚焦行情数据的字段约定与对齐问题。

核心讲解

选型依据

K 线图是 OHLC(开、高、低、收)数据的专用表达:实体表示开盘与收盘的差异,上下影线表示当日最高与最低。它与折线图的分工在于信息密度------折线只给一个收盘价序列,适合看长期趋势;K 线保留当日波动区间,适合看形态与振幅。

选型判断要落在业务用途上:收盘日报、投研归档、风险留痕适合 K 线;需要展示月度均价走势时,折线图更清晰。用于展示时,K 线图不应被当作交易信号,PDF 中必须附上免责声明,明确数据仅用于报告展示。

数据字段与顺序约定

KCharTest 已明确 JCandlestick 与 JKChartsRenderer 的调用方式,以及示例中每个交易日四个数值的真实写法。字段顺序必须由接口层固定下来,本文按业务惯例约定为开盘、最高、最低、收盘,并在入图前统一校验:最高价不小于开盘价与收盘价,最低价不大于开盘价与收盘价。

示例中四个数组的长度与分类轴的交易日数量一致,任何调换字段位置的操作都会让图形语义整体错位,因此建议在 DTO 中用明确的字段名(open、high、low、close)承载,而不是依赖数组下标传递。

交易日对齐与缺失交易日

分类轴上的日期与 K 线数量必须严格一一对应。非交易日(周末、法定节假日、停牌日)在原始数据中不会出现记录,如果聚合结果跳过了某一天,而分类轴仍然按自然日连续生成,图形就会整体错位。正确处理方式是:分类轴直接由查询结果的交易日集合生成,而不是由日期区间推算。

停牌、新股上市首日等场景需要单独处理。停牌日是否补一根与前一日收盘价相同的蜡烛,属于业务口径问题,必须在报告说明中写明;如果不补,则保持断点,让图形如实反映"当日无成交"。这两种策略都不应默认采用,而应由业务确认后在聚合层固定。

生成 SVG 与嵌入 PDF

链路与其它图表相同:renderer 把 SVG 写到磁盘,读取文件得到字符串,bind("svg", svg) 注入上下文,executeContent 返回 PDF 字节。模板在图表之后紧跟免责声明段落,这是金融类报表的固定要求:

html 复制代码
<pdf><body><h1>'投研日报'</h1><svg>${svg}</svg><p>'数据仅用于报告展示,不构成投资建议。'</p></body></pdf>

关键细节

  • 四元数据的开高低收顺序必须固定,并写入接口约定,任何跨模块传递都要带字段名。
  • 交易日缺失会导致轴与数据错位,分类轴应来自真实交易日集合。
  • 浮点精度与复权口径必须在入图前处理。复权前后价格不可混用,同一张图内只能是同一口径。
  • K 线图不是实时行情,PDF 中不能承诺刷新或盘中更新。
  • 异常价格应先拦截,避免比例尺失真。例如把成交额误写成价格,会让整张图的纵轴被拉到无意义的量级。
  • 空数据要显式处理,输出"所选区间内无行情记录"的提示段落。
  • 输出文件应记录数据快照时间、来源与时区,便于事后复现。
  • 报告权限与脱敏独立处理,行情数据同样可能涉及授权范围。

尺寸与分页方面,K 线的可读性取决于单根蜡烛的宽度。区间点数越多,蜡烛越窄,形态越难辨认。日报场景通常展示二十到六十个交易日为宜,更长区间建议按周或按月聚合,或拆成多张图分页输出。嵌入 PDF 后要实测分页结果,避免蜡烛图被切到下一页。

实战说明

下面程序输出当前目录的 k-report.pdf:

java 复制代码
import com.github.paohaijiao.JOption;
import com.github.paohaijiao.axis.JCategoryAxis;
import com.github.paohaijiao.axis.JValueAxis;
import com.github.paohaijiao.code.JTrigger;
import com.github.paohaijiao.config.JGraphConfig;
import com.github.paohaijiao.config.JPdfConfig;
import com.github.paohaijiao.data.JGraphContainer;
import com.github.paohaijiao.enums.JChartType;
import com.github.paohaijiao.executor.JQuickPdfFactory;
import com.github.paohaijiao.k.JKChartsRenderer;
import com.github.paohaijiao.series.JCandlestick;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;

public class KReportDemo {
    public static void main(String[] args) throws Exception {
        JOption option = new JOption();
        option.title().text("股票K线图");
        option.tooltip().trigger(JTrigger.axis);
        option.xAxis(new JCategoryAxis().data("01/01", "01/02", "01/03", "01/04"));
        option.yAxis(new JValueAxis());

        JCandlestick k = new JCandlestick().name("股价").data(
                new Object[]{105.2, 108.5, 104.8, 109.1},
                new Object[]{108.6, 107.8, 106.5, 109.5},
                new Object[]{107.9, 105.3, 104.2, 108.0},
                new Object[]{105.4, 106.1, 104.5, 107.2});
        option.series(k);

        String template = "<pdf><body><h1>'投研日报'</h1><svg>&{svg}</svg>"
                + "<p>'数据仅用于报告展示,不构成投资建议。'</p></body></pdf>";
        JGraphContainer graphContainer = new JGraphContainer();
        graphContainer.setType(JChartType.K);
        graphContainer.setOption(option);
        JGraphConfig graphConfig = new JGraphConfig();
        graphConfig.put("svg", graphContainer);
        JPdfConfig config = new JPdfConfig();
        config.setGraphConfig(graphConfig);
        byte[] pdf = new JQuickPdfFactory(config).executeContent(template);
        Files.write(Paths.get("d://test//k-report.pdf"), pdf);    }
}

逐段说明:先装配标题与触发方式,JTrigger.axis 是已验证的写法;分类轴写入四个交易日标签,值轴统一承载价格。JCandlestick 的 name 作为系列标识,data 接收四个数值数组,每个数组内部按交易日顺序排列;转入生产前,这四个数组的字段含义必须在接口注释或 DTO 中写明,不能靠记忆。renderer 输出 SVG,读回字符串后绑定变量 svg,模板用 <svg>${svg}</svg> 嵌入,并紧跟免责声明段落,最后写盘。

结果预期:PDF 中出现标题"投研日报"、四根蜡烛及其影线,以及免责声明文本。若图形只有一条水平线或蜡烛相互重叠到无法辨认,通常是分类轴日期数量与数据量不一致,应打印两个集合的长度核对。

常见失败案例:一是把 open/high/low/close 传成 high/low/open/close,图形看起来仍像蜡烛但形态整体错误;二是分类轴按自然日生成而数据按交易日聚合,导致日期与蜡烛错位;三是未做复权口径统一,长周期图上出现无法解释的跳空;四是把免责声明省略,金融类报告缺失说明会带来合规风险。

性能与监控方面,建议使用 BigDecimal 或统一行情精度做价格计算,避免浮点误差在长序列中累积;记录数据快照时间、来源与时区;限制历史点数;保存 SVG 便于问题复现。监控重点关注行情源可用性、交易日集合与图形点数是否一致,以及渲染失败率。

总结

K 线图的正确性建立在两个约定上:四元字段顺序固定,分类轴来自真实交易日集合。适用边界是静态行情展示,例如收盘日报、投研归档与风险留痕;均线、成交量等扩展能力需要先在当前版本的源码或测试中确认,本文不做假设,实时能力也不在已验证范围内。常见误区是把非交易日的空缺当作零成交、在同一张图内混用复权口径、以及省略免责声明。

版本基线:jquick-pdfx 4.0.0、JDK 8+;更多示例见 GitHub 仓库。

相关推荐
余槐i1 小时前
rollbackFor 不设置,Checked 异常不回滚:Spring 默认规则与两行修复的取舍
java·spring boot·后端·spring·事务管理
孙启超1 小时前
【AI开发之Rust】第 17 课:项目总览与核心架构 —— AI 助手 Rust 核心从 0 到 1
开发语言·后端·rust
❀͜͡傀儡师1 小时前
Spring AI 集成 TypeSafe:用判断模型处理工单分流与链路决策
java·人工智能·spring
bro_Java6661 小时前
《栈与队列:数据结构的“双生花”》
java·数据结构·编辑器
花开路口2 小时前
线程安全完全指南:从 Java 到 Kotlin,一文吃透并发编程
java·kotlin
她说..2 小时前
IntelliJ IDEA 快捷键速查表(Mac 版)
java·macos·intellij-idea
泡海椒2 小时前
多维数据分析:jquick-pdf 热力图、雷达图 PDF 实战
数据挖掘·数据分析·pdf
码匠许师傅2 小时前
【C++三方组件】Asio 上篇:回调式 TCP 客户端与服务端
开发语言·c++·tcp/ip
EatFan2 小时前
JunoYi 框架实践:Spring Boot 项目为什么拆成 framework、module、server 三层?
java·spring boot·后端·framework·module·模块化·junoyi