【免费下载链接】Vela
Fast, extensible financial charts for the web. The open-source core of Vela by LuxAlgo.
Vela是由 LuxAlgo 开源的金融图表库(Fast, extensible financial charts for the web),它用"一个核心 + 三层扩展 + 三个端口"的架构,让行情数据、指标脚本、渲染后端可以各自独立替换——这正是它又快又稳的底层原因。本文将用尽量少的代码,带你 10 分钟看懂这套设计的核心秘密 🧩。
Vela 是什么:一个可自由"换零件"的金融图表库
大多数图表库把"取数据、算指标、画屏幕"三件事写死在一起。Vela 反其道而行:
- 核心(Core):只做编排,不认识任何具体后端;
- 三个扩展层(Layers):数据源(Data providers)、脚本引擎(Scripting engines)、渲染器(Renderers);
- 三个端口(Ports):每层通过唯一一个窄接口接入核心。
这意味着:换一家行情 API、换一个 Pine Script 运行环境、甚至把 WebGL2 渲染器整个换成 Canvas 实现,核心代码和其他两层都毫不知情。
Vela 工作区:同一个核心驱动多张图表、多种指标与成交量分析
全局架构:一核三层三端口
先看整体形状(引自官方架构文档 docs/architecture/overview.md):
| 层(Layer) | 端口(Port) | 职责 |
|---|---|---|
| 数据提供商层 | MarketDataFeed | 提供历史 K 线与实时 tick |
| 脚本引擎层 | ScriptingEngine | 解析并执行指标脚本 |
| 渲染器层 | IChartRenderer | 把数据模型画成像素 |
三个端口的合同定义就放在 src/core/ports/ 目录下,非常精炼:
- 行情端口:src/core/ports/MarketDataFeed.ts
- 引擎端口:src/core/ports/ScriptingEngine.ts
- 渲染端口:src/core/ports/IChartRenderer.ts
核心只"对着合同说话",从不点名任何具体实现。箭头永远从核心指向端口,而不是指向某层内部的某个类。
核心是唯一的"总指挥":它独占两件事
核心并不是薄薄一层转发器。按 docs/architecture/data-flow.md 的说法,核心直接拥有两样东西:
规范 K 线数组(canonical bar array)核心是主行情数据唯一的加载者和流式订阅者。引擎不会自己去拉数据,它只能被"喂"一份快照;渲染器也不拉数据,它只负责"画"。所有已注册的引擎共享同一份数据集,避免了每个引擎重复请求。
编排循环(orchestration loop)加载、绘制、按语言选择引擎、把输出路由到正确的面板(pane)、打上稳定身份 ID、每个 tick 推送更新——"什么时候做、按什么顺序做"全部由核心决定。具体编排逻辑集中在 src/core/engine/EngineOrchestrator.ts 中。
这一条单一所有权原则,是三层能保持"窄"的根本原因:层与层之间不互相协调,全靠核心协调。
三个端口逐个拆:窄合同如何约束每一层
1️⃣ MarketDataFeed:数据的唯一入口
行情合同只有两个必需能力 + 两个可选能力:
- 必需:加载历史(
load)、订阅实时 tick(subscribe); - 可选:范围取数(
loadRange)、品种元数据(symbolInfo)。
可选成员缺失时,核心会回退到定义好的行为(比如退化为全量加载),而不是行为未定义——所以一个"最简数据源"也永远是合法数据源。
默认的行情实现是**"带缓存的装饰器"**:内置数据源外面包一层内存缓存(src/data/MultiProviderFeed.ts),重复请求不再打穿到交易所 API。缓存对核心完全透明,核心分不清自己在和缓存说话还是在和裸数据源说话。
2️⃣ ScriptingEngine:指标执行的窄表面
引擎合同极其克制,只有:语言 id + 能力声明 + 两个方法:
- Prepare:廉价解析脚本,返回输入参数 schema 和元数据,完全不碰行情数据;
- Execute:在 K 线快照上运行,返回一个执行会话句柄,结果通过回调流出。
脚本需要的次级数据(比如跨品种、跨周期的序列)也不许自己走网络,必须走核心提供的带缓存fetchSeries网关——数据进出的每一扇门,都在核心手里。
3️⃣ IChartRenderer:从模型到像素
渲染器合同围绕三组职责:
- 挂载 / 补丁 / 移除指标:按 id 幂等,tick 到来时就地打补丁;
- 管理面板:价格面板永远存在,研究指标各有自己的面板;
- 发出交互事件:十字光标、点击、视口变化等,每个都返回取消订阅句柄。
默认渲染器是自带WebGL2(canvas2d 兜底)的原生渲染器,位于 src/renderers/native/。想整体替换?给构造函数传一个自定义的IChartRenderer类即可。
中立模型:跨层流通的"世界语"
端口是"说话的地方",而中立模型(neutral model)是唯一允许跨越端口边界的东西——K 线、序列、面板、绘图、输入、更新补丁,全部用"不隶属任何后端"的术语描述。
它有两个关键约定:
- 后端内部类型绝不外泄。数据源交出的是中立 K 线,引擎吐出的是中立指标模型,渲染器接收的是中立指令;
- 时间统一为 epoch 毫秒。每个渲染器在自己的边界处自行换算,核心从不去迁就某个后端的时钟。
不透明(opacity)就是全部的意义:换渲染器不用碰引擎,加数据源也不用教会渲染器任何新东西。
为什么"默认不带脚本引擎"?这是一个刻意的决定
新图表打开时:渲染器必有(否则没东西看)、数据源必有(否则没有 K 线),但脚本引擎刻意缺席——裸图表只有 K 线,脚本能力是opt-in。
原因写在 ADR 里:指标执行是重且与语言强相关的负载。如果你请求了一个未注册引擎的语言,核心会抛出可操作的错误而不是猜。想跑 Pine Script,就安装独立包@luxalgo/vela-pinets(进程内版 + Web Worker 流式版);不想引入第三方语言运行时和许可证依赖,就什么都不装。
这一决策的完整论证见 docs/architecture/adr/0003-no-default-scripting-engine.md。
能力协商:核心"只信声明,从不猜测"
端口很窄,但后端能力参差不齐。Vela 的解法是能力声明(capabilities)+ 核心无条件信任:
- 引擎声明:能否流式(持久会话)、是否感知视口、是否暴露输入;
- 渲染器声明:面板、填充、标记、绘图、表格、逐点颜色、输入 UI……
核心拿到声明就按它路由。典型例子——走实时流式路径必须同时满足:图表处于 live 状态、脚本不依赖视口、引擎声明了 streaming;少一条就回退为"每次 bar 变化重新执行"的静态路径。两条路径最终都落到同一个中立模型上。
⚠️ 因此"如实声明"是合同的一部分:虚报能力会产生静默错误的输出,因为核心照单全收。
这套设计如何换来"快"与"稳"
| 设计决策 | 带来的收益 |
|---|---|
| 核心独占 K 线数据 | 单一数据源、单一事实来源,无重复拉取,行为可预测 |
| 内容寻址的稳定 ID | tick 到达时就地打补丁,而不是拆掉重建,实时更新开销极低 |
| 窄端口 + 中立模型 | 换任何一层都不波及其他两层,回归风险小 |
| 无默认引擎 | 包体不背语言运行时,按需 opt-in |
| Import ACL(导入访问控制列表) | 分层不是靠自觉,而是lint 机械强制:违规 import 直接构建失败 |
最后一条尤其值得新手注意:很多项目的"分层"只是文档里的约定,Vela 用 ADR 0004 把边界写进了工具链——脚本语言工具链在任何位置都不许被 import,自定义渲染器的图表依赖只能留在自己的渲染器目录里。边界是"被执行的规则",架构才敢长期维持。
延伸阅读:从哪里继续深挖
- 架构总览(一图看懂一核三层三端口):docs/architecture/overview.md
- 端口合同与合成根详解:docs/architecture/modules.md
- 数据端到端流转追踪:docs/architecture/data-flow.md
- 边界与不变量清单:docs/architecture/boundaries.md
- 架构决策记录(为什么这样设计):docs/architecture/adr/README.md
- 合成根(唯一允许导入具体后端的入口):src/Vela.ts
- 贡献指南(如何扩展):docs/contributing/
小结
Vela 架构的"秘密"其实不复杂,只有一条主线:核心独占数据并负责编排,三层各自守着一个窄端口,中立模型是唯一流通的货币。快,来自"单一数据源 + 稳定 ID 就地补丁";稳,来自"端口隔离 + lint 强制边界"。理解了这一点,无论你要换数据源、加引擎还是写自定义渲染器,路径都清晰可预测 ✅。
【免费下载链接】Vela
Fast, extensible financial charts for the web. The open-source core of Vela by LuxAlgo.
相关推荐
image库API设计哲学:为什么这样的接口设计能够提高开发效率
image库API设计哲学:为什么这样的接口设计能够提高开发效率 探索Rust图像处理库的精妙设计,了解如何通过统一的接口设计大幅提升开发效率 🚀 在当今的软
图像处理FastAPI WebSocket:掌握连接状态管理的完整指南
FastAPI WebSocket:掌握连接状态管理的完整指南 FastAPI 作为一款高性能、易学习的现代 Python Web 框架,提供了强大的 WebS
后端Web框架API设计Lightweight Charts源码架构深度解析:高性能金融图表的核心设计
Lightweight Charts源码架构深度解析:高性能金融图表的核心设计 Lightweight Charts是TradingView推出的高性能金融图表
前端图表库金融科技数据可视化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考