所有重要的项目更改都将记录在此文件中。
问题:设定分钟级/秒级 K 线时,时间轴只显示日期(如 2026-07-08),不显示时间。
根因:JS 端 _interval 初始化为 86400(1天)后从未更新,timeFormatter 中 this._interval >= 86400 永远为真,始终走"只显示日期"分支。
修复:共修改 2 个文件
| 文件 | 变更 |
|---|---|
lightweight_charts/abstract.py |
新增 _sync_interval_to_js() 方法,在 set_period() 和 set() 中调用,将 self._interval 同步到 JS 端并动态设置 secondsVisible |
lightweight_charts/js/bundle.js |
timeFormatter 新增秒级分支,_interval < 60 时显示 HH:MM:SS |
| 时间级别 | 间隔 | 轴刻度 | 标签格式示例 |
|---|---|---|---|
| 日线+ | >= 86400s |
关闭秒 | 2026-07-08 |
| 分钟级 | 60~86399s |
关闭秒 | 2026-07-08 14:30 |
| 秒级 | < 60s |
开启秒 | 2026-07-08 14:30:45 |
[v3.1.0] - 2026-07-07
新增 chart_model/ 子包,提供一个声明式、扁平化、引用式的纯数据图表模型,与渲染层完全解耦。
| 功能 | 说明 |
|---|---|
| Model / Window / Chart / Series | 声明式结构定义,dataclass 实现 |
| Layout | build() 构建只读关系图,含 pane 分组、主序列映射、引用校验 |
| Adapter.render() | 将 Layout 翻译为 lightweight-charts 渲染实例,支持单/多 Window |
| SeriesAccessor | model['name'].set/append/pop/add_marker 链式数据操作 |
| DrawingManager | model.drawing.add/delete/help 5 种画线类型管理 |
| live 同步 | 版本号追踪 + 互斥锁 + 三路同步(增量/全量/单条) |
| 8 种 Series 类型 | candle / ohlc_bar / line / area / baseline / histogram / volume / open_interest |
| 示例 | 说明 |
|---|---|
examples/01_hello_world/ |
最小闭环:1 Chart × 2 pane + live 同步 |
examples/02_multi_window_dashboard/ |
多窗口仪表盘:2 Window × 5 Chart × 22 Series |
examples/03_drawing_live/ |
画线工具:5 种类型 + 动态增删同步 |
- 目前只提供了基本功能支持,API 可能尚未定型
- 建议参考使用,不太推荐直接使用
- 详见
chart_model/CHART_MODEL_DESIGN.md
根因:candle_style() 中 _apply_options 使用 locals() 获取参数值,但 wick_up_color / wick_down_color 等参数默认值为 ''(空字符串)。方法正确计算了 self.wick_up_color = wick_up_color if wick_up_color else up_color 回退值,但 locals() 中仍是原始空字符串,导致 JS 端收到 "wickUpColor": "",渲染为黑色。
修复:_apply_options 改为使用 self. 实例属性值,确保回退值被正确发送到 JS 端。
| 重构 | 说明 |
|---|---|
ind_sys → chart_model |
子包包名更名(indicator system → chart model) |
System → Model |
根类更名,与包名一致 |
SystemLayout → Layout |
构建结果类名精简 |
| 示例目录更名 | 1_minimal → 01_hello_world,2_demo → 02_multi_window_dashboard,3_drawing → 03_drawing_live |
- 主 README 新增
chart_model子包介绍,说明其作为参考原型而非可依赖库的定位 - 中英文 README 同步更新
- 所有文档文件中的残留旧引用已清理
| 文件 | 改动 |
|---|---|
pyproject.toml |
版本号 3.0.1 → 3.1.0 |
lightweight_charts/series.py |
candle_style() 修复空字符串引线颜色 bug |
chart_model/ (新子包) |
全部文件(~20 个 .py/.md,完整子包) |
README.md / README_EN.md |
新增 chart_model 章节 |
根因:pop() 只调了 JS 端的 series.pop(N),但 Python 端的 self.data、self._last_bar、self.markers 均未同步更新,导致 chart.data 等属性与实际渲染不一致。
修复内容:
self.data:同步截断为iloc[:keep_count]self._last_bar:同步更新为新的最后一行(全删则置None)self.markers:过滤掉指向被删数据的 marker(Python dict + JS 端_update_markers()双同步)- 清理顺序:先清理 markers(依附于 series),再清理数据
- markers 按 time 升序排序:
sorted(list(self.markers.values()), key=lambda m: m['time']),避免因 markers 插入顺序与时间顺序不一致导致图表显示异常 - 空 markers 时销毁 JS seriesMarkers 对象:从
setMarkers([])改为destroy()+delete彻底销毁,避免残留
| 文件 | 改动 |
|---|---|
lightweight_charts/series.py |
pop() 新增 Python 端 data/markers/_last_bar 同步;_update_markers() 排序 + 销毁 |
pyproject.toml |
版本号 3.0.0 → 3.0.1 |
v3.0 是 lightweight-charts-python 的第一个大版本,标志着项目进入成熟稳定期。 从上次发布版本 v2.5.1 到 v3.0,经历了 15 个子版本迭代、21 天的密集开发。
核心功能覆盖率达到 ~85%,API 设计趋于完善,架构经过多轮重构验证。
| 版本 | 日期 | 定位 | 核心变更 |
|---|---|---|---|
| v2.5.1 | 06-10 | 上次发布 | HtmlTabChart iframe 嵌入、reset_sub() 子图重置 |
| v2.5.2 | 06-15 | 参数扩展 | StaticLWC 新参数支持、QUICK_REFERENCE 更新 |
| v2.5.3 | 06-15 | 布局修复 | HtmlTabChart 多子图布局溢出修复、操作柄双击重置修复 |
| v2.6.0 | 06-16 | 同步重构 | CandleSeries 独立K线系列、sync → sync_id 组同步 |
| v2.6.1 | 06-16 | 关键修复 | evaluate_js 卡死修复(;0 后缀)、消息循环终止修复 |
| v2.7.0 | 06-21 | 组合架构 | 固定 ID、VolumeSeries/OI 独立化、组合架构重构 |
| v2.7.1 | 06-21 | 清理优化 | Handler seriesMarkers 移除、_marker_auto_scale 修复 |
| v2.7.2 | 06-21 | 转发修复 | volume/OI update_bars/ticks 转发、TS 编译警告消除 |
| v2.7.3 | 06-23 | 功能增强 | Histogram 任意颜色支持、abstract.py 拆分 → series.py |
| v2.8.0 | 06-26 | 统一契约 | 统一输入列、set→update_bars 委托、normal_df 精简 |
| v2.8.1 | 06-27 | 类型扩展 | Area/OHLCBar/Baseline 三种新 Series、DrawingSeries |
| v2.8.2 | 06-28 | 绘图革新 | Pane Primitive 架构、ToolBox on_change 回调 |
| v2.8.3 | 06-30 | API 清理 | 旧别名/方法/参数全面移除、price_scale 重写 |
| v2.8.4 | 07-01 | 跨 Pane 绘图 | ToolBox 跨 Pane 自动识别、DrawingInfo 增强 |
| v2.8.6 | 07-01 | API 补全 | TimeScaleApi、PriceScaleApi、HtmlTabChart 快照重放 |
| v3.0.0 | 07-01 | 正式发布 | 确认最终 API,提供完整迁移指南 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| 同步机制 | sync=chart.id |
sync_id='组名' |
不再依赖 chart.id,改为组名字符串。True→'True',False/None→不同步 |
| 参数字段 | sync |
sync_id |
方法签名重命名 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| volume/OI 管理 | candle.attach_volume(df) |
AbstractChart 直接管理 | chart.volume/chart.oi 由 AbstractChart 创建 |
| volume/OI 创建 | candle.attach_open_interest(df) |
Chart(...) 自动创建 |
不再需要手动 attach,设置即自动创建 |
| CandleSeries delete | 级联删除附属 series | 只删除自身 | volume/OI 独立生命周期 |
| CandleSeries clear_data | 级联清空附属 | 只清自身 | AbstractChart.clear_data() 统一处理 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| 函数重命名 | update_from_tick() |
update_tick() |
旧名已在 v2.8.3 移除 |
| 函数重命名 | update_from_ticks() |
update_ticks() |
旧名已在 v2.8.3 移除 |
| 类重命名 | Line |
LineSeries |
旧名已在 v2.8.3 移除 |
| 类重命名 | Histogram |
HistogramSeries |
旧名已在 v2.8.3 移除 |
update 别名 |
series.update(s) |
series.update_bar(s) |
统一方法名 |
| normal_df 行为 | 自动小写 + date→time | 不再自动转换 | 列名必须精确匹配 |
| _lines 联动 | 自动转发数据 | 不再自动转发 | 需手动 line.set(df) |
| 输入列统一 | 各 series 格式不一致 | 统一 time + value |
VolumeSeries 需要 open/close 列 |
| cumulative_volume | update_ticks 参数 |
已移除 | 无替代 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| 回调注册 | toolbox.save_drawings_under(cb) |
toolbox.on_change += func |
支持多回调 |
| Drawing 架构 | ISeriesPrimitive |
IPanePrimitive |
直接附着到 pane |
| Ctrl+Z 撤销 | 内置支持 | 已移除 | 需自行实现 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| 持久化保存 | toolbox.save_drawings_under(w) |
用 on_change 回调 |
自行实现持久化 |
| 持久化加载 | toolbox.load_drawings(tag) |
用 on_change 回调 |
自行实现持久化 |
| 持久化导入 | toolbox.import_drawings(path) |
用 on_change 回调 |
自行实现持久化 |
| 持久化导出 | toolbox.export_drawings(path) |
用 on_change 回调 |
自行实现持久化 |
| 参数删除 | price_scale(perm_width=N) |
已删除 | 无替代 |
| 参数默认值 | price_scale() 硬编码默认值 |
默认值改为 None |
需显式传入依赖的旧默认值 |
| 变更 | 旧 API | 新 API | 迁移要点 |
|---|---|---|---|
| _drawings 列表 | chart._drawings |
chart._drawing_series |
dict {pane_index: DrawingSeries} |
| 功能 | 版本 | 说明 |
|---|---|---|
| CandleSeries 独立K线系列 | v2.6.0 | 任意 pane 上绘制独立 K 线,无 volume/OI |
| sync_id 组同步 | v2.6.0 | 基于组名的图表同步机制,替代旧配对同步 |
| VolumeSeries / OI 独立化 | v2.7.0 | 独立生命周期,由 AbstractChart 直接管理 |
| Histogram 任意颜色着色 | v2.7.3 | 每根柱子独立颜色,支持 set/update_bars |
| 统一输入契约 | v2.8.0 | 所有 Series 统一 time + value 列 |
| set→update_bars 委托 | v2.8.0 | 统一清空→委托模式 |
| Series | 说明 | 工厂方法 | 版本 |
|---|---|---|---|
| AreaSeries | 面积图(折线+渐变填充) | chart.create_area() |
v2.8.1 |
| OHLCBarSeries | 美国线(横向 OHLC 柱状图) | chart.create_ohlc_bar() |
v2.8.1 |
| BaselineSeries | 基准线(以基准值为界上下分色) | chart.create_baseline() |
v2.8.1 |
| API | 说明 | 版本 |
|---|---|---|
| TimeScaleApi | chart.time_scale_api() — 时间轴完整控制(14 方法) |
v2.8.6 |
| PriceScaleApi | chart.price_scale_api(scale_id) — 价格轴完整控制(6 方法) |
v2.8.6 |
_apply_options() |
chart/series 级统一选项入口 | v2.8.6 |
build_price_scale_options() |
snake_case→JS 驼峰纯函数 | v2.8.6 |
fit() / set_visible_range() |
复用 TimeScaleApi | v2.8.6 |
| reset_sub() | 子图内容重置,保留布局 | v2.5.1 |
| chart.show(wait=N) | 计时自动关闭窗口 | v2.8.1 |
| StaticLWC 新参数 | position/pane_index/marker_auto_scale | v2.5.2 |
| 功能 | 版本 | 说明 |
|---|---|---|
| Pane Primitive 架构 | v2.8.2 | Drawing 改为 IPanePrimitive,跨 pane 稳定渲染 |
| ToolBox on_change 回调 | v2.8.2 | += / -= 注册/卸载多回调 |
| DrawingSeries per-pane | v2.8.1 | 每个 pane 独立 DrawingSeries 管理 |
| ToolBox 跨 Pane 绘图 | v2.8.4 | 鼠标点击自动识别目标 pane |
| DrawingInfo 增强 | v2.8.4 | 新增 pane_index/time/price 字段 |
| ToolBox 生命周期管理 | v2.8.2 | _delete() + _build() 模式 |
| Legend OHLC 支持 | v2.8.1 | Bar/Candlestick 显示 O H L C |
| 功能 | 版本 | 说明 |
|---|---|---|
| init 快照重放 | v2.8.6 | new_window 重放 init 全量 JS 命令 |
| iframe 嵌入 | v2.5.1 | 双文件方案(外壳 HTML + 内容 HTML) |
| 多子图布局 | v2.5.3 | subcharts/panes/absolute 三种布局方式 |
| 操作柄双击重置 | v2.5.3 | 拖拽后双击恢复原始尺寸 |
| 改进 | 版本 | 说明 |
|---|---|---|
| abstract.py 拆分 | v2.7.3 | SeriesCommon 等移入 series.py,-45% 行数 |
| SeriesCommon.delete() 基类统一 | v2.7.3 | 5 个子类全部简化 |
| price_scale() 重写 | v2.8.3 | dict 构建 + js_json() 序列化,-80 行 |
| 子类冗余 delete() 清理 | v2.8.3 | 7 个子类纯透传全部删除 |
| 常驻系列重构 | v2.7.3 | candle/volume/oi 始终存在 |
| clear_data() 统一清空 | v2.7.3 | 基类默认实现 + 子类调用 super() |
| 测试补全 | v2.7.3/v2.8.4 | 从 3 个 → 8 个测试套件 |
| 示例 | 持续 | 从约 30 个 → 40 个 |
v2.5.x v2.6.x v2.7.x
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 旧配对同步模式 │ │ CandleSeries 独立 │ │ 组合架构重构 │
│ sync=chart.id │ ───→ │ sync_id 组同步 │ ───→ │ 固定ID + 常驻系列 │
│ attach 附属模式 │ │ CandleSeries 脱离 │ │ Volume/OI 独立化 │
│ volume/OI 捆绑 │ │ 主 chart 独立使用 │ │ series.py 拆分 │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │
v v
v2.8.0 v2.8.1-2 v2.8.3-6
┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐
│ 统一输入契约 │ │ 3种新Series │ │ API 清理 │
│ set→update_bars │──→ │ Pane Primitive│──→ │ TimeScaleApi │
│ normal_df 精简 │ │ DrawingSeries │ │ PriceScaleApi │
│ 不联动 _lines │ │ on_change │ │ 快照重放 │
└──────────────────┘ └──────────────┘ └──────────────────┘
│
v
┌──────────┐
│ v3.0.0 │
│ 正式发布 │
└──────────┘
| Bug | 修复版本 | 根因 |
|---|---|---|
| CandleSeries 边界替换 OHLC 丢失 | v2.8.6 | 旧 bar 的 open/high/low 被新 bar 覆盖 |
| time_to_bar_time 返回类型错误 | v2.8.6 | Series 输入返回 ndarray |
| HtmlTabChart 图表全背景色 | v2.8.6 | callbackFunction 未定义 |
| ReflexChart _html 内存泄漏 | v2.8.6 | _html 无限增长 |
| HtmlTabChart 多 tab legend/candle 不可见 | v2.8.6 | 旧全局变量未清理 + _build 未加防重复 |
| ToolBox _delete 顺序 | v2.8.3 | JS 清理后 Python handler 已不存在 |
| _clear_handlers 误杀其他图表 | v2.8.3 | 清空整个 Window 所有 handler |
| Legend reset_sub 后不恢复 | v2.8.2 | div.remove() 不可逆 + 重建时序错误 |
| volume/OI update_bars/ticks 不转发 | v2.8.1 | AbstractChart 只委托 candle |
| _seriesList 含 volume/OI 审计错误 | v2.8.1 | create 方法无条件 push |
| clear_data 漏清 volume/OI | v2.8.0 | 组合架构后未同步 |
evaluate_js 卡死(;0 后缀) |
v2.6.1 | pywebview 无法序列化 ISeriesApi |
| 消息循环 return 终止 | v2.6.1 | 异常处理误用 return |
| CandleSeries 标记不显示 | v2.6.1 | _update_markers 缺少 try-catch |
| HtmlTabChart 多子图布局溢出 | v2.5.3 | 容器高度 100vh 导致溢出 |
| 操作柄双击重置尺寸异常 | v2.5.3 | px/百分比混用 |
| 指标 | 数据 |
|---|---|
| Series 类型 | 7/7 ✅ (Candle / OHLCBar / Line / Area / Baseline / Histogram / Volume / OI) |
| TimeScaleApi 方法 | 14/14 ✅ |
| PriceScaleApi 方法 | 6/6 ✅ |
| 测试套件 | 8 个 ✅ |
| 示例 | 40 个 ✅ |
| 核心功能覆盖率 | ~85% |
| 总迭代版本 | 16 个版本(v2.5.1 → v3.0) |
| 开发周期 | 21 天(06-10 → 07-01) |
| 文档 | QUICK_REFERENCE.md (1886 行) + MEMORY.md (1393 行) |
| Python 源文件 | abstract.py / series.py / chart.py / widgets.py / toolbox.py / ...(~8000 行) |
| TypeScript 源文件 | handler.ts / legend.ts / toolbox.ts / drawing 引擎 / ...(大幅重构) |
- Python >= 3.8(不变)
- 核心依赖:pandas、pywebview>=5.0.5(不变)
- 可选依赖:pyside6 / pyqt5 / pyqt6 / wxpython / ipython / reflex(不变)
- lightweight-charts v5.2.0 官方引擎(不变)
- 窗口系统:Windows / macOS / Linux 均支持(不变)
-
AbstractChart
_apply_options(options)内部方法:直接调用chart.applyOptions()的通用入口,接受 JS 驼峰格式的选项字典。与 Series 级别的_apply_options()对称,用于图表级选项的灵活设置。 -
TimeScaleApi 时间轴 API:封装
chart.timeScale()的完整 API,通过chart.time_scale_api()方法访问。支持:- 滚动控制:
scroll_position(),scroll_to_position(),scroll_to_real_time() - 范围管理:
get_visible_range(),set_visible_range(),get_visible_logical_range(),set_visible_logical_range() - 视图控制:
fit_content() - 事件订阅:
subscribe_visible_logical_range_change(),subscribe_visible_time_range_change(),subscribe_size_change() - 尺寸获取:
width()
- 滚动控制:
-
AbstractChart 方法复用 TimeScaleApi:
fit()和set_visible_range()现在内部调用time_scale_api(),代码更简洁,逻辑复用。 -
AbstractChart.price_scale() 重构:从委托到
candle.price_scale()改为使用PriceScaleApi,支持指定价格轴 ID('left' 或 'right')。默认配置右侧价格轴。 -
QUICK_REFERENCE.md 更新:新增 3.8.2.1 章节,包含 TimeScaleApi 与 PriceScaleApi 的完整方法对比表格。
-
build_price_scale_options() 纯函数:将 Python snake_case 参数转换为 JS 驼峰格式的选项字典。供
SeriesCommon.price_scale()和PriceScaleApi.apply_options()复用。 -
PriceScaleApi 价格轴 API:封装
chart.priceScale()的完整 API,通过chart.price_scale_api(scale_id)方法访问。支持:- 选项管理:
apply_options(**kwargs)(使用 snake_case 参数) - 范围控制:
get_visible_range(),set_visible_range(),set_auto_scale() - 尺寸获取:
width()
- 选项管理:
-
SeriesCommon.price_scale() 重构:简化为使用
build_price_scale_options()纯函数,代码量从 ~80 行减少到 ~5 行。
- HtmlTabChart
new_window()重构为 init 快照重放:__init__末尾保存self._init_html = self._html(init 阶段全量 JS 命令快照)new_window()直接self._html = self._init_html重放完整 init 命令- 删除 6 行手动
_build()/run_script/toolbox._build()代码 - 自动覆盖所有 init 组件(candle/volume/oi/toolbox + 未来新增)
-
ReflexChart
_html内存泄漏:run_script每次调用都通过super()追加到self._html,永不清理。引入_html_frozen机制,to_reflex()后冻结_html,后续只走_pending通道。_html恒定 ~28 KB,_pending每次flush()后清空。 -
HtmlTabChart + ToolBox 图表全背景色(波及所有静态图表子类):
- 根因:
window.callbackFunction在静态 HTML 中未定义。DrawingTool初始化时触发回调调用,抛出TypeError,导致setData/update等数据加载代码未执行,图表数据为 0。 - 修复:
StaticLWC.__init__统一加self.run_script('window.callbackFunction = function(){};')。HTMLChart、JupyterChart、StreamlitChart等所有静态图表组件自动受益。
- 根因:
| 文件 | 改动 |
|---|---|
lightweight_charts/widgets.py |
StaticLWC.__init__ 加 callbackFunction 空函数 + HtmlTabChart.__init__ 加快照 + new_window() 重放 + get_html() 安全网 |
lightweight_charts/reflex_chart.py |
_build_html() 将 messaging 移到 IIFE 之后 + _html_frozen 机制防止 _html 无限增长 |
- HtmlTabChart 多 tab legend/candle 修复:切换 tab 后第二个及后续 tab 的 candle 不可见、legend 静态不更新。
- 根因:
updateChart(id)清空容器但不清除 JS 全局变量(window.{prefix}_candle/volume/oi),新 Handler 创建新 chart 后 series 全局变量仍指向旧的已销毁对象。_build()只在__init__中调用一次,后续 tab 的set()无法重建 series。 - 修复:
get_html()切换 tab 前先delete旧全局变量;_build()加if (!{id})防重复;set()开头调_build()+ handler 引用赋值。
- 根因:
- HtmlTabChart legend 只显示眼睛图标:
makeSeriesRow创建的 div 为空,只在legendHandler(crosshair 移动)中才填充。后续 tab 切换后 crosshair 未触发,div 一直空着。修复:创建 div 后立即设置初始内容■ 系列名。
| 文件 | 改动 |
|---|---|
lightweight_charts/widgets.py |
get_html() 新增切换 tab 前清理旧全局变量 |
lightweight_charts/series.py |
CandleSeries/VolumeSeries/OpenInterestSeries _build() 加 if (!{self.id}) |
lightweight_charts/abstract.py |
set() 开头调 _build() + handler 引用赋值 |
src/general/legend.ts |
makeSeriesRow() 设置 div 初始内容 |
- ToolBox 跨 Pane 绘图:ToolBox UI 固定在 Pane 0,但鼠标点击哪个 pane 就在哪个 pane 上创建 drawing。利用
MouseEventParams.paneIndex自动识别点击目标 pane。 DrawingInfo增强:新增pane_index、start_time、start_price、end_time、end_price字段,回调信息更完整。
CandleSeries缺失group参数:create_candle_series(group=...)传 group 但CandleSeries.__init__不接受,导致TypeError。已补上并透传给SeriesCommon.__init__。
test/run_tests.py:补上遗漏的test_volume_series.py(8/8 test suites)。
| 文件 | 改动 |
|---|---|
src/drawing/drawing-tool.ts |
新增 _resolvePane(param);_onClick 解析目标 pane |
src/general/toolbox.ts |
saveDrawings 附加 paneIndex |
lightweight_charts/toolbox.py |
DrawingInfo 增加 pane_index + time/price 字段 |
lightweight_charts/series.py |
CandleSeries.__init__ 补 group 参数 |
test/run_tests.py |
加入 test_volume_series.py |
examples/40_toolbox_multi_pane/ |
3 pane ToolBox 示例 |
Line/Histogram别名已移除:使用LineSeries/HistogramSeries代替。update_from_tick()/update_from_ticks()已移除:使用update_tick()/update_ticks()代替。update = update_bar别名已移除:使用update_bar()或update_bars()代替。price_scale()参数perm_width已移除:官方 API 中不存在此字段。- ToolBox 方法移除:
save_drawings_under()、load_drawings()、import_drawings()、export_drawings()已移除。使用on_change回调自行实现持久化。
SeriesCommon.price_scale()重写:f-string 拼接改为 dict 构建 +js_json()序列化,可读性和可维护性大幅提升。同时修复了borderColor/textColor引号拼接 bug(旧代码未对值加引号)。SeriesCommon.price_scale()参数默认值改为None:所有参数不再硬编码默认值,不传则由 JS 端使用官方默认值。scale_margin_top/scale_margin_bottom互锁:必须同时指定或同时省略。CandleSeries.price_scale()删除:与SeriesCommon.price_scale()完全相同,改为直接继承,减少 ~60 行重复代码。price_scale()新增参数ensure_edge_tick_marks_visible:始终在价格轴顶部和底部绘制刻度线。- ToolBox
_delete()顺序修复:先 JS 清理再移除 Python handler,避免 JS 清理过程中触发的回调找不到 handler。 - 子类冗余
delete()清理:7 个子类的delete()纯透传 override 全部删除,直接继承 SeriesCommon。 _apply_options()通用方法:SeriesCommon 新增_apply_options(options)统一series.applyOptions()入口。- 测试修复:
_clear_handlers()→_remove_my_handlers(),避免多图表场景误杀其他图表的 handler。
| 旧 API | 新 API |
|---|---|
Line(...) |
LineSeries(...) |
Histogram(...) |
HistogramSeries(...) |
series.update_from_tick(s) |
series.update_tick(s) |
series.update_from_ticks(df) |
series.update_ticks(df) |
chart.update_from_tick(s) |
chart.update_tick(s) |
chart.update_from_ticks(df) |
chart.update_ticks(df) |
series.update(s) |
series.update_bar(s) |
chart.update(s) |
chart.update_bar(s) |
chart.price_scale(perm_width=N) |
已删除,无替代 |
chart.toolbox.save_drawings_under(w) |
用 on_change 回调自行实现 |
chart.toolbox.load_drawings(tag) |
用 on_change 回调自行实现 |
chart.toolbox.import_drawings(path) |
用 on_change 回调自行实现 |
chart.toolbox.export_drawings(path) |
用 on_change 回调自行实现 |
注意:
price_scale()参数默认值从硬编码值改为None。如果你依赖旧默认值(如border_visible=False、scale_margin_top=0.2),需要显式传入。
- ToolBox 回调重构:新增
chart.toolbox.on_change += func/-= func回调注册方式。回调签名为func(drawings: list[DrawingInfo])。旧的save_drawings_under持久化机制已在 v2.8.3 移除。 - Ctrl+Z 撤销移除:ToolBox 不再监听 Ctrl+Z 撤销快捷键。
- ToolBox 生命周期:
_cleanup()方法已移除,改用_delete()(销毁)/_build()(重建)模式。
- Pane Primitive 架构:Drawing 从
ISeriesPrimitive改为IPanePrimitive,直接附着到 pane 而非 series。- 新文件
src/pane-plugin-base.ts:实现IPanePrimitive接口 - 所有 pane 的 drawing 都可见,不再依赖 series 数据状态
- 坐标转换通过
pane.getSeries()[0].coordinateToPrice()实现
- 新文件
- ToolBox on_change 回调系统:
_CallbackList支持+=/-=注册/卸载多个回调 - ToolBox DrawingInfo 追踪:
chart.toolbox.drawings_list返回当前所有 drawing 的元信息(id/type/points/options) - ToolBox 生命周期管理:
_delete()销毁 JS toolBox + 清空所有状态,_build()注册 handler + 创建 JS toolBox - 跨 pane 拖拽修复:
_isMouseInMyPane()利用MouseEventParams.paneIndex检查鼠标所在 pane,拖拽中不检查边界 - RayLine 数据范围外可拖拽:坐标转换 null 时跳过该维度检查,不再直接 return false
- show(wait=N) 消息循环修复:改为后台超时线程 + 主线程运行
show_async(),JS 回调正常触发 - Audit 补充:Python 端新增 volume_oi/toolbox/drawing_series/interval/offset/period_locked,JS 端新增 paneCount/pane.N.seriesCount/pane.N.height/toolboxDrawings/toolboxHasOnChanged
__init__AttributeError:移除__init__中多余的self.toolbox._build()调用(在self.toolbox赋值之前引用)- reset() handler 恢复:
_save_drawings→_on_callback(方法重命名后未同步) - reset_sub() toolbox 重建:销毁后自动
_build()重建
- DrawingSeries 精简:移除
_ensure_js_series和 dummy 数据,仅作 per-pane drawing 管理器(~70 行) - ToolBox 不再创建独立 DrawingSeries:直接使用主 chart 的 pane(
chart.panes()[0])
- Drawing 重构:
chart._drawings列表已移除,改为chart._drawing_series字典({pane_index: DrawingSeries})。chart.drawings属性保留兼容性,遍历所有 pane 的 drawing 列表。
-
DrawingSeries 绘图管理重构:每个 pane 拥有独立的
DrawingSeries(Pane)管理 drawing 对象- 新文件
drawing_series.py:惰性创建不可见 JS LineSeries,5 个工厂方法 - AbstractChart 用
_drawing_series字典按 pane_index 管理 - ToolBox 持有独立的 DrawingSeries,与 chart 完全隔离
- Drawing 基类改为持有
drawing_series(不再直接持有 chart) - 工厂方法新增
pane_index参数:chart.horizontal_line(price, pane_index=1)
- 新文件
-
chart.show(wait=5):显示窗口后等待指定秒数自动关闭,适用于截图/演示场景- 内部使用
Process.join(timeout=wait)替代time.sleep,窗口被用户关闭时会提前返回 - PyWV 事件循环在
queue.get超时后增加is_alive二次检查,窗口关闭后最多等待 2 秒即退出
- 内部使用
-
AreaSeries(面积图):折线+渐变填充,支持 topColor/bottomColor/relativeGradient/invertFilledArea
- 工厂方法:
chart.create_area(name, color, style, width, top_color, bottom_color, ...) - Python 类:
AreaSeries(SeriesCommon),数据输入与 LineSeries 完全一致(time + value) - 全部继承 SeriesCommon 的 set/update_bars/update_ticks/delete/marker
- 示例:
examples/37_more_series_types/
- 工厂方法:
-
OHLCBarSeries(美国线):横向 OHLC 柱状图,open 左 close 右
- 工厂方法:
chart.create_ohlc_bar(name, up_color, down_color, open_visible, thin_bars, ...) - Python 类:
OHLCBarSeries(CandleSeries),继承 CandleSeries 共享全部 OHLC 数据处理逻辑 - 覆盖
__init__(调 createOHLCBarSeries)+_build()+bar_style()(美国线专属样式) - 覆盖
candle_style()抛出 AttributeError 提示使用bar_style() - 数据输入与 CandleSeries 完全一致(time + open + high + low + close)
- 示例:
examples/37_more_series_types/
- 工厂方法:
-
BaselineSeries(基准线):以基准值为界上下分色
- 工厂方法:
chart.create_baseline(name, base_value, top_fill_color1/2, bottom_fill_color1/2, ...) - Python 类:
BaselineSeries(SeriesCommon),数据输入为 time + value - 全部继承 SeriesCommon 的 set/update_bars/update_ticks/delete/marker
- 示例:
examples/37_more_series_types/
- 工厂方法:
-
Legend OHLC 支持:legend.ts 的
legendHandler新增对 Bar/Candlestick 类型 series 的 OHLC 格式显示- lines 遍历中根据
seriesType()判断:Bar/Candlestick →O ... | H ... | L ... | C ... - 修复 OHLCBarSeries 在 legend 中只显示眼睛图标无内容的问题
- lines 遍历中根据
- handler.ts import:新增 AreaSeries、BarSeries、BaselineSeries 及其 StyleOptions 类型导入
- handler.ts SKIP_KEYS:新增
createAreaSeries、createOHLCBarSeries、createBaselineSeries - handler.ts GLOBALS_RE:新增
AreaSeries_\d、OHLCBarSeries_\d、BaselineSeries_\d模式 - series.py:新增 AreaSeries、OHLCBarSeries、BaselineSeries 三个类
- abstract.py:新增
create_area_series()、create_ohlc_bar_series()、create_baseline_series()工厂方法 - init.py:导出 AreaSeries、OHLCBarSeries、BaselineSeries
- OHLCBarSeries 继承 CandleSeries:两者 95% 代码相同(OHLC 数据处理),仅 JS 创建方法和样式配置不同。通过覆盖
__init__/_build()/bar_style()+ 覆盖candle_style()抛错,避免 ~80 行重复代码 - AreaSeries/BaselineSeries 继承 SeriesCommon:与 LineSeries 相同的数据输入(time + value),只需覆盖
__init__调不同的 JS 创建方法 - legend OHLC 支持:在 legendHandler 的 lines 遍历中,通过
seriesType()检测 Bar/Candlestick 类型,显示 OHLC 四个数字而非 value
- PyWV 事件循环退出延迟:窗口关闭后
_event_loop最多等待 4 秒才退出(queue.get2s +while2s)。修复:在queue.get超时后增加is_alive二次检查,窗口关闭后最多 2 秒即退出 chart.show(wait=N)提前返回:旧实现用time.sleep(wait)傻等,用户关窗口后仍需等满 N 秒。修复:改用Process.join(timeout=wait),进程结束时立即返回
- 函数重命名:
update_from_tick()→update_tick(),update_from_ticks()→update_ticks()(旧名已在 v2.8.3 移除) - 类重命名:
Line→LineSeries,Histogram→HistogramSeries(旧名已在 v2.8.3 移除) - normal_df 精简:不再自动将列名转为小写,不再自动将
date列重命名为time - AbstractChart 不联动 _lines:
set()/update_bars()/update_ticks()不再自动转发数据给 Line/Histogram - 统一输入列:所有系列的
set()/update_bars()/update_ticks()统一接受time+value列 - VolumeSeries 要求 open/close:
_prepare_vol_df要求open/close列用于涨跌着色,缺失时抛ValueError - 移除 cumulative_volume:
AbstractChart.update_ticks()不再接受cumulative_volume参数
chart.data始终 7 列:返回time, open, high, low, close, volume, open_interest,缺失系列对应列填 NaNchart.vol_data:只返回time, value(不暴露 open/close/color)chart.oi_data:返回time, value- VolumeSeries 维护 open/close:
self.data存储time, value, open, close, color,tick 累积时保留 open、更新 close、重算 color - VolumeSeries.update_ticks 自动聚合 open/close:从 tick 的
price列聚合open(first)/close(last) 供着色
- SeriesCommon set→update_bars 委托:
set()简化为清空 + 委托update_bars()+ markers,约 8 行 - SeriesCommon update_bars 智能分支:空数据用
setData批量写入(高效),有数据用 per-rowupdate - OpenInterestSeries 大幅精简:删除 ~90 行重复代码,
set/update_bars/update_ticks/delete全部继承自 SeriesCommon - OI 只保留
__init__+_build+config:三个特有方法,其余全部继承 - VolumeSeries _prepare_vol_df:输出从
time, value, color扩展为time, value, open, close, color - AbstractChart.update_ticks 转发:candle 用
price→value,volume 用volume→value+open/closefromprice,OI 用open_interest→value - AbstractChart.reset() 清理:移除重复的
series.data = pd.DataFrame(),markers.clear()移入循环 lines()返回类型:list[LineSeries]→list[SeriesCommon]vertical_span:不再绕道self.candle._single_datetime_format,直接用self._single_datetime_format
- Histogram 任意颜色支持:Histogram 内置
_option_columns=['color'],set/update_bars 时若输入 DataFrame 中存在color列则自动携带到 JS 端,支持每根柱子独立着色- 新增
_check_value_name_conflict_and_rename()方法:统一处理 value 列和系列名的冲突检测与重命名 - 方法返回新 df(非 inplace),防止多 line 共享同一个 df 时互相污染
SeriesCommon.set()和update_bars()均支持_option_columns参数- 新增示例
examples/36_histogram_colors/:买卖量差正负渐变色演示
- 新增
-
AbstractChart 常驻系列重构:
candle/volume/oi始终存在(reset 后自动重建),消除所有if self.volume:/if self.oi:/if self.candle else守卫代码reset()末尾自动重建三者(CandleSeries / VolumeSeries / OpenInterestSeries)并重新赋值 Handler 引用set()移除 10 行"检测并重建被 reset() 删除的 series"代码块update_bars()/update_from_ticks()/clear_data()各移除 None 守卫,只保留'volume' in df.columns列检查candle_data/data/markers三个属性去掉if self.candle else三元判断hide_data()/show_data()去掉 volume/oi 的 None 守卫- 类 docstring 从"可选挂载"改为"始终存在"
-
SeriesCommon.clear_data() 统一清空逻辑:基类新增
clear_data()方法(清空 JS 数据 + 重置self.data+clear_markers())- VolumeSeries / OpenInterestSeries 继承基类默认实现,无需额外定义
- CandleSeries
clear_data()改为super().clear_data()+ 清理candle_data和_last_bar - AbstractChart
clear_data()简化为统一调用三个系列的clear_data()
-
abstract.py 拆分:SeriesCommon + VolumeSeries + OpenInterestSeries + CandleSeries 移入新文件
series.py(1198 行),abstract.py 从 2795 行缩减到 1553 行(-45%),零继承链变化 -
SeriesCommon.delete() 基类统一:基类新增
delete()方法(clear_markers + 重置 _last_bar/data + JS 清理),5 个子类(Line/Histogram/VolumeSeries/OI/CandleSeries)全部简化为super().delete()- 修复 Line/Histogram 的 JS bug:
{self.id}legendItem变量名含.导致 JS 语法错误,统一为var _legendItem - delete 时调用
clear_markers()清除 Python 和 JS 端标记,防止 removeSeries 失败后残留
- 修复 Line/Histogram 的 JS bug:
-
三个系列类 _build() 提取 + 参数存储:CandleSeries / VolumeSeries / OpenInterestSeries 的
__init__将 JS 创建逻辑提取到_build()方法,构造参数存储为实例属性config()/candle_style()同步更新 Python 属性 + JS,确保_build()重建时使用最新值
-
CandleSeries candle_data → data 合并:移除
self.candle_data,统一使用基类的self.data,消除每次更新的.copy()开销AbstractChart.candle_dataproperty 保留兼容性,返回self.candle.data
-
CandleSeries 删除多余 volume/OI 检测:
update_from_ticks()中移除 ~20 行 volume/OI 聚合逻辑(CandleSeries 只处理 OHLC,聚合后会被update_bars()丢弃) -
AbstractChart toolbox 始终存在:
self.toolbox = ToolBox(self) if toolbox else None,不再使用hasattr检查- ToolBox 新增
clear_drawings()/reposition_drawings()方法,封装 JS 细节
- ToolBox 新增
-
run_tests.py 补全:新增 4 个缺失测试(test_candle_series / test_data_aggregation / test_position / test_reset_sub),现在 7/7 test suites 全部覆盖
-
update()/update_batch()/update_from_ticks()不转发 volume/OI 给独立 series:v2.7.0 组合架构重构后,AbstractChart.update_batch(df)只委托给self.candle.update_batch(df),后者只处理 OHLC 列,volume/OI 数据被静默丢弃。set()正确转发了 volume/OI,但更新方法遗漏了update():新增 volume/OI 转发给self.volume/self.oiupdate_batch():新增 volume/OI 转发给self.volume/self.oiupdate_from_ticks():重写——先在 AbstractChart 层聚合 volume/OI 转发给独立 series,再将不含 volume/OI 的 DataFrame 交给 CandleSeries 处理 OHLC,避免 volume 被重复聚合update_from_tick():委托给update_from_ticks()统一处理,避免重复转发update_bar/update_bars别名:从property(lambda: self.candle.xxx)改为普通方法,委托给update()/update_batch(),确保 volume/OI 转发不被绕过
-
CandleSeries.set()调用time_to_bar_time()缺少参数:直接调用模块级函数缺少offset/interval,改为self._chart._time_to_bar_time(df) -
TypeScript 编译警告消除(11 → 0):v2.7.0 重构将
Handler.series改为ISeriesApi | null(惰性创建),但使用处缺少 null guard,导致 11 个 TS2345/TS2531 警告createToolBox():添加if (!this.series) return提前返回syncChartsAll×2:crosshair 回调中对source.series和target.series添加 null guardsyncCharts:crosshairHandler()顶部加if (!chart.series) return;getPoint()签名改为series: ISeriesApi | null,内部 guard_syncCharts:crosshair 回调中对chart.series和target.series添加 null guardlegend.ts legendHandler():顶部加if (!this.handler.series) return- 所有 guard 均为防御性编程——运行时 series 一定已设置(Python 端先创建,用户交互在后)
- 问题:v2.7.0 重构后,Handler 的
seriesMarkers属性从未被功能性使用——Python 勤奋赋值,JS 端从不读取(audit 中的markersCount因.length不存在永远返回 0) - 清理内容:
- JS:移除
seriesMarkers属性声明、构造函数初始化、SKIP_KEYS 条目、createSeriesMarkersimport 和调用 - JS:
createCandleSeries()不再返回seriesMarkers,改为_update_markers()按需在 series 级别创建 - JS:移除 audit 中坏掉的
markersCount读取 - Python:移除
AbstractChart.__init__和set()中{self.id}.seriesMarkers = {self.candle.id}.seriesMarkers赋值 - Python:移除
reset()中seriesMarkers清理(随 series 删除自动清理)
- JS:移除
- 设计变更:
seriesMarkers从"Handler 级别持有 + 全局复制"改为"按需在 series 级别创建"——_update_markers()首次调用时自动创建,delete series时自动清理
- 问题:Handler 构造函数接收
marker_auto_scale参数但从未存储或使用,_update_markers()中autoScale硬编码为true - 修复:
- Python:
AbstractChart.__init__存储self._marker_auto_scale = marker_auto_scale - Python:
_update_markers()使用self._chart._marker_auto_scale替代硬编码true - JS:移除 Handler 构造函数中的
marker_auto_scale参数(纯 Python 侧逻辑)
- Python:
paneIndex:pane_index 在系列创建时(createLineSeries等)传入,Handler 层面不需要,已移除_marker_auto_scale:纯 Python 侧逻辑(AbstractChart._marker_auto_scale存储 +_update_markers()读取),已移除- Handler 构造函数从 8 个参数精简为 7 个
- 主 series 使用固定 ID:
window.Chart_1_candle/window.Chart_1_volume/window.Chart_1_oi- ID 不由 IDGen 自动生成,但 audit 的
GLOBALS_RE(Chart_\d前缀)能正确捕获 - 删除后按同名重建,JS 全局变量名一致
- ID 不由 IDGen 自动生成,但 audit 的
- Handler 构造函数惰性创建:
this.series/this.volumeSeries/this.openInterestSeries全部设为null- 由 Python 端 AbstractChart.init 创建后通过 JS 脚本设置 Handler 引用
reset()彻底清理:删除 candle/volume/oi 的 JS 对象和 Python 状态,Handler 引用设为 nullset()按需重建:检测self.candle/self.volume/self.oi为 None 时按固定 ID 重建_wrap_handler删除:不再需要,直接用_fixed_id参数创建
- 构造函数参数
candle→chart:不再绑定 CandleSeries,只依赖 AbstractChart _wrap_existing参数删除:不再区分"包装"和"独立"模式self._candle依赖移除:self._candle._normal_df()→self._normal_df()(继承自 SeriesCommon)- OHLC 着色保留:有
open/close列时自动着色,否则用默认_down_color price_scale_id参数暴露:VolumeSeries/OI Series 的__init__支持自定义价格尺度 ID- AbstractChart 直接管理:
self.volume/self.oi由 AbstractChart 创建和管理,不再通过candle.attach_volume()
_attached列表删除:CandleSeries 不再管理附属 seriesattach_volume/attach_open_interest删除:由 AbstractChart 直接管理delete()不再级联:只删除自身,不删除 volume/oiclear_data()不再级联:只清自身数据_toggle_data()不再遍历:只控制自身显隐set()不再自动转发:volume/oi 数据由 AbstractChart.set() 转发volume_config()/open_interest_config()委托:改为委托到self._chart.volume/self._chart.oi
_normal_df/merge_value_by_time/get_df_interval_offset/time_to_bar_time提取到util.py- SeriesCommon 中保留薄委托
_interval/offset/_period_locked从 SeriesCommon 迁移到 AbstractChart_set_interval/_time_to_bar_time/_single_datetime_format/set_period只在 AbstractChart 定义- SeriesCommon 中的
_time_to_bar_time/_single_datetime_format委托到self._chart set()中_set_interval在normal_df之后调用- SeriesCommon.set() 增加初始化检查
_update_markers统一 try-catch:SeriesCommon 中升级,CandleSeries 删除冗余覆盖VerticalSpan修复:参数series→chart,时间处理统一用_single_datetime_format,新增参数校验_is_subchart属性:reset()/clear_handlers()限制仅主图可调用remove_subchart清理:JS 端遍历 window 全局变量,删除引用子图表 series 的 VolumeSeries/OI@propertyNone 保护:candle_data/data/markers/_last_bar在self.candle为 None 时返回安全默认值- test_cleanup.py:新增
test_reset_cleanup()验证 reset 后 series 全部删除再重建;WARN 改为 FAIL
examples/35_line_markers/— Line 和 Histogram 上的标记演示
- pywebview
evaluate_js无法序列化 lightweight-charts API 对象: JS 函数返回包含 ISeriesApi/IChartApi 等对象的结构时,evaluate_js永久卡死,导致run_script_and_get超时- 修复: Python 端
run_script调用末尾加;0,阻止返回值传播 - 影响:
CandleSeries、Line、Histogram等所有通过run_script创建的 series
- 修复: Python 端
- 消息循环异常处理终止整个消息处理:
chart.py消息循环中KeyError和Exception的return会终止消息循环,导致后续消息全部丢失- 修复:
KeyError和未知Exception改为break+put(None)+ 输出[FATAL]错误信息;JavascriptException继续循环
- 修复:
- CandleSeries 标记不显示:
_update_markers()未添加 try/catch 保护,JS 错误中断 async IIFE 执行链- 修复:
CandleSeries._update_markers()添加 try/catch 防御
- 修复:
- 示例 34: 新增
examples/34_candle_series/— CandleSeries 独立K线系列演示(静态/实时/批量更新) - 测试: 新增
test/test_candle_series.py— 6 个测试用例覆盖创建/删除/update/markers/多pane/混合资源/审计验证
CandleSeries独立K线系列: 在任意 pane 上绘制独立 K 线(无 volume/open interest),适用于参考K线、对比K线等场景AbstractChart.create_candle_series()工厂方法,支持 name/pane_index/up_color/down_color/price_line/price_label 等参数CandleSeries.set()设置初始 OHLC 数据CandleSeries.update()更新最新一根 bar 或追加新 barCandleSeries.update_batch()批量更新多根 barCandleSeries.marker()在独立 K 线上打标记CandleSeries.delete()删除系列并清理 JS 对象- JS 端新增
Handler.createCandleSeries()方法,调用chart.addSeries(CandlestickSeries, ...),注册到_seriesList和legend _update_markers()添加 try/catch 防御,防止 JS 错误中断 async IIFE 执行链
sync_id组同步 API: 全新的基于组名的图表同步机制,替代旧的sync=chart.id配对同步- 所有
AbstractChart子类(Chart、HtmlTabChart、HTMLChart、StreamlitChart、JupyterChart、WxChart、QtChart)统一支持sync_id和sync_crosshairs_only参数 Chart.__init__新增sync_id参数,主图表可直接加入同步组join_sync_group()方法:任意图表可运行时动态加入同步组_normalize_sync_id()静态方法:统一校验sync_id输入(仅允许str/None/True/False)- 同步组规则:同组所有图表互相同步十字光标;时间范围仅在
sync_crosshairs_only=False的图表间同步 reset_sub()后同步自动恢复(_syncGroup属性保留组名)
- 所有
sync参数重命名为sync_id,语义从"链式传递 chart.id"改为"组名字符串":- 旧 API(v2.5.x 及更早):
create_subchart(sync=chart.id)— 传入目标图表的 ID(如window.Chart_1),建立 A↔B 两点之间的配对同步关系 - 新 API(v2.6.0):
create_subchart(sync_id='main')— 传入任意组名字符串,所有使用相同组名的图表自动互相同步,无需知道彼此的 ID - 主图表加入同步组:
Chart(sync_id='main')或chart.join_sync_group('main') True会被转为字符串'True'作为组名,False/None表示不同步- 传入非
str/None/True/False类型会抛出TypeError - 迁移示例:
# 旧写法(v2.5.x) chart = Chart(...) sub = chart.create_subchart(sync=chart.id) # 传入 chart.id # 新写法(v2.6.0) chart = Chart(..., sync_id='main') # 主图表加入 'main' 组 sub = chart.create_subchart(sync_id='main') # 子图加入同一组
- 旧 API(v2.5.x 及更早):
syncChartsAll不再直接使用: 内部同步重建改用syncGroup按_syncGroup分组重建
- JS 端
joinSyncGroup简化: 移除startsWith('window.')兼容处理和window[id]fallback,直接通过Handler._all.find()匹配 _unsync_all重写: 从复杂的 4 步配对拆解简化为 2 步(清空所有回调 → 按_syncGroup分组重建)- QUICK_REFERENCE.md 更新: 同步部分全面替换为新的
sync_id组同步 API 文档
-
HtmlTabChart 多子图布局溢出修复: 修复
create_subchart()在 HtmlTabChart 中布局溢出的问题setupGridLayout: 容器高度100vh→100%,跟随父元素而非视口reSize()grid 模式: 去掉 HtmlTabChart 特殊分支,统一用wrapper.getBoundingClientRect()获取实际尺寸_createChart(): 初始高度减去 nav 栏高度,避免首次渲染溢出
-
操作柄双击重置修复: 修复绝对定位模式下操作柄双击重置后图表尺寸异常的问题
- 根因:拖拽操作柄写入 px 高度,双击时混合使用百分比恢复导致尺寸错乱
- 修复:首次拖拽时备份
wrapper.style.height原始值,双击时从备份恢复 - 涉及
handler.ts三处修改:新增_originalHeight属性、mousedown时备份、dblclick时恢复
HTMLChart.export(filename): 重写export()方法,直接接受filename参数,不再需要调用内部_export()- 示例 32 全面重写:
html_chart_example.py: 2 subcharts × 2 panes 布局(K线+Volume × 2)html_tab_chart_demo.py: 3 个策略 tab(Subcharts T/B + Panes T/B + Absolute Position)- 演示
create_subchart()+pane_index+set_position()三种布局方式
- StaticLWC 及其子类新参数支持: 为
StaticLWC、StreamlitChart、JupyterChart、HTMLChart、HtmlTabChart添加AbstractChart的新参数支持- 新增参数:
position(网格位置)、pane_index(面板索引)、marker_auto_scale(标记自动缩放) - 确保参数完整传递链: 子类 →
StaticLWC→AbstractChart - 更新示例
32_html_tab_chart展示新参数使用
- 新增参数:
- QUICK_REFERENCE.md 文档更新: 更新
HTMLChart和HtmlTabChart示例,展示新参数使用 - 示例代码更新:
examples/32_html_tab_chart/html_tab_chart_demo.py添加新参数示例
- HtmlTabChart iframe 嵌入示例: 新增示例
32_html_tab_chart中的 iframe 嵌入演示,展示如何将 HtmlTabChart 嵌入其他 HTML 页面- 采用双文件方案:外壳 HTML + 图表内容 HTML,通过
<iframe src="...">引用 - 记录了多种单文件方案(srcdoc/data:base64/blob/Shadow DOM/innerHTML)的失败原因
- 采用双文件方案:外壳 HTML + 图表内容 HTML,通过
- reset_sub(): 新增子图内容重置功能,清除子图全部内容但保留布局,不影响其他子图,reset 后可重用
- 清除范围:K线数据、折线/柱状图系列、价格线、标记、绘图、表格、ToolBox、TopBar、Legend、Events、sync、handlers
- 新增示例
33_reset_sub,演示 4 子图网格 + 主图 reset + 独立子图 + 十字光标同步恢复 - 新增测试
test_reset_sub.py,自动化验证 Python + JS 双端资源清理
- Table div 归属修复: Table 不再追加到全局容器,改为追加到所属图表的 div,修复多子图表格重叠问题
- syncChartsAll 回调存储: crosshair 和 range 回调现在被正确存储到
_syncCallbacks中,支持后续清理和重建
- syncChartsAll 保护检查:
target.legend?.div检查仅保护legendHandler调用,不再阻断setCrosshairPosition - DrawingTool/ContextMenu 访问权限:
_chart、_clickHandler、_moveHandler、_onRightClick、div改为 public,支持 ToolBox 清理 - ToolBox 构造函数: 存储
_contextMenu和_undoHandler引用,支持精确清理
- syncChartsAll 回调未存储: 匿名回调改为命名变量并存储到
_syncCallbacks['__crosshairAll']/['__rangeAll'],支持 unsubscribe - _unsync_all 只处理部分回调: 改为遍历所有
_syncCallbacks条目统一清理,兼容syncCharts和syncChartsAll两种模式 - _rebuildSync 排除 reset 子图: reset_sub 后改为调用
syncChartsAll全量重建,不排除任何子图 - setCrosshairPosition 异常中断: 用 try-catch 包裹,空数据图表异常不影响其他图表的十字光标同步
- Table div 追加到全局容器: 移除 Table JS 构造函数中的
window.containerDiv.appendChild,由 Python 端控制追加位置
- HtmlTabChart: 新增多策略 Tab 切换图表,支持多策略切换、交易明细、绩效指标展示
- 改自 smalinin/bn_lightweight-charts-python 的 HtmlChart_BN
- 新增示例
32_html_tab_chart - 支持技术指标(SMA、布林带)、买卖标记、图例显示
- 使用专用标记
html-tab-chart-marker实现自适应高度计算
- API 重命名:
StaticLWC.load()→export(),_load()→_export() - HTMLChart: 移除
filename构造参数,改为export(filename)方法 - HtmlTabChart: 移除
filename构造参数,改为export(filename)方法 - ReflexChart:
load()→export(),_load()→_export()
- HtmlTabChart 多策略代码丢失: 修复
_prepare_html()只遍历历史策略,遗漏当前策略的问题 - HtmlTabChart UTF-8 编码: 修复 HTML 文件写入时的
UnicodeEncodeError - marker API 参数格式: 修复
position和shape参数使用错误格式导致标记不显示的问题 - HtmlTabChart X 轴刻度被裁剪: 修复图表高度计算错误导致 X 轴刻度不可见的问题
- HtmlTabChart 滚动条: 修复页面出现滚动条的问题,改用 flexbox 布局
- 图表同步功能:
create_subchart()新增sync参数,支持多图表同步时间轴和十字光标 - 图表同步示例: 新增示例
31_chart_sync,演示sync和sync_crosshairs_only参数的使用 - 表格组件改进:
create_table()支持height=None和width=None实现自动适应内容大小 - 网格布局系统:
position参数支持三种格式:整数(如111)、元组(如(2,2,1))、字符串(已弃用) - 运行时位置控制: 新增
get_position()和set_position()方法,支持动态调整图表位置 - 相对大小控制:
width/height参数相对于网格单元,支持内缩(<1.0)和侵占(>1.0) - 网格冲突检测: 自动检测同一窗口中图表网格规格冲突,防止布局混乱,抛出清晰的
ValueError异常 - 测试整合: 将根目录测试文件整合到
tests/文件夹,统一管理测试用例 - 文档完善: 添加详细的网格布局与冲突处理说明到 API 参考文档
- 表格 position 参数变更:
create_table()的position参数字符串输入已废弃,输入任何字符串等效于输入(0, 0),会发出DeprecationWarning - 表格位置处理逻辑: 统一 position 参数处理,移除重复的类型检查
- Table 类默认位置: 默认值从
'left'改为(0, 0) - position 参数弃用警告:
parse_position()对字符串输入发出DeprecationWarning,推荐使用数字格式 - 代码优化: 重构
parse_position()和_convert_string_to_grid()函数,使用字典映射替代 if-elif 链,提高代码可维护性 - 参数重命名:
sync_id重命名为sync,更符合 Python 命名规范
- 表格布局问题: 修复了表格内容不显示、表头与表内容重叠的问题
- 表格拖动区域问题: 修复了表格可拖动区域过大超出表格大小的问题
- 回调 KeyError: 修复了表格点击时
KeyError: 'null'的问题 - 表格样式修复: 添加
overflowWrapper.style.flex = '1'和overflowWrapper.style.minHeight = '0' - 代码质量: 清理了多处 TODO 注释,添加了详细说明和类型定义
- Rollup 编译警告: 修复了 TypeScript 类型错误,解决
example.ts和toolbox.ts的编译警告
- 表格 position 字符串:
create_table()的position参数不再支持字符串('left','right','top','bottom'),建议使用相对坐标元组格式position=(x, y) - 字符串 position 格式:
parse_position()对字符串输入发出弃用警告,推荐使用数字格式(如121)或元组格式(如(1, 2, 1))
- 实时数据流式更新: 支持直接从 tick 数据更新 K 线
- 多面板图表: 使用
create_subchart()创建子图 - 工具箱: 在图表上直接绘制趋势线、矩形、射线、水平线
- 事件系统: 时间周期选择器、搜索、快捷键等
- 表格组件: 用于自选股、下单、持仓管理
- Polygon.io 集成: 直接获取市场数据
- 成交量 + 持仓量叠加: 独立 Y 轴缩放
- 多 Chart 实例: 完全独立的图表对象
- 常驻图例: 鼠标移出图表时 OHLC 仍可见
- 垂直区间高亮: 半透明填充标记日期范围
- 资源清理 API:
reset()、clear_handlers()、audit()、delete() - PriceLine 对象:
create_price_line().delete() - Table.delete(): 销毁表格并清理 JS 状态
- 人类可读的 ID:
window.Chart_1、window.Line_3等 - 资源审计:
chart.audit(use_js=True)返回完整 TOML 格式的 JS 变量状态 - 全面的清理测试: test_cleanup.py 验证所有资源类型的 Python + JS 无泄漏
- 序列批量更新 API:
Line/Histogram.update_batch()高性能批量更新 - K 线批量更新:
chart.update_bars()/update_from_ticks() - 跨进程嵌入 Qt:
CrossProcessChart通过原生窗口句柄将 pywebview 窗口嵌入 QWidget
- PySide6
- PyQt6
- wxPython
- asyncio
- Reflex
Added: 新增功能Changed: 现有功能的变更Deprecated: 即将移除的功能Removed: 已移除的功能Fixed: 修复的 bugSecurity: 安全相关的修复