Flutter K线系统拆解(二):指标引擎与增量计算

目标

这篇只讲一件事:
如何把 K 线指标计算做成高性能、可维护、可测试的生产级引擎。


一、最佳实践架构:三层拆分

指标模块建议拆成三层:

  1. IndicatorConfig(配置层):维护 MA/BOLL/MACD 等参数与开关
  2. IndicatorEngine(计算层):只负责输入数据、输出结果,不关心 UI
  3. ChartAdapter(消费层):把结果喂给渲染,不做任何业务计算

核心原则:

  • 渲染层只读结果,不参与计算
  • 计算层纯函数化,避免隐式全局状态
  • 配置变更和行情更新走不同刷新路径

二、指标计算顺序要固定

生产上要明确“依赖顺序”,不能随意调整。

推荐顺序:

  1. 输入 List<KLineEntity>
  2. 计算 MA
  3. 计算 BOLL(依赖 MA)
  4. 计算 Volume MA
  5. 计算 KDJ
  6. 计算 MACD
  7. 计算 RSI
  8. 计算 WR
  9. 计算 SuperTrend
  10. 结果回填到每个 KLineEntity
  11. 渲染层直接读取实体字段

建议把顺序写进统一入口方法,避免外部随意单独调用。


三、更新策略:全量与增量必须分流

这是性能分水岭。

1) 全量计算(初始化/切参数)

  • 场景:首次加载历史数据、用户修改指标参数
  • 策略:完整跑一遍指标链路

2) 增量计算(实时推送)

  • 场景:WebSocket 新增一根,或更新最后一根未收线 K
  • 策略:只重算受影响尾部区间,不重跑全历史

实践建议:

  • 新增一根:走 addLastData(...)
  • 更新末根:走 updateLastData(...)
  • 配置变化:强制全量

不要混用,否则很容易出现“偶发指标跳变”。


四、算法实现的性能要点

1) 滚动窗口优先

均线、方差这类窗口指标,优先使用滑动累积变量。
例如 BOLL 的方差计算可维护 sumClose2,避免每步重新遍历窗口。

2) 避免重复数学开销

log/exp、格式化、字符串拼接都放在计算后或展示层,
不要在每帧、每点位重复做。

3) 结果就地回填

计算结果直接写回数据实体,渲染阶段只读取。
这样可避免渲染期再做派生计算。


五、配置管理最佳实践

推荐做法:

  • 配置快照注入计算器,不直接依赖可变全局 Map
  • 参数改动有明确版本号,触发全量重算
  • 配置存储只负责持久化,不直接触发 UI 与计算耦合逻辑

六、并发与线程策略

当数据规模大到几千到上万根时,建议:

  • UI 线程只做增量计算
  • 参数变更触发的全量计算下放 isolate
  • 计算完成后一次性回传结果快照,避免碎片化 setState

七、测试与验收标准

指标引擎必须有自动化对照测试,至少覆盖:

  • 全量计算结果一致性(固定输入 -> 固定输出)
  • 增量与全量一致性(同一尾部数据,结果相同)
  • 边界数据(空数据、单点、超长窗口、异常值)
  • 参数变更后的重算正确性

工程上建议补两类基准:

  • 10k 数据全量耗时
  • 高频实时更新(例如 10Hz)下的帧稳定性

八、常见错误清单(建议直接排查)

  1. 每次推送都全量重算
  2. 计算层读写全局可变状态
  3. 渲染阶段临时算指标
  4. 参数变化不触发全量重算
  5. 增量路径未覆盖“更新最后一根”场景

总结

指标模块的最佳实践可以压成三句话:

  • 计算顺序固定,渲染只消费结果
  • 全量与增量分流,实时更新永不全量
  • 配置注入与自动化测试先行,保证可维护和可验证

把这三条做到位,K 线在复杂业务下也能稳定、可控、可扩展。