From 4a451179280dec81e08fab1316868c4d3d02b306 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 12:34:42 +0530 Subject: [PATCH 01/29] build(deps): bump actions/checkout from 6 to 7 in /.github/workflows (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
Release notes

Sourced from actions/checkout's releases.

v7.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6.0.3...v7.0.0

v6.0.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6...v6.0.3

v6.0.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v6.0.1...v6.0.2

v6.0.1

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v6...v6.0.1

Changelog

Sourced from actions/checkout's changelog.

Changelog

v7.0.0

v6.0.3

v6.0.2

v6.0.1

v6.0.0

v5.0.1

v5.0.0

v4.3.1

v4.3.0

v4.2.2

v4.2.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/publish.yml | 4 ++-- .github/workflows/test.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03d7f26..50ec683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: name: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1810d6d..95c44ba 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index acdbb99..a840da3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 50bc26c..7a2cbaf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,7 +34,7 @@ jobs: should_publish: ${{ steps.check-pypi.outputs.should_publish }} repository: ${{ steps.set-repo.outputs.repository }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 @@ -102,7 +102,7 @@ jobs: if: needs.version-check.outputs.should_publish == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce31fcb..52987f7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: python-version: ["3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install uv uses: astral-sh/setup-uv@v7 From 438d5b672caf36ebe37b6bf7d92ae3cd252afce8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 12:36:27 +0530 Subject: [PATCH 02/29] build(deps): bump actions/checkout from 6 to 7 in /.github/workflows (#33) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
Release notes

Sourced from actions/checkout's releases.

v7.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6.0.3...v7.0.0

v6.0.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6...v6.0.3

v6.0.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v6.0.1...v6.0.2

v6.0.1

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v6...v6.0.1

Changelog

Sourced from actions/checkout's changelog.

Changelog

v7.0.0

v6.0.3

v6.0.2

v6.0.1

v6.0.0

v5.0.1

v5.0.0

v4.3.1

v4.3.0

v4.2.2

v4.2.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From dd7d485dffc680f82a2afc95ba683707b72c5bcc Mon Sep 17 00:00:00 2001 From: Gopal Parashar Date: Mon, 29 Jun 2026 18:38:01 +0530 Subject: [PATCH 03/29] fix: Subclassed StreamWindow from Window class to fix missing attributes --- lightweight_charts/stream.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lightweight_charts/stream.py b/lightweight_charts/stream.py index d12f363..a8b8aad 100644 --- a/lightweight_charts/stream.py +++ b/lightweight_charts/stream.py @@ -25,7 +25,7 @@ from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware -from .abstract import AbstractChart +from .abstract import AbstractChart, Window from .util import BulkRunScript, parse_event_message # --------------------------------------------------------------------------- @@ -36,17 +36,22 @@ _JS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "js") -class StreamWindow: +class StreamWindow(Window): """ Drop-in replacement for abstract.Window that communicates with a browser client over WebSocket instead of pywebview. + + Subclasses ``Window`` so ``_id_gen``, ``create_table``, ``style``, and + other shared window helpers stay in sync with ``AbstractChart``. """ def __init__(self) -> None: - self.token: str = secrets.token_hex(32) - self.scripts: list = [] # replay buffer — never cleared + super().__init__() + # Per-instance handlers (``Window.handlers`` is a shared class dict). self.handlers: dict = {} + self.token: str = secrets.token_hex(32) + self._ws: WebSocket | None = None self._loop: asyncio.AbstractEventLoop | None = None self._return_event = threading.Event() @@ -54,7 +59,7 @@ def __init__(self) -> None: self._server: uvicorn.Server | None = None self._thread: threading.Thread | None = None - # BulkRunScript batches JS calls; script_func is called on __exit__ + # Route batched JS through this window's WebSocket-aware run_script. self.bulk_run = BulkRunScript(self.run_script) # ------------------------------------------------------------------ From 69a557ca074a85fc4377699ca75e3f5e42bc8aee Mon Sep 17 00:00:00 2001 From: Gopal Parashar Date: Mon, 29 Jun 2026 18:39:24 +0530 Subject: [PATCH 04/29] fix: Added internal data helper for volume profile --- lightweight_charts/plugins/volume_profile.py | 36 ++++++++++++++++---- src/volume-profile/volume-profile.ts | 36 +++++++++----------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/lightweight_charts/plugins/volume_profile.py b/lightweight_charts/plugins/volume_profile.py index 779ed0d..e695b7f 100644 --- a/lightweight_charts/plugins/volume_profile.py +++ b/lightweight_charts/plugins/volume_profile.py @@ -15,8 +15,8 @@ class VolumeProfile(Pane): :param series: The series to attach to (also provides the chart reference). :param time: Anchor timestamp for the profile (Unix seconds, datetime, or string). :param profile: Price-level volume data — either a list of - ``{'price': float, 'vol': float}`` dicts or a DataFrame with - ``price`` and ``vol`` columns. + ``{'price': float, 'vol': float, 'color': str}`` dicts or a DataFrame with + ``price``, ``vol``, and optional ``color`` columns. :param width: Width of the profile in bar units (default 10). """ @@ -30,11 +30,9 @@ def __init__( super().__init__(series._chart.win) self._series = series ts = series._chart._format_time(time) - profile_list = ( - profile[["price", "vol"]].to_dict("records") - if isinstance(profile, pd.DataFrame) - else profile - ) + profile_list = self._profile_records(profile) + self._vpData_time = ts + self._vpData_width = width vp_data = {"time": ts, "profile": profile_list, "width": width} self.run_script(f""" {self.id} = new Lib.VolumeProfile( @@ -45,6 +43,30 @@ def __init__( {series.id}.series.attachPrimitive({self.id}); null""") + @staticmethod + def _profile_records(profile: list[dict] | pd.DataFrame) -> list[dict]: + if isinstance(profile, pd.DataFrame): + cols = [c for c in ("price", "vol", "color") if c in profile.columns] + return profile[cols].to_dict("records") + return profile + + def update_data( + self, + profile: list[dict] | pd.DataFrame, + time=None, + width: int | None = None, + ) -> None: + """Replace profile data in-place without detaching the primitive.""" + ts = self._series._chart._format_time(time) if time is not None else self._vpData_time + if time is not None: + self._vpData_time = ts + if width is not None: + self._vpData_width = width + profile_list = self._profile_records(profile) + w = width if width is not None else self._vpData_width + vp_data = {"time": ts, "profile": profile_list, "width": w} + self.run_script(f"{self.id}.updateData({json.dumps(vp_data)})") + def delete(self): """Detaches and removes the volume profile from the series.""" self.run_script(f"{self._series.id}.series.detachPrimitive({self.id})") diff --git a/src/volume-profile/volume-profile.ts b/src/volume-profile/volume-profile.ts index 7209668..d7ba7b9 100644 --- a/src/volume-profile/volume-profile.ts +++ b/src/volume-profile/volume-profile.ts @@ -17,6 +17,7 @@ import { positionsBox } from '../helpers/dimensions/positions'; interface VolumeProfileItem { y: Coordinate | null; width: number; + color?: string; } interface VolumeProfileRendererData { @@ -30,6 +31,7 @@ interface VolumeProfileRendererData { interface VolumeProfileDataPoint { price: number; vol: number; + color?: string; } export interface VolumeProfileData { @@ -48,26 +50,7 @@ class VolumeProfileRenderer implements IPrimitivePaneRenderer { target.useBitmapCoordinateSpace(scope => { if (this._data.x === null || this._data.top === null) return; const ctx = scope.context; - const horizontalPositions = positionsBox( - this._data.x, - this._data.x + this._data.width, - scope.horizontalPixelRatio - ); - const verticalPositions = positionsBox( - this._data.top, - this._data.top - this._data.columnHeight * this._data.items.length, - scope.verticalPixelRatio - ); - - ctx.fillStyle = 'rgba(0, 0, 255, 0.2)'; - ctx.fillRect( - horizontalPositions.position, - verticalPositions.position, - horizontalPositions.length, - verticalPositions.length - ); - - ctx.fillStyle = 'rgba(80, 80, 255, 0.8)'; + this._data.items.forEach(row => { if (row.y === null) return; const itemVerticalPos = positionsBox( @@ -80,6 +63,7 @@ class VolumeProfileRenderer implements IPrimitivePaneRenderer { this._data.x! + row.width, scope.horizontalPixelRatio ); + ctx.fillStyle = row.color ?? 'rgba(80, 80, 255, 0.8)'; ctx.fillRect( itemHorizontalPos.position, itemVerticalPos.position, @@ -125,6 +109,7 @@ class VolumeProfilePaneView implements IPrimitivePaneView { this._items = data.profile.map(row => ({ y: series.priceToCoordinate(row.price), width: (this._width * row.vol) / maxVolume, + color: row.color, })); } @@ -169,6 +154,17 @@ export class VolumeProfile implements ISeriesPrimitive