用K线API构建可交互行情面板:历史数据加载与实时更新实践

用 K 线 API 构建可交互行情面板:历史数据加载与实时更新实践

系列文章 · Demo#2

在上一篇文章中,我实现了一个基于 Ticker API

的实时行情面板,解决的是"实时价格展示"的问题。但在实际使用中,一个更工程化的问题出现了:

实时快照只能告诉你"现在",却无法支撑时间序列分析。

因此,在 Demo #2 中,我对原有结构进行了一次完整升级 ------ 引入 K

线(蜡烛图)能力,并实现:

  • 历史数据加载
  • 当前周期实时补齐
  • 预加载策略
  • 可视范围控制
  • 主从面板结构改造

一、结构升级:主从布局改造

原始 Demo #1 是全宽行情列表。

本次升级采用"主从布局":

  • 左侧:简化行情列表
  • 右侧:行情快照 + K 线图表

不引入新路由,不刷新页面,仅通过状态控制 DOM 展开。

结构示意如下:

工程目标:

  • 不破坏原有 Ticker 刷新逻辑
  • 不增加页面跳转复杂度
  • 保持组件解耦

二、接口职责拆分:History vs Latest

核心接口:

  • /kline ------ 返回已完成周期的历史数据
  • /kline/latest ------ 返回当前正在形成的周期数据

工程逻辑必须分层处理:

pseudo 复制代码
// 1. 先加载历史数据
historyData = await fetchKLine(symbol, interval, 75)

// 2. 获取当前周期
latestKline = await fetchLatestKLine(symbol, interval)

// 3. 合并逻辑
if latestKline exists:
    if same timestamp:
        replace
    else:
        push

设计原则:

  1. 历史数据只负责结构化展示\
  2. latest 只负责补齐当前周期\
  3. 两层逻辑完全解耦

否则会出现时间错位或重复渲染问题。


三、时间序列处理的关键细节

接口数据存在两个常见坑:

1️⃣ 时间戳单位问题

接口返回毫秒,图表库使用秒。

pseudo 复制代码
time: Math.floor(item.time / 1000)

2️⃣ 返回顺序问题

接口默认倒序,图表需要升序。

pseudo 复制代码
klineData.sort((a, b) => a.time - b.time)

完整转换逻辑:

pseudo 复制代码
const rawKlines = result.data.klines
const klineData = rawKlines.map(item => ({
    time: Math.floor(item.time / 1000),
    open: parseFloat(item.open),
    high: parseFloat(item.high),
    low: parseFloat(item.low),
    close: parseFloat(item.close)
}))

klineData.sort((a, b) => a.time - b.time)

四、预加载策略:Buffer 设计

如果用户滑到最左侧才加载历史数据,会出现明显卡顿。

我采用"可视区 + Buffer"策略:

复制代码
|------------------ 75 ------------------|
|------ 50 visible ------|-- 25 buffer --|

加载策略:

  • 首次加载 75 根
  • 可见区约 50 根
  • 预留 25 根 buffer
  • 当 buffer 消耗 50% 时触发加载

核心判断逻辑:

pseudo 复制代码
if leftBufferCount < batchLoad * triggerRatio:
    preloadHistoricalData()

五、Resize 与可视范围控制

浏览器宽度变化会改变可见 K 线数量。

使用 ResizeObserver:

pseudo 复制代码
const resizeObserver = new ResizeObserver(() => {
    const currentRange = chart.timeScale().getVisibleLogicalRange()

    chart.applyOptions({
        width: container.clientWidth,
        height: container.clientHeight
    })

    chart.timeScale().setVisibleLogicalRange(currentRange)
})

六、分层错误处理

pseudo 复制代码
loadHistory()  → 失败显示错误
preload()      → 静默失败
loadLatest()   → 不影响主图

原则:稳定性优先于完整性。


七、工程分层总结

1️⃣ 数据层 ------ History / Latest 分层

2️⃣ 视图层 ------ 主从结构 + 响应式图表

3️⃣ 交互层 ------ 预加载 + 滑动控制


最终效果


结语

从 Demo #1 的实时行情展示,到 Demo #2 的时间序列管理,系统结构更加完整。

源码可在 GitHub 搜索 tickdb-demo-ticker-panel 查看对应 Demo#2 实现。

相关推荐
TickDB官方5 小时前
在行情面板中加入 K 线:一次结构升级的实现过程
实时数据·行情api设计·行情系统·行情面板
TickDB官方17 天前
用Ticker API写一个行情面板:一次完整的实现过程
实时数据·行情系统·行情面板
TickDB官方20 天前
行情API的正确使用方式:从接口调通到系统设计
实时数据·wbsocket·行情api设计·行情系统
涤生大数据2 个月前
放弃Canal后,我们用Flink CDC实现了99.99%的数据一致性
大数据·数据仓库·flink·大数据开发·flink cdc·数据开发·实时数据
云器科技2 个月前
小红书×云器科技|增量计算+实时湖仓构建小红书实验数仓生产新范式
大数据·数据库架构·小红书·实时数据·数据湖仓
Tapdata 钛铂数据6 个月前
TapData vs Kafka ETL Pipeline:竞争?共存?——企业实时数据策略的正确打开方式
kafka·数据同步·实时数据·kafka connect
kngines7 个月前
【力扣(LeetCode)】数据挖掘面试题0002:当面对实时数据流时您如何设计和实现机器学习模型?
机器学习·数据挖掘·面试题·实时数据
PersistJiao1 年前
数仓报表需要支持历史数据和实时数据的整合的场景要如何处理
数仓·lambda架构·实时数据·离线数据
༺心有谦谦结༻2 年前
淘宝数据分析——Python爬虫模式♥
数据采集·python爬虫·实时数据·电商api·淘宝销量·淘宝店铺·淘宝天猫app