From 90bab840e34f728fd40cbd7b06e07610a270d50a Mon Sep 17 00:00:00 2001 From: dsmmcken Date: Sat, 11 Apr 2026 10:56:01 -0400 Subject: [PATCH 01/13] TVL init --- package-lock.json | 1246 ++++++++++++++- plugins/tradingview-lightweight/.gitignore | 11 + plugins/tradingview-lightweight/AGENTS.md | 165 ++ plugins/tradingview-lightweight/CLAUDE.md | 1 + plugins/tradingview-lightweight/LICENSE | 202 +++ plugins/tradingview-lightweight/Makefile | 7 + plugins/tradingview-lightweight/PLAN.md | 305 ++++ plugins/tradingview-lightweight/README.md | 31 + .../notes/api-reference/INDEX.md | 47 + .../notes/api-reference/chart-api.md | 218 +++ .../notes/api-reference/enumerations.md | 81 + .../api-reference/functions-variables.md | 117 ++ .../notes/api-reference/markers-events.md | 101 ++ .../notes/api-reference/panes-api.md | 59 + .../notes/api-reference/price-scale-api.md | 75 + .../notes/api-reference/series-api.md | 66 + .../notes/api-reference/series-types.md | 172 ++ .../notes/api-reference/time-scale-api.md | 134 ++ .../notes/api-reference/utility-types.md | 112 ++ .../notes/downsampling-plan.md | 411 +++++ .../notes/local-e2e-testing.md | 148 ++ .../notes/plotly-express-downsampling.md | 270 ++++ .../tradingview-lightweight/notes/sizzle.py | 363 +++++ .../tradingview-lightweight/pyproject.toml | 3 + plugins/tradingview-lightweight/setup.cfg | 37 + plugins/tradingview-lightweight/setup.py | 10 + .../plot/tradingview_lightweight/__init__.py | 115 ++ .../tradingview_lightweight/_js/package.json | 68 + .../plot/tradingview_lightweight/_register.py | 21 + .../plot/tradingview_lightweight/_types.py | 12 + .../plot/tradingview_lightweight/chart.py | 990 ++++++++++++ .../communication/__init__.py | 4 + .../communication/connection.py | 39 + .../communication/listener.py | 74 + .../plot/tradingview_lightweight/markers.py | 236 +++ .../plot/tradingview_lightweight/options.py | 83 + .../plot/tradingview_lightweight/series.py | 621 ++++++++ .../src/js/jest.config.cjs | 14 + .../src/js/package.json | 68 + .../src/js/src/TradingViewChart.tsx | 510 ++++++ .../src/js/src/TradingViewChartModel.ts | 892 +++++++++++ .../src/js/src/TradingViewChartRenderer.ts | 685 ++++++++ .../src/js/src/TradingViewPlugin.ts | 15 + .../src/js/src/TradingViewTheme.ts | 136 ++ .../src/js/src/TradingViewTypes.ts | 123 ++ .../src/js/src/TradingViewUtils.ts | 348 ++++ .../js/src/__mocks__/lightweight-charts.js | 89 ++ .../TradingViewChartRenderer.test.ts | 1398 +++++++++++++++++ .../js/src/__tests__/TradingViewTheme.test.ts | 75 + .../js/src/__tests__/TradingViewUtils.test.ts | 735 +++++++++ .../src/js/src/index.ts | 9 + .../src/js/tsconfig.json | 13 + .../src/js/vite.config.ts | 34 + .../tradingview-lightweight/start-server.sh | 92 ++ .../tradingview-lightweight/stop-server.sh | 10 + .../plot/tradingview_lightweight/__init__.py | 0 .../tradingview_lightweight/test_chart.py | 1089 +++++++++++++ .../tradingview_lightweight/test_markers.py | 723 +++++++++ .../tradingview_lightweight/test_series.py | 722 +++++++++ plugins/tradingview-lightweight/tox.ini | 8 + tests/app.d/tests.app | 3 +- tests/app.d/tradingview_lightweight.py | 639 ++++++++ tests/tradingview_lightweight.spec.ts | 280 ++++ ...ck-with-markers-loads-1-chromium-linux.png | Bin 0 -> 11669 bytes ...ith-price-lines-loads-1-chromium-linux.png | Bin 0 -> 12617 bytes ...ce-after-button-click-1-chromium-linux.png | Bin 0 -> 14855 bytes ...ce-after-button-click-2-chromium-linux.png | Bin 0 -> 10248 bytes ...sed-price-lines-loads-1-chromium-linux.png | Bin 0 -> 15436 bytes ...mic-price-lines-loads-1-chromium-linux.png | Bin 0 -> 13583 bytes ...ith-SMA-overlay-loads-1-chromium-linux.png | Bin 0 -> 15743 bytes ...olume-histogram-loads-1-chromium-linux.png | Bin 0 -> 11710 bytes ...-series-overlay-loads-1-chromium-linux.png | Bin 0 -> 29428 bytes ...ading-dashboard-loads-1-chromium-linux.png | Bin 0 -> 18782 bytes ...wo-price-scales-loads-1-chromium-linux.png | Bin 0 -> 22826 bytes ...s-options-chart-loads-1-chromium-linux.png | Bin 0 -> 29828 bytes ...s-options-chart-loads-1-chromium-linux.png | Bin 0 -> 21290 bytes ...stom-separators-loads-1-chromium-linux.png | Bin 0 -> 16052 bytes ...tick-and-volume-loads-1-chromium-linux.png | Bin 0 -> 10078 bytes ...ries-Area-chart-loads-1-chromium-linux.png | Bin 0 -> 29386 bytes ...eries-Bar-chart-loads-1-chromium-linux.png | Bin 0 -> 10906 bytes ...-Baseline-chart-loads-1-chromium-linux.png | Bin 0 -> 26049 bytes ...ndlestick-chart-loads-1-chromium-linux.png | Bin 0 -> 10911 bytes ...Histogram-chart-loads-1-chromium-linux.png | Bin 0 -> 9419 bytes ...ries-Line-chart-loads-1-chromium-linux.png | Bin 0 -> 21454 bytes ...-with-watermark-loads-1-chromium-linux.png | Bin 0 -> 34433 bytes ...h-custom-colors-loads-1-chromium-linux.png | Bin 0 -> 13396 bytes ...ith-custom-grid-loads-1-chromium-linux.png | Bin 0 -> 21649 bytes ...per-row-columns-loads-1-chromium-linux.png | Bin 0 -> 11669 bytes ...s-fixed-styling-loads-1-chromium-linux.png | Bin 0 -> 11266 bytes ...urve-area-chart-loads-1-chromium-linux.png | Bin 0 -> 19279 bytes ...urve-line-chart-loads-1-chromium-linux.png | Bin 0 -> 21242 bytes 91 files changed, 15335 insertions(+), 30 deletions(-) create mode 100644 plugins/tradingview-lightweight/.gitignore create mode 100644 plugins/tradingview-lightweight/AGENTS.md create mode 100644 plugins/tradingview-lightweight/CLAUDE.md create mode 100644 plugins/tradingview-lightweight/LICENSE create mode 100644 plugins/tradingview-lightweight/Makefile create mode 100644 plugins/tradingview-lightweight/PLAN.md create mode 100644 plugins/tradingview-lightweight/README.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/INDEX.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/chart-api.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/enumerations.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/functions-variables.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/markers-events.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/panes-api.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/price-scale-api.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/series-api.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/series-types.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/time-scale-api.md create mode 100644 plugins/tradingview-lightweight/notes/api-reference/utility-types.md create mode 100644 plugins/tradingview-lightweight/notes/downsampling-plan.md create mode 100644 plugins/tradingview-lightweight/notes/local-e2e-testing.md create mode 100644 plugins/tradingview-lightweight/notes/plotly-express-downsampling.md create mode 100644 plugins/tradingview-lightweight/notes/sizzle.py create mode 100644 plugins/tradingview-lightweight/pyproject.toml create mode 100644 plugins/tradingview-lightweight/setup.cfg create mode 100644 plugins/tradingview-lightweight/setup.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/__init__.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/_js/package.json create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/_register.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/_types.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/chart.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/communication/__init__.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/communication/connection.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/communication/listener.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/markers.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/options.py create mode 100644 plugins/tradingview-lightweight/src/deephaven/plot/tradingview_lightweight/series.py create mode 100644 plugins/tradingview-lightweight/src/js/jest.config.cjs create mode 100644 plugins/tradingview-lightweight/src/js/package.json create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewChart.tsx create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewChartModel.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewChartRenderer.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewPlugin.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewTheme.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewTypes.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/TradingViewUtils.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/__mocks__/lightweight-charts.js create mode 100644 plugins/tradingview-lightweight/src/js/src/__tests__/TradingViewChartRenderer.test.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/__tests__/TradingViewTheme.test.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/__tests__/TradingViewUtils.test.ts create mode 100644 plugins/tradingview-lightweight/src/js/src/index.ts create mode 100644 plugins/tradingview-lightweight/src/js/tsconfig.json create mode 100644 plugins/tradingview-lightweight/src/js/vite.config.ts create mode 100755 plugins/tradingview-lightweight/start-server.sh create mode 100755 plugins/tradingview-lightweight/stop-server.sh create mode 100644 plugins/tradingview-lightweight/test/deephaven/plot/tradingview_lightweight/__init__.py create mode 100644 plugins/tradingview-lightweight/test/deephaven/plot/tradingview_lightweight/test_chart.py create mode 100644 plugins/tradingview-lightweight/test/deephaven/plot/tradingview_lightweight/test_markers.py create mode 100644 plugins/tradingview-lightweight/test/deephaven/plot/tradingview_lightweight/test_series.py create mode 100644 plugins/tradingview-lightweight/tox.ini create mode 100644 tests/app.d/tradingview_lightweight.py create mode 100644 tests/tradingview_lightweight.spec.ts create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Annotations-Candlestick-with-markers-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Annotations-Candlestick-with-price-lines-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---By-Ticking-New-partition-key-adds-a-second-trace-after-button-click-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---By-Ticking-New-partition-key-adds-a-second-trace-after-button-click-2-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Dynamic-Price-Lines--75859-k-with-dynamic-column-based-price-lines-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Dynamic-Price-Lines--7f20b-th-mixed-static-and-dynamic-price-lines-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Multi-Series-Candlestick-with-SMA-overlay-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Multi-Series-Candlestick-with-volume-histogram-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Multi-Series-Dual-line-series-overlay-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Multi-Series-Full-trading-dashboard-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Multi-Series-Two-price-scales-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Options-Chart-Multi-series-options-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Options-Chart-Single-series-options-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Panes-Three-pane-chart-with-custom-separators-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Panes-Two-pane-chart-with-candlestick-and-volume-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Area-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Bar-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Baseline-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Candlestick-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Histogram-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Single-Series-Line-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Styled-Charts-Area-chart-with-watermark-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Styled-Charts-Candlestick-with-custom-colors-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Styled-Charts-Line-chart-with-custom-grid-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Table-Driven-Markers-4efae--table-driven-markers-per-row-columns-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Table-Driven-Markers-68c79-th-table-driven-markers-fixed-styling-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Yield-Curve-Yield-curve-area-chart-loads-1-chromium-linux.png create mode 100644 tests/tradingview_lightweight.spec.ts-snapshots/TradingView-Lightweight---Yield-Curve-Yield-curve-line-chart-loads-1-chromium-linux.png diff --git a/package-lock.json b/package-lock.json index 7990df301..3d51e3de1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3716,6 +3716,10 @@ "resolved": "plugins/theme-pack/src/js", "link": true }, + "node_modules/@deephaven/js-plugin-tradingview-lightweight": { + "resolved": "plugins/tradingview-lightweight/src/js", + "link": true + }, "node_modules/@deephaven/js-plugin-ui": { "resolved": "plugins/ui/src/js", "link": true @@ -5325,6 +5329,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fontsource/fira-mono": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/@fontsource/fira-mono/-/fira-mono-5.0.13.tgz", + "integrity": "sha512-fZDjR2BdAqmauEbTjcIT62zYzbOgDa5+IQH34D2k8Pxmy1T815mAqQkZciWZVQ9dc/BgdTtTUV9HJ2ulBNwchg==", + "license": "OFL-1.1" + }, + "node_modules/@fontsource/fira-sans": { + "version": "5.0.20", + "resolved": "https://registry.npmjs.org/@fontsource/fira-sans/-/fira-sans-5.0.20.tgz", + "integrity": "sha512-inmUjoKPrgnO4uUaZTAgP0b6YdhDfA52axHXvdTwgLvwd2kn3ZgK52UZoxD0VnrvTOjLA/iE4oC0tNtz4nyb5g==", + "license": "OFL-1.1" + }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.3.3", "license": "MIT", @@ -8056,6 +8072,166 @@ "@octokit/openapi-types": "^24.2.0" } }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-linux-x64-glibc": { "version": "2.5.1", "cpu": [ @@ -8092,6 +8268,66 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "license": "MIT", @@ -11854,6 +12090,16 @@ "@swc/counter": "^0.1.3" } }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.23", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.23.tgz", + "integrity": "sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.0", "dev": true, @@ -12522,6 +12768,12 @@ "version": "2.0.11", "license": "MIT" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.33", "dev": true, @@ -15129,7 +15381,9 @@ "license": "MIT" }, "node_modules/csstype": { - "version": "3.1.3", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/d": { @@ -17397,6 +17651,12 @@ "node": ">=0.4.0" } }, + "node_modules/fancy-canvas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fancy-canvas/-/fancy-canvas-2.1.0.tgz", + "integrity": "sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "license": "MIT" @@ -21830,6 +22090,15 @@ "immediate": "~3.0.5" } }, + "node_modules/lightweight-charts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/lightweight-charts/-/lightweight-charts-5.1.0.tgz", + "integrity": "sha512-jEAYR4ODYeyNZcWUigsoLTl52rbPmgXnvd5FLIv/ZoA/2sSDw63YKnef8n4yhzum7W926yHeFwlm7ididKb7YQ==", + "license": "Apache-2.0", + "dependencies": { + "fancy-canvas": "2.1.0" + } + }, "node_modules/lines-and-columns": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", @@ -21936,6 +22205,12 @@ "version": "4.6.2", "license": "MIT" }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "license": "MIT" + }, "node_modules/lodash.set": { "version": "4.3.2", "license": "MIT" @@ -27733,7 +28008,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "dev": true, "engines": { "node": ">=10" } @@ -30476,7 +30750,9 @@ "license": "MIT" }, "node_modules/world-calendars": { - "version": "1.0.3", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", + "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", "license": "MIT", "dependencies": { "object-assign": "^4.1.0" @@ -34774,30 +35050,950 @@ "node": ">=18.0.0" } }, - "plugins/theme-pack/src/js/node_modules/world-calendars": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", - "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", - "dev": true, + "plugins/tradingview-lightweight/src/js": { + "name": "@deephaven/js-plugin-tradingview-lightweight", + "version": "0.1.0", + "license": "Apache-2.0", "dependencies": { - "object-assign": "^4.1.0" + "@deephaven/components": "^1.2.0", + "@deephaven/dashboard": "^1.2.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/jsapi-bootstrap": "1.2.0", + "@deephaven/log": "1.1.0", + "@deephaven/plugin": "^1.2.0", + "@deephaven/utils": "^1.1.0", + "lightweight-charts": "^5.1.0" + }, + "devDependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.39.5", + "@deephaven/test-utils": "0.105.0", + "@types/react": "^17.0.2", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" } }, - "plugins/ui/src/js": { - "name": "@deephaven/js-plugin-ui", - "version": "0.32.1", + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-1.17.0.tgz", + "integrity": "sha512-0H/W0q3iH07rKvS/Ev3OLLfeAQtZi/sujuZL+MnQInPJTX3rNHb8XcwAKI5bI/u5a/+PvGkNswZcS3njvKxJ0Q==", "license": "Apache-2.0", "dependencies": { - "@deephaven/chart": "^1.5.1", - "@deephaven/components": "^1.5.1", - "@deephaven/console": "^1.5.1", - "@deephaven/dashboard": "^1.5.1", - "@deephaven/dashboard-core-plugins": "^1.5.1", - "@deephaven/golden-layout": "^1.5.1", - "@deephaven/grid": "^1.3.0", + "@adobe/react-spectrum": "3.38.0", "@deephaven/icons": "^1.2.0", - "@deephaven/iris-grid": "^1.5.1", - "@deephaven/jsapi-bootstrap": "^1.5.1", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/utils": "^1.10.0", + "@fontsource/fira-mono": "5.0.13", + "@fontsource/fira-sans": "5.0.20", + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "@hello-pangea/dnd": "^18.0.1", + "@internationalized/date": "^3.5.5", + "@react-spectrum/theme-default": "^3.5.1", + "@react-spectrum/toast": "^3.0.0-beta.16", + "@react-spectrum/utils": "^3.11.5", + "@react-types/combobox": "3.13.1", + "@react-types/radio": "^3.8.1", + "@react-types/shared": "^3.22.1", + "@react-types/textfield": "^3.9.1", + "bootstrap": "4.6.2", + "classnames": "^2.3.1", + "event-target-shim": "^6.0.2", + "lodash.clamp": "^4.0.3", + "lodash.debounce": "^4.0.8", + "lodash.flatten": "^4.4.0", + "memoizee": "^0.4.15", + "nanoid": "^5.0.7", + "popper.js": "^1.16.1", + "react-reverse-portal": "^2.3.0", + "react-transition-group": "^4.4.2", + "react-virtualized-auto-sizer": "1.0.7", + "react-window": "^1.8.7" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "react-is": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/@deephaven/react-hooks": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-1.14.0.tgz", + "integrity": "sha512-VWRU6Hka5GyN0zO5LJYI5YgKrEsf0xAKrQ5LnEX4WSloB1C5DFoS1K1kH3fPqVBhid5JTu7R7oe0y4Tvt4wesQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/@hello-pangea/dnd": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz", + "integrity": "sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.26.7", + "css-box-model": "^1.2.1", + "raf-schd": "^4.0.3", + "react-redux": "^9.2.0", + "redux": "^5.0.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/@hello-pangea/dnd/node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/@react-types/combobox": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.13.1.tgz", + "integrity": "sha512-7xr+HknfhReN4QPqKff5tbKTe2kGZvH+DGzPYskAtb51FAAiZsKo+WvnNAvLwg3kRoC9Rkn4TAiVBp/HgymRDw==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.26.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/react-virtualized-auto-sizer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.7.tgz", + "integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==", + "license": "MIT", + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/components/node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT", + "peer": true + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/dashboard": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-1.17.1.tgz", + "integrity": "sha512-ToEAhv9Im/kumvv+OLJgQO27rc+jRJGoNbej4rbRRU2PQGjKh9+eJlYMA4kHM4jSQrM9EJUtmF5MAoU9fwwyPA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/golden-layout": "^1.17.1", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/redux": "^1.17.0", + "@deephaven/utils": "^1.10.0", + "classnames": "^2.3.1", + "fast-deep-equal": "^3.1.3", + "lodash.ismatch": "^4.1.1", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "nanoid": "^5.0.7", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "react-redux": "^7.2.4" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/golden-layout": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-1.17.1.tgz", + "integrity": "sha512-lnA87WSFcFoceK7DtsxNqKjEYCF7L427VxtMdMR7xU/tsTJUQnlT5MNR9BV/2Ybz8AR8Kh1qQv/3EmY1vlHGmA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "jquery": "^3.6.0", + "nanoid": "^5.0.7" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-1.14.0.tgz", + "integrity": "sha512-VWRU6Hka5GyN0zO5LJYI5YgKrEsf0xAKrQ5LnEX4WSloB1C5DFoS1K1kH3fPqVBhid5JTu7R7oe0y4Tvt4wesQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/filters": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@deephaven/filters/-/filters-1.1.0.tgz", + "integrity": "sha512-SMWKYT8aFtZ/CyVUtUiF1/RPQGl4Y6dvNG43KvmIMKKMXYqhliKD291aynYSl7C8IafkHNzdDtdAZPgPXLoOWA==", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/icons": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@deephaven/icons/-/icons-1.2.0.tgz", + "integrity": "sha512-esxuQcRjQxuu+AycLIB7TWNDDGReDuol6KMx6LpcVHMx6AHp8Zm/u90qHyDrzDSJ6bhBTM6ZNEscWzWL58WUzg==", + "license": "Apache-2.0", + "dependencies": { + "@fortawesome/fontawesome-common-types": "^6.1.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/react-fontawesome": "^0.2.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-bootstrap": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-1.2.0.tgz", + "integrity": "sha512-KGhyebqhufveTrg7P/LlJvZbeL/mW2P80WUgPDPvY0S2yRvRTZd970aNSf6/aF9pplmGAO+NSBsrX7jJK4gA+A==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.2.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/log": "^1.1.0", + "@deephaven/react-hooks": "^1.2.0", + "@deephaven/utils": "^1.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/react-hooks": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-1.14.0.tgz", + "integrity": "sha512-VWRU6Hka5GyN0zO5LJYI5YgKrEsf0xAKrQ5LnEX4WSloB1C5DFoS1K1kH3fPqVBhid5JTu7R7oe0y4Tvt4wesQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.9", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.9.tgz", + "integrity": "sha512-NwMxFmNCnRV4/2+MdN/8vUGiEtXFgL1K/+iXTKKvi+Brje5JHOSCn2miCKR9tAn0LNb/UdmJq+DSIZqvz8cU/Q==", + "license": "Apache-2.0" + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-utils": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-utils/-/jsapi-utils-1.16.0.tgz", + "integrity": "sha512-lyMDgxmb7v2GDlm1Ksf4S037QuWUhpOMKtnHZoEuKKIthcd6WejsNP+S8U2iRCYSJiJ1jEpTAVMrrS2CM4ZC7w==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/filters": "^1.1.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/log": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "lodash.clamp": "^4.0.3", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/jsapi-utils/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/log": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.1.0.tgz", + "integrity": "sha512-07Ww5o1iA9M65KoyHTfHTmCnzGIa/5OVP29pyP+FGmaXXMgujdvFRPfLHki0EeW92WOttXfK51kjDyzkBcs11Q==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@deephaven/plugin/-/plugin-1.18.0.tgz", + "integrity": "sha512-vn5AKTlPDeI9p/yMDsacJqrkIL4FiQkQzGkctMbQH4c3tsbkcC+iPUIBbqKrvWOYDs42+ZoHHpQqDMOAM4c/tQ==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/dashboard": "^1.17.1", + "@deephaven/golden-layout": "^1.17.1", + "@deephaven/grid": "^1.18.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/iris-grid": "^1.18.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@fortawesome/fontawesome-common-types": "^6.1.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/golden-layout": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-1.17.1.tgz", + "integrity": "sha512-lnA87WSFcFoceK7DtsxNqKjEYCF7L427VxtMdMR7xU/tsTJUQnlT5MNR9BV/2Ybz8AR8Kh1qQv/3EmY1vlHGmA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "jquery": "^3.6.0", + "nanoid": "^5.0.7" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/grid": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-1.18.0.tgz", + "integrity": "sha512-2uF99HNqRhvqVOmLL1HSDlF7P8mjkS3LgFIxVZA6qxDbBQVo6sxr6ymPWChAd3I+MseDJedojgMjfsGTOOedFw==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/utils": "^1.10.0", + "classnames": "^2.3.1", + "color-convert": "^2.0.1", + "event-target-shim": "^6.0.2", + "linkifyjs": "^4.1.0", + "lodash.clamp": "^4.0.3", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-1.18.0.tgz", + "integrity": "sha512-DP6Hh2Nn0R3CgC4ED3eNPN8Ns9nUvHu3Ezi/++PerzqC6Ej0K1493KtapObJy9xESqBNkvzMStakypZ7nfm0PA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/console": "^1.17.0", + "@deephaven/filters": "^1.1.0", + "@deephaven/grid": "^1.18.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/jsapi-components": "^1.17.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/jsapi-utils": "^1.16.0", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/storage": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/modifiers": "^9.0.0", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "@hello-pangea/dnd": "^18.0.1", + "@tanstack/react-virtual": "^3.13.12", + "classnames": "^2.3.1", + "fast-deep-equal": "^3.1.3", + "lodash.clamp": "^4.0.3", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.43.0", + "nanoid": "^5.0.7", + "react-transition-group": "^4.4.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-1.17.0.tgz", + "integrity": "sha512-6ppKiIEauOsaoQqNVvnuy/sAUQ08jlt1oqpA+zDGExa4johJQznGtw33OlTCDpmOINui8JEQy8XRdRne/ND9tw==", + "license": "Apache-2.0", + "dependencies": { + "@astral-sh/ruff-wasm-web": "0.6.4", + "@deephaven/chart": "^1.17.0", + "@deephaven/components": "^1.17.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/jsapi-bootstrap": "^1.17.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/jsapi-utils": "^1.16.0", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/storage": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "classnames": "^2.3.1", + "linkifyjs": "^4.1.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.43.0", + "nanoid": "^5.0.7", + "papaparse": "5.3.2", + "popper.js": "^1.16.1", + "shell-quote": "^1.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console/node_modules/@deephaven/chart": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/chart/-/chart-1.17.0.tgz", + "integrity": "sha512-5HG0YfZrMali/6NVtKidpDYO+vOdLq2piWiwqHZf2XApdhwrn502I8xj1w2KsSLhbMJH8X6HFRMsqLLQjDZvbA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/jsapi-utils": "^1.16.0", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/utils": "^1.10.0", + "buffer": "^6.0.3", + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "plotly.js": "3.1.0", + "react-plotly.js": "^2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console/node_modules/@deephaven/jsapi-bootstrap": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-1.17.0.tgz", + "integrity": "sha512-0ffPtsrq0oTOzfjwG/JYx7gMVIrJ0125Axk0yDt1/ozOnPzVMSN9MpK9EtUyGxgckWCdCwvQ8XYgkYtliNmHPw==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/utils": "^1.10.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/jsapi-components": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-1.17.0.tgz", + "integrity": "sha512-am7GSuDiAa2L8+otndrK3wQ5HIZOiSnxBf/ytIEZo9J+bpuCuDH31J5E1GrXWNnRjKxEqSACwk7e5+fCysJXbw==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/jsapi-bootstrap": "^1.17.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/jsapi-utils": "^1.16.0", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/utils": "^1.10.0", + "@types/js-cookie": "^3.0.3", + "classnames": "^2.3.2", + "js-cookie": "^3.0.5", + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/jsapi-components/node_modules/@deephaven/jsapi-bootstrap": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-1.17.0.tgz", + "integrity": "sha512-0ffPtsrq0oTOzfjwG/JYx7gMVIrJ0125Axk0yDt1/ozOnPzVMSN9MpK9EtUyGxgckWCdCwvQ8XYgkYtliNmHPw==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^1.17.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/log": "^1.8.0", + "@deephaven/react-hooks": "^1.14.0", + "@deephaven/utils": "^1.10.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/storage": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-1.8.0.tgz", + "integrity": "sha512-uQm87RZofAsmhLzt4wayME5b6d7/H86PR5NTjdj4z9dV2KBVUpSryTUAkx84t3G6XVsOH4A5Xb7PtmXWh5Mz4g==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/filters": "^1.1.0", + "@deephaven/log": "^1.8.0", + "lodash.throttle": "^4.1.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@dnd-kit/modifiers": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/modifiers/-/modifiers-9.0.0.tgz", + "integrity": "sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@hello-pangea/dnd": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz", + "integrity": "sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.26.7", + "css-box-model": "^1.2.1", + "raf-schd": "^4.0.3", + "react-redux": "^9.2.0", + "redux": "^5.0.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@hello-pangea/dnd/node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@tanstack/react-virtual": { + "version": "3.13.23", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.23.tgz", + "integrity": "sha512-XnMRnHQ23piOVj2bzJqHrRrLg4r+F86fuBcwteKfbIjJrtGxb4z7tIvPVAe4B+4UVwo9G4Giuz5fmapcrnZ0OQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.23" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/react-hooks": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-1.14.0.tgz", + "integrity": "sha512-VWRU6Hka5GyN0zO5LJYI5YgKrEsf0xAKrQ5LnEX4WSloB1C5DFoS1K1kH3fPqVBhid5JTu7R7oe0y4Tvt4wesQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^1.8.0", + "@deephaven/utils": "^1.10.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.5" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/plugin/node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT", + "peer": true + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/redux": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@deephaven/redux/-/redux-1.17.0.tgz", + "integrity": "sha512-pbq1Npd0JHkZDiK7gt5Oj4EVJuikQ76Jd0qoo20P5Ouan5M2iZg3HZNHVmicAJHA9p7+EmYAeXpHS52rUmQszg==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.40.4", + "@deephaven/jsapi-utils": "^1.16.0", + "@deephaven/log": "^1.8.0", + "fast-deep-equal": "^3.1.3", + "lodash.mergewith": "^4.6.2", + "proxy-memoize": "^3.0.0", + "redux-thunk": "2.4.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "redux": "^4.2.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/redux/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-1.10.0.tgz", + "integrity": "sha512-KLs73wIU/T3ZA+H+YTlzQ1fT+6p02RfixMQ7+l8S+IyLxc+nwSMABYnoZybJJuRvw1huJuFv1+n0B0HDteDFZA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/log": "^1.8.0", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/@deephaven/utils/node_modules/@deephaven/log": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.8.0.tgz", + "integrity": "sha512-gzp6/7qW4W8Re+DLSaG33KEQJ30OrrNq3cNQA8fUeXQrabSNOIsyeVOaerQ/57c4zWhWVKamplax0LIYRsmDiw==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/color-rgba": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", + "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", + "license": "MIT", + "dependencies": { + "color-parse": "^2.0.0", + "color-space": "^2.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/color-space": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.3.2.tgz", + "integrity": "sha512-BcKnbOEsOarCwyoLstcoEztwT0IJxqqQkNwDuA3a65sICvvHL2yoeV13psoDFh5IuiOMnIOKdQDwB4Mk3BypiA==", + "license": "Unlicense" + }, + "plugins/tradingview-lightweight/src/js/node_modules/plotly.js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.1.0.tgz", + "integrity": "sha512-vx+CyzApL9tquFpwoPHOGSIWDbFPsA4om/tXZcnsygGUejXideDF9R5VwkltEIDG7Xuof45quVPyz1otv6Aqjw==", + "license": "MIT", + "dependencies": { + "@plotly/d3": "3.8.2", + "@plotly/d3-sankey": "0.7.2", + "@plotly/d3-sankey-circular": "0.33.1", + "@plotly/mapbox-gl": "1.13.4", + "@plotly/regl": "^2.1.2", + "@turf/area": "^7.1.0", + "@turf/bbox": "^7.1.0", + "@turf/centroid": "^7.1.0", + "base64-arraybuffer": "^1.0.2", + "canvas-fit": "^1.5.0", + "color-alpha": "1.0.4", + "color-normalize": "1.5.0", + "color-parse": "2.0.0", + "color-rgba": "3.0.0", + "country-regex": "^1.1.0", + "d3-force": "^1.2.1", + "d3-format": "^1.4.5", + "d3-geo": "^1.12.1", + "d3-geo-projection": "^2.9.0", + "d3-hierarchy": "^1.1.9", + "d3-interpolate": "^3.0.1", + "d3-time": "^1.1.0", + "d3-time-format": "^2.2.3", + "fast-isnumeric": "^1.1.4", + "gl-mat4": "^1.2.0", + "gl-text": "^1.4.0", + "has-hover": "^1.0.1", + "has-passive-events": "^1.0.0", + "is-mobile": "^4.0.0", + "maplibre-gl": "^4.7.1", + "mouse-change": "^1.4.0", + "mouse-event-offset": "^3.0.2", + "mouse-wheel": "^1.2.0", + "native-promise-only": "^0.8.1", + "parse-svg-path": "^0.1.2", + "point-in-polygon": "^1.1.0", + "polybooljs": "^1.2.2", + "probe-image-size": "^7.2.3", + "regl-error2d": "^2.0.12", + "regl-line2d": "^3.1.3", + "regl-scatter2d": "^3.3.1", + "regl-splom": "^1.0.14", + "strongly-connected-components": "^1.0.1", + "superscript-text": "^1.0.0", + "svg-path-sdf": "^1.1.3", + "tinycolor2": "^1.4.2", + "to-px": "1.0.1", + "topojson-client": "^3.1.0", + "webgl-context": "^2.2.0", + "world-calendars": "^1.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "license": "MIT", + "peerDependencies": { + "redux": "^4" + } + }, + "plugins/tradingview-lightweight/src/js/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "plugins/ui/src/js": { + "name": "@deephaven/js-plugin-ui", + "version": "0.32.1", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/chart": "^1.5.1", + "@deephaven/components": "^1.5.1", + "@deephaven/console": "^1.5.1", + "@deephaven/dashboard": "^1.5.1", + "@deephaven/dashboard-core-plugins": "^1.5.1", + "@deephaven/golden-layout": "^1.5.1", + "@deephaven/grid": "^1.3.0", + "@deephaven/icons": "^1.2.0", + "@deephaven/iris-grid": "^1.5.1", + "@deephaven/jsapi-bootstrap": "^1.5.1", "@deephaven/jsapi-components": "^1.5.1", "@deephaven/jsapi-types": "^1.0.0-dev0.39.6", "@deephaven/jsapi-utils": "^1.4.0", @@ -35546,14 +36742,6 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } - }, - "plugins/ui/src/js/node_modules/world-calendars": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", - "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", - "dependencies": { - "object-assign": "^4.1.0" - } } } } diff --git a/plugins/tradingview-lightweight/.gitignore b/plugins/tradingview-lightweight/.gitignore new file mode 100644 index 000000000..2d5572acd --- /dev/null +++ b/plugins/tradingview-lightweight/.gitignore @@ -0,0 +1,11 @@ +build/ +dist/ +.venv/ +/venv +*.egg-info/ +.idea +.DS_store +__pycache__/ +.server-venv/ +.app.d/ +notes/tmp/ \ No newline at end of file diff --git a/plugins/tradingview-lightweight/AGENTS.md b/plugins/tradingview-lightweight/AGENTS.md new file mode 100644 index 000000000..b2df28951 --- /dev/null +++ b/plugins/tradingview-lightweight/AGENTS.md @@ -0,0 +1,165 @@ +# Local Development & Testing + +## Quick Start + +```bash +# Start server (builds JS, installs plugin, launches DH server on port 10000) +bash start-server.sh + +# Stop server (kills all DH processes, closes browser) +bash stop-server.sh +``` + +After code changes, re-run `bash start-server.sh` — it rebuilds and restarts automatically. + +The ticking/by tests require `deephaven-plugin-ui`: +```bash +# One-time: install deephaven-plugin-ui into the server venv +.server-venv/bin/pip install deephaven-plugin-ui +``` + +## Testing with agent-browser + +After the server is running: + +```bash +# Open the IDE and set viewport +agent-browser open http://localhost:10000/ide/ +agent-browser wait --load networkidle +agent-browser wait 5000 +agent-browser set viewport 1920 1080 +``` + +### Running code in the DH console + +The DH IDE opens panels for **new variable assignments**, not bare expressions. +Typing `tvl_line` alone will not open a panel. You must assign to a new name: + +```bash +# 1. Find the console editor +agent-browser snapshot -i # look for the textbox ref +agent-browser click @e15 # click the editor (ref may vary) + +# 2. Type a variable assignment and execute +agent-browser keyboard type "my_chart = tvl_line" +agent-browser press Escape # dismiss autocomplete +agent-browser wait 100 +agent-browser press Enter # execute (Enter works; Ctrl+Enter may not) +agent-browser wait 5000 # wait for panel to open and data to load + +# 3. Move mouse away and screenshot +agent-browser mouse move 0 0 +agent-browser wait 500 +agent-browser screenshot /tmp/tvl_test.png +``` + +Multi-statement commands work the same way: +```bash +agent-browser keyboard type "from deephaven.plot import tradingview_lightweight as tvl" +agent-browser press Escape && agent-browser wait 100 && agent-browser press Enter +agent-browser wait 2000 + +agent-browser keyboard type "my_by = tvl.line(_by_table, time='Timestamp', value='Price', by='Sym')" +agent-browser press Escape && agent-browser wait 100 && agent-browser press Enter +agent-browser wait 5000 +``` + +To verify a panel opened, check the Golden Layout tabs: +```bash +agent-browser eval "JSON.stringify(Array.from(document.querySelectorAll('.lm_tab')).map(e => e.textContent).filter(t => t.length > 0))" +# Should include your variable name, e.g. ["Console","Log","Command History","File Explorer","my_chart"] +``` + +### Opening widgets from the Panels menu (alternative) + +The Panels menu lists all exported variables. This approach does NOT +reliably open widget panels — it works for tables but may silently +fail for plugin widgets. Prefer the console assignment method above. + +```bash +agent-browser snapshot -i -c +agent-browser click @e3 # "Panels" button — ref may vary +agent-browser wait 500 +agent-browser snapshot -i -c # find the search box ref +agent-browser fill @e7 "tvl_candlestick" +agent-browser wait 500 +agent-browser snapshot -i -c # find the button ref +agent-browser click @e11 # ref may vary +agent-browser wait 3000 +``` + +### Screenshotting an individual chart + +After opening a chart panel, isolate the chart and screenshot: +```bash +# Move mouse off chart to avoid hover tooltips +agent-browser mouse move 0 0 +agent-browser wait 500 + +# Screenshot the full page (chart will be visible in the panel area) +agent-browser screenshot /tmp/tvl_chart.png + +# Or check for chart elements +agent-browser eval "document.querySelectorAll('.dh-tvl-chart').length" +``` + +View the screenshot with the `Read` tool on the image path. + +### Important Notes + +- **Refs change between snapshots.** Always run `agent-browser snapshot -i` before clicking to get fresh refs. +- **Charts render on canvas.** Use screenshots to verify chart content — DOM queries won't see rendered lines/candles. +- **Use variable assignments** to open widget panels (e.g., `my_chart = tvl_line`). Bare expressions evaluate but don't open panels. +- **Enter, not Ctrl+Enter.** Plain `Enter` executes single-line commands. `Ctrl+Enter` may insert a newline instead. +- **Dismiss autocomplete** with `agent-browser press Escape` before pressing Enter, otherwise it may select a completion instead of executing. +- **Zombie processes.** If the server seems stale (serving old JS), run `bash stop-server.sh` which kills all DH-related processes aggressively. + +## How It Works + +`start-server.sh`: +1. Creates `.server-venv/` with `deephaven-server` + `deephaven-plugin-utilities` (skipped if exists) +2. Builds JS via `npm run build` in `src/js/` +3. Builds a Python wheel and installs it into `.server-venv/` +4. Copies test fixtures from `tests/app.d/` into `.app.d/` +5. Starts the DH server on port 10000 using the Python Server API +6. Waits for the server to be ready + +The DH web client loads the JS plugin via `/js-plugins/manifest.json`. The CJS bundle uses `require()` for modules the DH client provides (react, @deephaven/plugin, etc.) — these are resolved by the client's built-in require shim. + +## API Reference Notes + +Comprehensive TradingView Lightweight Charts v5.1 API documentation is in `notes/api-reference/`. + +**Index:** `notes/api-reference/INDEX.md` — links to all sub-pages with quick lookup tables. + +| File | What's Covered | +|------|---------------| +| `enumerations.md` | All 11 enums (LineStyle, CrosshairMode, PriceScaleMode, TickMarkType, etc.) | +| `chart-api.md` | `IChartApi` (26 methods), `ChartOptionsBase`, layout, grid, crosshair, watermark, scroll/scale options | +| `series-api.md` | `ISeriesApi` (5 props, 20 methods) — setData/update, price lines, primitives | +| `series-types.md` | Data interfaces per series type + all style options with defaults | +| `time-scale-api.md` | `ITimeScaleApi` (22 methods), `TimeScaleOptions` (25+ props), Time/BusinessDay/UTCTimestamp | +| `price-scale-api.md` | `IPriceScaleApi`, `PriceScaleOptions`, `PriceLineOptions`, `IPriceLine` | +| `markers-events.md` | SeriesMarker, MouseEventParams, marker shapes/positions, touch events | +| `functions-variables.md` | createChart, createYieldCurveChart, watermark/marker factories, series definition variables | +| `panes-api.md` | `IPaneApi` (15 methods), stretch factors, pane primitives | +| `utility-types.md` | DeepPartial, Coordinate, Logical, LineWidth, PriceFormat, Background | + +Use these when you need to look up available properties/methods, default values, or type signatures without fetching the web docs. + +## Running Unit Tests + +```bash +# Python (uses uv-managed Python 3.13) +PY=/home/sandbox/.local/share/uv/python/cpython-3.13.12-linux-x86_64-gnu/bin/python3.13 +$PY -m pip install pytest --break-system-packages +$PY -m pytest test/ -v + +# JavaScript +cd src/js +npx jest --verbose + +# TypeScript type check +cd src/js +npx tsc --noEmit +``` diff --git a/plugins/tradingview-lightweight/CLAUDE.md b/plugins/tradingview-lightweight/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/plugins/tradingview-lightweight/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/plugins/tradingview-lightweight/LICENSE b/plugins/tradingview-lightweight/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/plugins/tradingview-lightweight/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/tradingview-lightweight/Makefile b/plugins/tradingview-lightweight/Makefile new file mode 100644 index 000000000..35650b03c --- /dev/null +++ b/plugins/tradingview-lightweight/Makefile @@ -0,0 +1,7 @@ +.PHONY: install build + +install: + pip install -e ".[dev]" + +build: + python -m build --wheel diff --git a/plugins/tradingview-lightweight/PLAN.md b/plugins/tradingview-lightweight/PLAN.md new file mode 100644 index 000000000..3a5f43361 --- /dev/null +++ b/plugins/tradingview-lightweight/PLAN.md @@ -0,0 +1,305 @@ +# Plan: TradingView Lightweight Charts Plugin for Deephaven + +## Context + +We are building a new plugin `tradingview-lightweight` for the deephaven-plugins monorepo that wraps the [TradingView Lightweight Charts](https://tradingview.github.io/lightweight-charts/) JS library. Users will write Python code to create financial charts that render in the Deephaven web UI. The import pattern is: + +```python +from deephaven.plot import tradingview_lightweight as tvl +``` + +The plugin follows the established patterns from `plotly-express` (BidirectionalObjectType, MessageStream, JS WidgetPlugin) but renders via lightweight-charts instead of Plotly. + +--- + +## Agent Team Strategy + +The coordinator spawns specialized agents and tracks progress. **No code or research by the coordinator** -- all work delegated to agents. + +### Agent Assignments + +| # | Agent | Responsibility | Dependencies | +|---|-------|---------------|-------------| +| 1 | **Scaffold Agent** | Create the full directory structure, build configs, namespace packages | None | +| 2 | **Python Core Agent** | TvlChart, SeriesSpec, registration, connection, listener | Agent 1 | +| 3 | **Python API Agent** | Series functions, chart(), convenience functions, options, markers | Agent 2 | +| 4 | **JS Plugin Agent** | TradingViewPlugin.ts, index.ts, package.json, vite.config.ts, tsconfig.json | Agent 1 | +| 5 | **JS Renderer Agent** | TradingViewChartRenderer.ts (imperative wrapper around lightweight-charts) | Agent 4 | +| 6 | **JS Model Agent** | TradingViewChartModel.ts (table subscriptions, data hydration) | Agent 4 | +| 7 | **JS Component Agent** | TradingViewChart.tsx, TradingViewChartPanel.tsx, hooks, theming | Agents 5, 6 | +| 8 | **Python Tests Agent** | Unit tests for Python side following plotly-express test patterns | Agent 3 | +| 9 | **JS Tests Agent** | Unit tests for JS side following plotly-express Jest patterns | Agent 7 | +| 10 | **Integration Agent** | Build verification, agent-browser visual testing | Agents 8, 9 | + +### Execution Waves + +- **Wave 1** (parallel): Agents 1 + 4 (scaffold + JS boilerplate) +- **Wave 2** (parallel): Agents 2 + 5 + 6 (Python core + JS renderer + JS model) +- **Wave 3** (parallel): Agents 3 + 7 (Python API + JS components) +- **Wave 4** (parallel): Agents 8 + 9 (tests) +- **Wave 5**: Agent 10 (integration + verification) + +--- + +## File Structure + +``` +plugins/tradingview-lightweight/ +├── setup.cfg # Python package metadata + entry point +├── setup.py # JS packaging (package_js) +├── pyproject.toml # Build system config +├── tox.ini # Python test config +├── Makefile # Build helpers +├── README.md +├── LICENSE +├── src/ +│ ├── deephaven/ +│ │ └── plot/ +│ │ └── tradingview_lightweight/ +│ │ ├── __init__.py # Exports + TvlChartType (BidirectionalObjectType) +│ │ ├── _register.py # TvlRegistration class +│ │ ├── _types.py # Type aliases (TableLike, etc.) +│ │ ├── chart.py # TvlChart class + chart() + convenience fns +│ │ ├── series.py # Series creation functions (6 types) +│ │ ├── options.py # Literal types, PriceFormat, etc. +│ │ ├── markers.py # marker(), price_line(), markers_from_table() +│ │ ├── communication/ +│ │ │ ├── __init__.py +│ │ │ ├── connection.py # TvlChartConnection (MessageStream) +│ │ │ └── listener.py # TvlChartListener (table listeners) +│ │ └── _js/ # Auto-populated by package_js at build +│ └── js/ +│ ├── package.json # @deephaven/js-plugin-tradingview-lightweight +│ ├── tsconfig.json +│ ├── vite.config.ts +│ ├── jest.config.cjs +│ └── src/ +│ ├── index.ts # Plugin export +│ ├── TradingViewPlugin.ts # WidgetPlugin definition +│ ├── TradingViewChart.tsx # Main React component +│ ├── TradingViewChartPanel.tsx # Panel wrapper +│ ├── TradingViewChartModel.ts # Data model (table subs, events) +│ ├── TradingViewChartRenderer.ts # Imperative chart wrapper +│ ├── TradingViewTheme.ts # CSS var -> chart options mapping +│ ├── TradingViewTheme.module.css # DH theme CSS var references +│ ├── TradingViewTypes.ts # Shared TS types +│ ├── TradingViewUtils.ts # Data transform utilities +│ ├── useChartLifecycle.ts # Chart create/update/destroy hook +│ ├── useResizeObserver.ts # Container resize hook +│ ├── DashboardPlugin.tsx # Legacy dashboard plugin +│ └── __tests__/ +│ ├── TradingViewChartModel.test.ts +│ ├── TradingViewChartRenderer.test.ts +│ └── TradingViewUtils.test.ts +└── test/ + └── deephaven/ + └── plot/ + └── tradingview_lightweight/ + ├── test_chart.py + ├── test_series.py + └── test_markers.py +``` + +--- + +## Python API Design + +### Approach: Hybrid (Composable primary, convenience wrappers) + +TradingView charts naturally compose multiple series. The primary API uses `tvl.chart(*series)` with series created by typed functions. Convenience functions wrap single-series use cases. + +### Series Functions (in `series.py`) + +Each returns a `SeriesSpec` dataclass: + +```text +def candlestick_series(table, time="Timestamp", open="Open", high="High", + low="Low", close="Close", up_color=None, down_color=None, + title=None, price_scale_id=None, markers=None, + price_lines=None, ...) -> SeriesSpec + +def bar_series(table, time, open, high, low, close, ...) -> SeriesSpec +def line_series(table, time, value, color=None, line_width=None, ...) -> SeriesSpec +def area_series(table, time, value, line_color=None, top_color=None, ...) -> SeriesSpec +def baseline_series(table, time, value, base_value=0.0, ...) -> SeriesSpec +def histogram_series(table, time, value, color=None, color_column=None, ...) -> SeriesSpec +``` + +### Chart Function (in `chart.py`) + +```text +def chart(*series: SeriesSpec, + background_color=None, text_color=None, + crosshair_mode=None, time_visible=None, seconds_visible=None, + right_price_scale_visible=None, left_price_scale_visible=None, + watermark_text=None, width=None, height=None, + ...) -> TvlChart +``` + +### Convenience Functions (also in `chart.py`) + +```text +def candlestick(table, time="Timestamp", open="Open", ...) -> TvlChart +def line(table, time="Timestamp", value="Value", ...) -> TvlChart +def area(table, ...) -> TvlChart +def bar(table, ...) -> TvlChart +def baseline(table, ...) -> TvlChart +def histogram(table, ...) -> TvlChart +``` + +### Annotations (in `markers.py`) + +```text +def marker(time, position="above_bar", shape="circle", color="#2196F3", text="") -> Marker +def price_line(price, color=None, line_width=None, title=None) -> PriceLine +def markers_from_table(table, time, position, shape, color, text) -> MarkerSpec +``` + +### Usage Examples + +```python +# Simple +chart = tvl.candlestick( + ohlc_table, time="Timestamp", open="Open", high="High", low="Low", close="Close" +) + +# Multi-series overlay +chart = tvl.chart( + tvl.candlestick_series( + ohlc_table, time="Timestamp", open="Open", high="High", low="Low", close="Close" + ), + tvl.line_series( + sma_table, time="Timestamp", value="SMA_20", color="#2962FF", title="SMA 20" + ), + tvl.histogram_series( + vol_table, time="Timestamp", value="Volume", price_scale_id="volume" + ), + crosshair_mode="magnet", + time_visible=True, + watermark_text="AAPL", +) +``` + +--- + +## JavaScript Architecture + +### Plugin Registration (`TradingViewPlugin.ts`) + +```typescript +export const TradingViewPlugin: WidgetPlugin = { + name: '@deephaven/tradingview-lightweight', + type: PluginType.WIDGET_PLUGIN, + supportedTypes: 'deephaven.plot.tradingview_lightweight.TvlChart', + component: TradingViewChart, + panelComponent: TradingViewChartPanel, + icon: vsGraph, +}; +``` + +### Three-Layer JS Architecture + +1. **TradingViewChart.tsx** (React) -- calls `fetch()`, creates Model + Renderer, wires them together +2. **TradingViewChartModel.ts** (Data) -- manages widget messages, table subscriptions, emits data events +3. **TradingViewChartRenderer.ts** (Rendering) -- imperative wrapper around `createChart()` / `ISeriesApi` + +### Data Flow + +``` +Python TvlChart.to_json() → JSON message with chart config + table refs + ↓ +JS Widget fetch() → parse config, get exported table objects + ↓ +TradingViewChartModel subscribes to tables → receives column data + ↓ +Model transforms columns into {time, open, high, low, close} arrays + ↓ +TradingViewChartRenderer.setSeriesData() / .updateSeries() +``` + +### Message Protocol + +- Client → Server: `{ "type": "RETRIEVE" }` +- Server → Client: `{ "type": "NEW_FIGURE", "figure": {...}, "revision": N, "new_references": [...], "removed_references": [...] }` + +### Real-Time Updates + +- Single-row append → `series.update(point)` (O(1)) +- Multi-row change → `series.setData(allData)` (full refresh) +- Config change → `chart.applyOptions()` + series reconfiguration + +### Theming + +`TradingViewTheme.module.css` maps `--dh-color-chart-*` CSS variables. Resolved at runtime via `getComputedStyle`. Applied to chart via `chart.applyOptions()`. Re-applied on theme change. + +--- + +## Critical Files to Reference + +| Purpose | File | +|---------|------| +| Registration pattern | `plugins/plotly-express/src/deephaven/plot/express/_register.py` | +| BidirectionalObjectType | `plugins/plotly-express/src/deephaven/plot/express/__init__.py:57-113` | +| MessageStream connection | `plugins/plotly-express/src/deephaven/plot/express/communication/DeephavenFigureConnection.py` | +| Table listener | `plugins/plotly-express/src/deephaven/plot/express/communication/DeephavenFigureListener.py` | +| JS WidgetPlugin | `plugins/plotly-express/src/js/src/PlotlyExpressPlugin.ts` | +| JS chart component | `plugins/plotly-express/src/js/src/PlotlyExpressChart.tsx` | +| JS chart model | `plugins/plotly-express/src/js/src/PlotlyExpressChartModel.ts` | +| Vite config | `plugins/plotly-express/src/js/vite.config.ts` | +| setup.py packaging | `plugins/plotly-express/setup.py` | +| setup.cfg metadata | `plugins/plotly-express/setup.cfg` | +| Theme CSS vars | `plugins/theme-pack/src/js/src/*.css` (for `--dh-color-chart-*` variables) | + +--- + +## Build Configuration + +### Python (`setup.cfg`) +``` +name = deephaven-plugin-tradingview-lightweight +entry_point = deephaven.plot.tradingview_lightweight._register:TvlRegistration +deps = deephaven-core>=0.41.1, deephaven-plugin>=0.6.0, deephaven-plugin-utilities>=0.0.2 +``` + +### JS (`package.json`) +``` +name = @deephaven/js-plugin-tradingview-lightweight +deps: lightweight-charts ^5.1.0, @deephaven/plugin, @deephaven/components, @deephaven/icons, etc. +lightweight-charts is BUNDLED (not externalized) -- it's only ~45KB gzipped +``` + +### Vite +- CJS output to `dist/bundle/index.js` +- Externalize: react, react-dom, redux, @deephaven/* packages +- DO NOT externalize: `lightweight-charts` (bundle it) + +--- + +## Testing Strategy + +### Python Tests (`test/`) +- Unit tests for `TvlChart` serialization (chart config → JSON) +- Unit tests for `SeriesSpec` creation (column mappings, options) +- Unit tests for markers and price lines +- Pattern: `unittest.TestCase`, following `plugins/plotly-express/test/` + +### JS Tests (`src/js/src/__tests__/`) +- `TradingViewChartModel.test.ts` -- mock widget/table, verify data hydration +- `TradingViewChartRenderer.test.ts` -- mock lightweight-charts, verify API calls +- `TradingViewUtils.test.ts` -- data transformation unit tests +- Pattern: Jest with `@deephaven/test-utils` mocks, following plotly-express + +### Integration / Visual +- Use agent-browser to load a Deephaven session, create a chart, and screenshot +- Verify chart renders in the panel with correct data + +--- + +## Verification Plan + +1. **Build**: `cd plugins/tradingview-lightweight/src/js && npm install && npm run build` +2. **Python package**: `python -m build --wheel plugins/tradingview-lightweight` +3. **JS tests**: `npx jest --config plugins/tradingview-lightweight/src/js/jest.config.cjs` +4. **Python tests**: `cd plugins/tradingview-lightweight && python -m pytest test/` +5. **Visual**: Use agent-browser to load in Deephaven and confirm chart renders +6. **Lint**: `npx eslint plugins/tradingview-lightweight/src/js/src/` diff --git a/plugins/tradingview-lightweight/README.md b/plugins/tradingview-lightweight/README.md new file mode 100644 index 000000000..3c823c0af --- /dev/null +++ b/plugins/tradingview-lightweight/README.md @@ -0,0 +1,31 @@ +# deephaven-plugin-tradingview-lightweight + +A Deephaven plugin for creating TradingView Lightweight Charts from Python. + +## Usage + +```python +from deephaven.plot import tradingview_lightweight as tvl + +# Simple candlestick chart +chart = tvl.candlestick( + ohlc_table, + time="Timestamp", + open="Open", + high="High", + low="Low", + close="Close", +) + +# Multi-series chart +chart = tvl.chart( + tvl.candlestick_series( + ohlc_table, time="Timestamp", open="Open", high="High", low="Low", close="Close" + ), + tvl.line_series( + sma_table, time="Timestamp", value="SMA_20", color="#2962FF", title="SMA 20" + ), + crosshair_mode="magnet", + time_visible=True, +) +``` diff --git a/plugins/tradingview-lightweight/notes/api-reference/INDEX.md b/plugins/tradingview-lightweight/notes/api-reference/INDEX.md new file mode 100644 index 000000000..6640995f2 --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/INDEX.md @@ -0,0 +1,47 @@ +# TradingView Lightweight Charts v5.1 — API Reference + +Complete API reference for the [lightweight-charts](https://tradingview.github.io/lightweight-charts/docs/api) library. + +## Reference Files + +| File | Contents | +|------|----------| +| [enumerations.md](enumerations.md) | All 11 enums: ColorType, CrosshairMode, LineStyle, LineType, PriceScaleMode, TickMarkType, etc. | +| [chart-api.md](chart-api.md) | `IChartApi` (26 methods), `ChartOptionsBase`, `LayoutOptions`, `GridOptions`, `CrosshairOptions`, `WatermarkOptions`, scroll/scale/kinetic/localization options | +| [series-api.md](series-api.md) | `ISeriesApi` (5 properties, 20 methods) — data management, price lines, primitives, pane management | +| [series-types.md](series-types.md) | Data interfaces (AreaData, BarData, CandlestickData, LineData, BaselineData, HistogramData) + all style options per series type + `SeriesOptionsCommon` | +| [time-scale-api.md](time-scale-api.md) | `ITimeScaleApi` (22 methods), `TimeScaleOptions` (25+ properties), `Time` type, `BusinessDay`, `UTCTimestamp` | +| [price-scale-api.md](price-scale-api.md) | `IPriceScaleApi` (6 methods), `PriceScaleOptions` (13 properties), `PriceLineOptions` (10 properties), `IPriceLine` | +| [markers-events.md](markers-events.md) | `SeriesMarker`, `MouseEventParams`, `ISeriesMarkersPluginApi`, `TouchMouseEventData`, marker shapes/positions | +| [functions-variables.md](functions-variables.md) | `createChart`, `createChartEx`, `createYieldCurveChart`, watermark/marker factories, series definition variables | +| [panes-api.md](panes-api.md) | `IPaneApi` (15 methods), `PaneSize`, stretch factors, pane primitives | +| [utility-types.md](utility-types.md) | `DeepPartial`, `Coordinate`, `Logical`, `LineWidth`, `PriceFormat`, `Background`, `PriceScaleMargins` | + +## Quick Lookup + +### Chart Creation +```ts +createChart(container, options?) → IChartApi +createYieldCurveChart(container, options?) → IYieldCurveChartApi +``` + +### Adding Series (v5 API) +```ts +import { LineSeries, CandlestickSeries, ... } from 'lightweight-charts'; +const series = chart.addSeries(LineSeries, options?, paneIndex?); +``` + +### Series Types +`Line` | `Area` | `Baseline` | `Candlestick` | `Bar` | `Histogram` | `Custom` + +### Time Values +- `UTCTimestamp`: seconds since epoch (number) +- `BusinessDay`: `{ year, month, day }` +- ISO string: `'2021-02-03'` + +### Key Enums +- `LineStyle`: Solid=0, Dotted=1, Dashed=2, LargeDashed=3, SparseDotted=4 +- `LineType`: Simple=0, WithSteps=1, Curved=2 +- `CrosshairMode`: Normal=0, Magnet=1, Hidden=2, MagnetOHLC=3 +- `PriceScaleMode`: Normal=0, Logarithmic=1, Percentage=2, IndexedTo100=3 +- `TickMarkType`: Year=0, Month=1, DayOfMonth=2, Time=3, TimeWithSeconds=4 diff --git a/plugins/tradingview-lightweight/notes/api-reference/chart-api.md b/plugins/tradingview-lightweight/notes/api-reference/chart-api.md new file mode 100644 index 000000000..4f7497fba --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/chart-api.md @@ -0,0 +1,218 @@ +# IChartApi & Chart Options + +## IChartApi + +Returned by `createChart()`. 26 methods total. + +### Chart Lifecycle +| Method | Signature | Description | +|--------|-----------|-------------| +| `remove()` | `() → void` | Removes chart and all DOM elements (irreversible) | + +### Sizing +| Method | Signature | Description | +|--------|-----------|-------------| +| `resize()` | `(width, height, forceRepaint?) → void` | Set fixed dimensions; ignored if `autoSize` enabled | +| `paneSize()` | `(paneIndex?) → PaneSize` | Plot surface dimensions excluding scales | +| `autoSizeActive()` | `() → boolean` | Whether ResizeObserver auto-sizing is active | + +### Series Management +| Method | Signature | Description | +|--------|-----------|-------------| +| `addSeries()` | `(definition, options?, paneIndex?) → ISeriesApi` | Create series (v5: pass `LineSeries`, `CandlestickSeries`, etc.) | +| `addCustomSeries()` | `(customPaneView, options?, paneIndex?) → ISeriesApi<"Custom">` | Create custom-rendered series | +| `removeSeries()` | `(seriesApi) → void` | Remove a series (irreversible) | + +### Event Subscriptions +| Method | Signature | Description | +|--------|-----------|-------------| +| `subscribeClick()` | `(handler: MouseEventHandler) → void` | Chart click | +| `unsubscribeClick()` | `(handler) → void` | Remove click handler | +| `subscribeDblClick()` | `(handler) → void` | Double-click | +| `unsubscribeDblClick()` | `(handler) → void` | Remove double-click handler | +| `subscribeCrosshairMove()` | `(handler) → void` | Crosshair movement | +| `unsubscribeCrosshairMove()` | `(handler) → void` | Remove crosshair handler | + +### Scale APIs +| Method | Signature | Description | +|--------|-----------|-------------| +| `priceScale()` | `(priceScaleId, paneIndex?) → IPriceScaleApi` | Access a price scale | +| `timeScale()` | `() → ITimeScaleApi` | Access the time scale | +| `horzBehaviour()` | `() → IHorzScaleBehavior` | Horizontal scale behavior | + +### Configuration +| Method | Signature | Description | +|--------|-----------|-------------| +| `applyOptions()` | `(options: DeepPartial) → void` | Apply new chart options | +| `options()` | `() → Readonly` | Current options with defaults | + +### Visualization +| Method | Signature | Description | +|--------|-----------|-------------| +| `takeScreenshot()` | `(addTopLayer?, includeCrosshair?) → HTMLCanvasElement` | Generate screenshot canvas | +| `chartElement()` | `() → HTMLDivElement` | Container div for custom listeners | + +### Pane Management +| Method | Signature | Description | +|--------|-----------|-------------| +| `addPane()` | `(preserveEmptyPane?) → IPaneApi` | Add a new pane | +| `panes()` | `() → IPaneApi[]` | All pane APIs | +| `removePane()` | `(index) → void` | Remove pane by index | +| `swapPanes()` | `(first, second) → void` | Swap two panes | + +### Crosshair +| Method | Signature | Description | +|--------|-----------|-------------| +| `setCrosshairPosition()` | `(price, horizontalPosition, seriesApi) → void` | Position crosshair explicitly (for multi-chart sync) | +| `clearCrosshairPosition()` | `() → void` | Remove crosshair | + +--- + +## ChartOptionsBase + +Top-level options passed to `createChart()`. + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `width` | `number` | `0` | Chart width in pixels (0 = from container) | +| `height` | `number` | `0` | Chart height in pixels (0 = from container) | +| `autoSize` | `boolean` | `false` | Auto-resize via ResizeObserver | +| `layout` | `LayoutOptions` | — | Layout/appearance options | +| `leftPriceScale` | `PriceScaleOptions` | — | Left price scale | +| `rightPriceScale` | `PriceScaleOptions` | — | Right price scale | +| `overlayPriceScales` | `OverlayPriceScaleOptions` | — | Overlay price scale defaults | +| `timeScale` | `HorzScaleOptions` | — | Time scale options | +| `crosshair` | `CrosshairOptions` | — | Crosshair options | +| `grid` | `GridOptions` | — | Grid line options | +| `handleScroll` | `boolean \| HandleScrollOptions` | — | Scroll control | +| `handleScale` | `boolean \| HandleScaleOptions` | — | Scale/zoom control | +| `kineticScroll` | `KineticScrollOptions` | — | Momentum scrolling | +| `trackingMode` | `TrackingModeOptions` | — | Mobile tracking mode | +| `localization` | `LocalizationOptionsBase` | — | Locale/formatting | +| `addDefaultPane` | `boolean` | `true` | Create default pane automatically | + +--- + +## LayoutOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `background` | `Background` | `{ type: 'solid', color: '#FFFFFF' }` | Chart background (solid or vertical gradient) | +| `textColor` | `string` | `'#191919'` | Text color on scales | +| `fontSize` | `number` | `12` | Font size (px) | +| `fontFamily` | `string` | `-apple-system, BlinkMacSystemFont, 'Trebuchet MS', Roboto, Ubuntu, sans-serif` | Font family | +| `panes` | `LayoutPanesOptions` | `{ enableResize: true, separatorColor: '#2B2B43', separatorHoverColor: 'rgba(178, 181, 189, 0.2)' }` | Pane separator options | +| `attributionLogo` | `boolean` | `true` | Show TradingView logo | +| `colorSpace` | `ColorSpace` | `'srgb'` | Canvas color space (set at creation only) | +| `colorParsers` | `CustomColorParser[]` | `[]` | Custom color parser functions | + +--- + +## GridOptions + +| Property | Type | Description | +|----------|------|-------------| +| `vertLines` | `GridLineOptions` | Vertical grid lines | +| `horzLines` | `GridLineOptions` | Horizontal grid lines | + +### GridLineOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `color` | `string` | `'#D6DCDE'` | Line color | +| `style` | `LineStyle` | `LineStyle.Solid` | Line style | +| `visible` | `boolean` | `true` | Show lines | + +--- + +## CrosshairOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `mode` | `CrosshairMode` | `Magnet` | Crosshair behavior mode | +| `vertLine` | `CrosshairLineOptions` | — | Vertical line options | +| `horzLine` | `CrosshairLineOptions` | — | Horizontal line options | +| `doNotSnapToHiddenSeriesIndices` | `boolean` | `false` | Skip hidden series when snapping | + +### CrosshairLineOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `color` | `string` | `'#758696'` | Line color | +| `width` | `LineWidth` | `1` | Line width | +| `style` | `LineStyle` | `LargeDashed` | Line style | +| `visible` | `boolean` | `true` | Show line | +| `labelVisible` | `boolean` | `true` | Show label on scale | +| `labelBackgroundColor` | `string` | `'#4c525e'` | Label background | + +--- + +## Watermark Options + +### TextWatermarkOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `visible` | `boolean` | `true` | Show watermark | +| `horzAlign` | `HorzAlign` | `'center'` | Horizontal alignment | +| `vertAlign` | `VertAlign` | `'center'` | Vertical alignment | +| `lines` | `TextWatermarkLineOptions[]` | `[]` | Text lines | + +### TextWatermarkLineOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `text` | `string` | `''` | Watermark text (no word wrap) | +| `color` | `string` | `'rgba(0,0,0,0.5)'` | Text color | +| `fontSize` | `number` | `48` | Font size (px) | +| `lineHeight` | `number?` | `1.2 * fontSize` | Line height (px) | +| `fontFamily` | `string` | system default | Font family | +| `fontStyle` | `string` | `''` | Font style (e.g. `'italic'`) | + +### ImageWatermarkOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `maxWidth` | `number?` | — | Maximum image width | +| `maxHeight` | `number?` | — | Maximum image height | +| `padding` | `number` | `0` | Padding from chart edges | +| `alpha` | `number` | `1` | Opacity (0–1) | + +--- + +## HandleScrollOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `mouseWheel` | `boolean` | `true` | Scroll with mouse wheel | +| `pressedMouseMove` | `boolean` | `true` | Scroll by dragging | +| `horzTouchDrag` | `boolean` | `true` | Horizontal touch scroll | +| `vertTouchDrag` | `boolean` | `true` | Vertical touch scroll | + +## HandleScaleOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `mouseWheel` | `boolean` | `true` | Scale with mouse wheel | +| `pinch` | `boolean` | `true` | Pinch-to-zoom | +| `axisPressedMouseMove` | `boolean \| AxisPressedMouseMoveOptions` | — | Scale by dragging axis | +| `axisDoubleClickReset` | `boolean \| AxisDoubleClickOptions` | — | Reset scale on double-click | + +## KineticScrollOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `touch` | `boolean` | `true` | Kinetic scroll on touch | +| `mouse` | `boolean` | `false` | Kinetic scroll on mouse | + +--- + +## LocalizationOptionsBase + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `locale` | `string` | `navigator.language` | Locale for date formatting | +| `priceFormatter` | `PriceFormatterFn?` | — | Custom price formatter | +| `tickmarksPriceFormatter` | `TickmarksPriceFormatterFn?` | — | Custom price tick marks formatter | +| `percentageFormatter` | `PercentageFormatterFn?` | — | Custom percentage formatter | +| `tickmarksPercentageFormatter` | `TickmarksPercentageFormatterFn?` | — | Custom percentage tick formatter | diff --git a/plugins/tradingview-lightweight/notes/api-reference/enumerations.md b/plugins/tradingview-lightweight/notes/api-reference/enumerations.md new file mode 100644 index 000000000..7503c1acb --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/enumerations.md @@ -0,0 +1,81 @@ +# Enumerations + +## ColorType +| Member | Value | Description | +|--------|-------|-------------| +| `Solid` | `"solid"` | Solid color | +| `VerticalGradient` | `"gradient"` | Vertical gradient color | + +## CrosshairMode +| Member | Value | Description | +|--------|-------|-------------| +| `Normal` | `0` | Crosshair moves freely | +| `Magnet` | `1` | Snaps to close price (single-value or OHLC close) | +| `Hidden` | `2` | Crosshair disabled | +| `MagnetOHLC` | `3` | Snaps to nearest O/H/L/C price | + +## LastPriceAnimationMode +| Member | Value | Description | +|--------|-------|-------------| +| `Disabled` | `0` | Animation always disabled | +| `Continuous` | `1` | Animation always enabled | +| `OnDataUpdate` | `2` | Animation active after new data | + +## LineStyle +| Member | Value | Description | +|--------|-------|-------------| +| `Solid` | `0` | Solid line | +| `Dotted` | `1` | Dotted line | +| `Dashed` | `2` | Dashed line | +| `LargeDashed` | `3` | Dashed with bigger dashes | +| `SparseDotted` | `4` | Dotted with more spacing | + +## LineType +| Member | Value | Description | +|--------|-------|-------------| +| `Simple` | `0` | Straight line segments | +| `WithSteps` | `1` | Stepped line | +| `Curved` | `2` | Curved (spline) line | + +## MarkerSign +| Member | Value | Description | +|--------|-------|-------------| +| `Negative` | `-1` | Negative change | +| `Neutral` | `0` | No change | +| `Positive` | `1` | Positive change | + +## MismatchDirection +| Member | Value | Description | +|--------|-------|-------------| +| `NearestLeft` | `-1` | Search nearest left item | +| `None` | `0` | Do not search | +| `NearestRight` | `1` | Search nearest right item | + +## PriceLineSource +| Member | Value | Description | +|--------|-------|-------------| +| `LastBar` | `0` | Use last bar data | +| `LastVisible` | `1` | Use last visible data in viewport | + +## PriceScaleMode +| Member | Value | Description | +|--------|-------|-------------| +| `Normal` | `0` | Linear price range | +| `Logarithmic` | `1` | Logarithmic price range | +| `Percentage` | `2` | Percentage relative to first visible value (= 0%) | +| `IndexedTo100` | `3` | Like percentage but first value = 100 | + +## TickMarkType +| Member | Value | Description | +|--------|-------|-------------| +| `Year` | `0` | First tick in a year | +| `Month` | `1` | First tick in a month | +| `DayOfMonth` | `2` | A day of the month | +| `Time` | `3` | Time without seconds | +| `TimeWithSeconds` | `4` | Time with seconds | + +## TrackingModeExitMode +| Member | Value | Description | +|--------|-------|-------------| +| `OnTouchEnd` | `0` | Deactivate on touch end | +| `OnNextTap` | `1` | Deactivate on next tap | diff --git a/plugins/tradingview-lightweight/notes/api-reference/functions-variables.md b/plugins/tradingview-lightweight/notes/api-reference/functions-variables.md new file mode 100644 index 000000000..dec6f0499 --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/functions-variables.md @@ -0,0 +1,117 @@ +# Functions & Variables + +## Chart Creation + +### createChart() +```ts +createChart(container: string | HTMLElement, options?: DeepPartial): IChartApi +``` +Main entry point. Creates a time-based chart. + +### createChartEx() +```ts +createChartEx( + container: string | HTMLElement, + horzScaleBehavior: THorzScaleBehavior, + options?: DeepPartial<...> +): IChartApiBase +``` +Flexible horizontal scale. Use `createChart()` for standard time-based charts. + +### createYieldCurveChart() +```ts +createYieldCurveChart( + container: string | HTMLElement, + options?: DeepPartial +): IYieldCurveChartApi +``` +Specialized yield curve chart with linearly-spaced horizontal scale in monthly duration units. + +--- + +## Watermark Factories + +### createTextWatermark() +```ts +createTextWatermark( + pane: IPaneApi, + options: DeepPartial +): ITextWatermarkPluginApi +``` +Creates text watermark on a pane. Returns API with `applyOptions()` and `detach()`. + +### createImageWatermark() +```ts +createImageWatermark( + pane: IPaneApi, + imageUrl: string, + options: DeepPartial +): IImageWatermarkPluginApi +``` +Creates image watermark on a pane. + +--- + +## Marker Factories + +### createSeriesMarkers() +```ts +createSeriesMarkers( + series: ISeriesApi, + markers?: SeriesMarker[], + options?: ... +): ISeriesMarkersPluginApi +``` +Creates marker plugin attached to a series. Returns API with `setMarkers()`, `markers()`, `detach()`. + +### createUpDownMarkers() +```ts +createUpDownMarkers( + series: ISeriesApi, + options?: UpDownMarkersPluginOptions +): ISeriesUpDownMarkerPluginApi +``` +Creates up/down visual markers on series data. + +--- + +## Utility Functions + +### isBusinessDay() +```ts +isBusinessDay(time: Time): time is BusinessDay +``` +Type guard: checks if time is a `BusinessDay` object. + +### isUTCTimestamp() +```ts +isUTCTimestamp(time: Time): time is UTCTimestamp +``` +Type guard: checks if time is a numeric UTC timestamp. + +### version() +```ts +version(): string +``` +Returns library version string (e.g., `"5.1.0"`). + +--- + +## Series Definition Variables + +Used with `chart.addSeries()` in v5: + +```ts +import { LineSeries, CandlestickSeries, ... } from 'lightweight-charts'; +const series = chart.addSeries(LineSeries, options?); +``` + +| Variable | Type | Description | +|----------|------|-------------| +| `LineSeries` | `SeriesDefinition<"Line">` | Line series definition | +| `AreaSeries` | `SeriesDefinition<"Area">` | Area series definition | +| `BaselineSeries` | `SeriesDefinition<"Baseline">` | Baseline series definition | +| `CandlestickSeries` | `SeriesDefinition<"Candlestick">` | Candlestick series definition | +| `BarSeries` | `SeriesDefinition<"Bar">` | Bar series definition | +| `HistogramSeries` | `SeriesDefinition<"Histogram">` | Histogram series definition | +| `customSeriesDefaultOptions` | `CustomSeriesOptions` | Default options template for custom series | diff --git a/plugins/tradingview-lightweight/notes/api-reference/markers-events.md b/plugins/tradingview-lightweight/notes/api-reference/markers-events.md new file mode 100644 index 000000000..dc4c6d79b --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/markers-events.md @@ -0,0 +1,101 @@ +# Markers & Events + +## SeriesMarker + +Union type: `SeriesMarkerBar | SeriesMarkerPrice` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `time` | `Time` | Yes | Marker timestamp | +| `position` | `SeriesMarkerPosition` | Yes | Position relative to bar or price | +| `shape` | `SeriesMarkerShape` | Yes | Visual shape | +| `color` | `string` | Yes | Marker color | +| `id?` | `string` | No | Unique identifier | +| `text?` | `string` | No | Label text | +| `size?` | `number` | No | Size multiplier (default: 1) | +| `price?` | `number` | Conditional | Required for price-based positions | + +### SeriesMarkerShape +`'circle' | 'square' | 'arrowUp' | 'arrowDown'` + +### SeriesMarkerPosition +Bar positions: `'aboveBar' | 'belowBar' | 'inBar'` +Price positions: `'atPriceTop' | 'atPriceBottom' | 'atPriceMiddle'` (require `price` property) + +--- + +## ISeriesMarkersPluginApi + +Created by `createSeriesMarkers(series, markers?, options?)`. + +| Method | Signature | Description | +|--------|-----------|-------------| +| `setMarkers()` | `(markers: SeriesMarker[]) → void` | Set all markers | +| `markers()` | `() → readonly SeriesMarker[]` | Current markers | +| `detach()` | `() → void` | Detach plugin from series | +| `getSeries()` | `() → ISeriesApi` | Get parent series | +| `applyOptions()` | `(options) → void` | Apply plugin options | + +--- + +## MouseEventParams + +Passed to click/dblClick/crosshairMove handlers. + +| Property | Type | Optional | Description | +|----------|------|----------|-------------| +| `time` | `Time` | Yes | Time at mouse position (undefined if outside data) | +| `logical` | `Logical` | Yes | Logical index | +| `point` | `Point` | Yes | Pixel coordinates (undefined if outside chart) | +| `paneIndex` | `number` | Yes | Pane index | +| `seriesData` | `Map` | No | Data for all series at this position | +| `hoveredSeries` | `ISeriesApi` | Yes | Series under cursor | +| `hoveredObjectId` | `unknown` | Yes | Object under cursor | +| `sourceEvent` | `TouchMouseEventData` | Yes | Raw mouse/touch event data | + +### Point +```ts +interface Point { + x: Coordinate; + y: Coordinate; +} +``` + +### TouchMouseEventData + +| Property | Type | Description | +|----------|------|-------------| +| `clientX` | `Coordinate` | DOM-relative X | +| `clientY` | `Coordinate` | DOM-relative Y | +| `pageX` | `Coordinate` | Page X | +| `pageY` | `Coordinate` | Page Y | +| `screenX` | `Coordinate` | Screen X | +| `screenY` | `Coordinate` | Screen Y | +| `localX` | `Coordinate` | Chart-relative X | +| `localY` | `Coordinate` | Chart-relative Y | +| `ctrlKey` | `boolean` | Ctrl pressed | +| `altKey` | `boolean` | Alt pressed | +| `shiftKey` | `boolean` | Shift pressed | +| `metaKey` | `boolean` | Meta/Cmd pressed | + +--- + +## MouseEventHandler + +```ts +type MouseEventHandler = (param: MouseEventParams) => void; +``` + +--- + +## Range / LogicalRange + +```ts +interface IRange { + from: T; + to: T; +} + +type LogicalRange = IRange; +// from/to can be fractional (e.g., 5.2 means 6th bar is 20% visible) +``` diff --git a/plugins/tradingview-lightweight/notes/api-reference/panes-api.md b/plugins/tradingview-lightweight/notes/api-reference/panes-api.md new file mode 100644 index 000000000..344a62899 --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/panes-api.md @@ -0,0 +1,59 @@ +# Panes API + +## IPaneApi + +Returned by `chart.addPane()`, `chart.panes()`, or `series.getPane()`. + +| Method | Signature | Description | +|--------|-----------|-------------| +| `getHeight()` | `() → number` | Pane height (px) | +| `setHeight()` | `(height: number) → void` | Set pane height (px) | +| `moveTo()` | `(paneIndex: number) → void` | Move pane to new index (0-based) | +| `paneIndex()` | `() → number` | Current pane index | +| `getSeries()` | `() → ISeriesApi[]` | All series in this pane | +| `getHTMLElement()` | `() → HTMLElement` | Underlying HTML element | +| `priceScale()` | `(priceScaleId: string) → IPriceScaleApi` | Get price scale by ID | +| `getStretchFactor()` | `() → number` | Stretch factor (default: 1) | +| `setStretchFactor()` | `(factor: number) → void` | Set relative sizing vs other panes | +| `setPreserveEmptyPane()` | `(preserve: boolean) → void` | Keep pane when empty | +| `preserveEmptyPane()` | `() → boolean` | Current preservation setting | +| `addSeries()` | `(definition, options?) → ISeriesApi` | Add series to this pane | +| `addCustomSeries()` | `(customPaneView, options?) → ISeriesApi` | Add custom series | +| `attachPrimitive()` | `(primitive: IPanePrimitive) → void` | Attach drawing primitive | +| `detachPrimitive()` | `(primitive: IPanePrimitive) → void` | Detach drawing primitive | + +## PaneSize + +| Property | Type | Description | +|----------|------|-------------| +| `height` | `number` | Pane height (px) | +| `width` | `number` | Pane width (px) | + +## Pane Management via IChartApi + +```ts +const pane = chart.addPane(preserveEmptyPane?); // Add new pane +chart.panes(); // Get all panes +chart.removePane(index); // Remove by index +chart.swapPanes(first, second); // Swap positions +``` + +## Stretch Factors + +Stretch factors control relative pane sizes. Default is 1 for all panes. + +```ts +// Make bottom pane half the height of top +chart.panes()[0].setStretchFactor(2); +chart.panes()[1].setStretchFactor(1); +``` + +## Layout Pane Options + +Set via `chart.applyOptions({ layout: { panes: { ... } } })`: + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `enableResize` | `boolean` | `true` | Allow drag-resizing | +| `separatorColor` | `string` | `'#2B2B43'` | Separator line color | +| `separatorHoverColor` | `string` | `'rgba(178,181,189,0.2)'` | Separator hover color | diff --git a/plugins/tradingview-lightweight/notes/api-reference/price-scale-api.md b/plugins/tradingview-lightweight/notes/api-reference/price-scale-api.md new file mode 100644 index 000000000..748e1065b --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/price-scale-api.md @@ -0,0 +1,75 @@ +# Price Scale & Price Lines + +## IPriceScaleApi + +Returned by `chart.priceScale(id)` or `series.priceScale()`. + +| Method | Signature | Description | +|--------|-----------|-------------| +| `applyOptions()` | `(options: DeepPartial) → void` | Apply new options | +| `options()` | `() → Readonly` | Current options | +| `width()` | `() → number` | Width in px (0 if invisible) | +| `setVisibleRange()` | `(range: IRange) → void` | Set visible price range | +| `getVisibleRange()` | `() → IRange` | Get visible price range | +| `setAutoScale()` | `(on: boolean) → void` | Enable/disable autoscaling | + +--- + +## PriceScaleOptions + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `autoScale` | `boolean` | `true` | Auto-adjust to fit visible data | +| `mode` | `PriceScaleMode` | `Normal` | Normal / Logarithmic / Percentage / IndexedTo100 | +| `invertScale` | `boolean` | `false` | Invert price direction | +| `alignLabels` | `boolean` | `true` | Prevent label overlap | +| `scaleMargins` | `PriceScaleMargins` | `{ top: 0.2, bottom: 0.1 }` | Top/bottom margins (0–1) | +| `borderVisible` | `boolean` | `true` | Show border | +| `borderColor` | `string` | `'#2B2B43'` | Border color | +| `textColor?` | `string` | — | Override text color | +| `entireTextOnly` | `boolean` | `false` | Only show labels if fully visible | +| `visible` | `boolean` | `true` (right) / `false` (left) | Scale visibility | +| `ticksVisible` | `boolean` | `false` | Small tick lines on labels | +| `minimumWidth` | `number` | `0` | Minimum width (px) | +| `ensureEdgeTickMarksVisible` | `boolean` | `false` | Ensure ticks at boundaries | + +### PriceScaleMargins + +| Property | Type | Description | +|----------|------|-------------| +| `top` | `number` | Top margin (0–1, percentage of pane height) | +| `bottom` | `number` | Bottom margin (0–1, percentage of pane height) | + +### OverlayPriceScaleOptions +Same as `PriceScaleOptions` but without `visible` and `autoScale`. +Used for overlay series that don't affect the main price scales. + +--- + +## PriceLineOptions + +Options for `series.createPriceLine()`. + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `id?` | `string` | — | Optional identifier | +| `price` | `number` | `0` | Price level | +| `color` | `string` | `''` | Line color | +| `lineWidth` | `LineWidth` | `1` | Width (px) | +| `lineStyle` | `LineStyle` | `Solid` | Style | +| `lineVisible` | `boolean` | `true` | Show line | +| `axisLabelVisible` | `boolean` | `true` | Show label on price scale | +| `title` | `string` | `''` | Title on chart pane | +| `axisLabelColor` | `string` | `''` | Label background (empty = line color) | +| `axisLabelTextColor` | `string` | `''` | Label text color | + +--- + +## IPriceLine + +Returned by `series.createPriceLine()`. + +| Method | Signature | Description | +|--------|-----------|-------------| +| `applyOptions()` | `(options: Partial) → void` | Update options | +| `options()` | `() → Readonly` | Current options | diff --git a/plugins/tradingview-lightweight/notes/api-reference/series-api.md b/plugins/tradingview-lightweight/notes/api-reference/series-api.md new file mode 100644 index 000000000..7a8c10c1e --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/series-api.md @@ -0,0 +1,66 @@ +# ISeriesApi + +The series API for interacting with individual chart series. Returned by `chart.addSeries()`. + +## Properties + +| Property | Return Type | Description | +|----------|------------|-------------| +| `data()` | `readonly TData[]` | All bar data for the series | +| `options()` | `Readonly` | Currently applied options with defaults | +| `seriesType()` | `TSeriesType` | Current series type string | +| `seriesOrder()` | `number` | Zero-based render order index | +| `priceFormatter()` | `IPriceFormatter` | Current price formatter | + +## Data Methods + +| Method | Parameters | Return | Description | +|--------|-----------|--------|-------------| +| `setData()` | `data: TData[]` | `void` | Replace ALL series data (must be time-ordered) | +| `update()` | `bar: TData, historicalUpdate?: boolean` | `void` | Append or update latest data point | +| `pop()` | `count: number` | `TData[]` | Remove N items from end | +| `dataByIndex()` | `logicalIndex, mismatchDirection?` | `TData` | Get data at logical index | +| `subscribeDataChanged()` | `handler: DataChangedHandler` | `void` | Listen for data changes | +| `unsubscribeDataChanged()` | `handler` | `void` | Remove data change listener | + +## Coordinate Conversion + +| Method | Parameters | Return | Description | +|--------|-----------|--------|-------------| +| `priceToCoordinate()` | `price: number` | `Coordinate` | Price → pixel Y coordinate | +| `coordinateToPrice()` | `coordinate: number` | `BarPrice` | Pixel Y → price value | +| `barsInLogicalRange()` | `range, mismatchDirection?` | `BarsInfo` | Bars info within logical range | + +## Price Lines + +| Method | Parameters | Return | Description | +|--------|-----------|--------|-------------| +| `createPriceLine()` | `options: CreatePriceLineOptions` | `IPriceLine` | Create a new price line | +| `removePriceLine()` | `line: IPriceLine` | `void` | Delete a price line | +| `priceLines()` | — | `IPriceLine[]` | All attached price lines | + +## Configuration + +| Method | Parameters | Return | Description | +|--------|-----------|--------|-------------| +| `applyOptions()` | `options: TPartialOptions` | `void` | Update series options (partial) | +| `priceScale()` | — | `IPriceScaleApi` | Access the series' price scale | +| `lastValueData()` | `globalLast: boolean` | `LastValueDataResult` | Get last value data | + +## Primitives & Panes + +| Method | Parameters | Return | Description | +|--------|-----------|--------|-------------| +| `attachPrimitive()` | `primitive: ISeriesPrimitive` | `void` | Attach drawing primitive | +| `detachPrimitive()` | `primitive: ISeriesPrimitive` | `void` | Detach drawing primitive | +| `moveToPane()` | `paneIndex: number` | `void` | Move series to another pane | +| `setSeriesOrder()` | `order: number` | `void` | Set render order within pane | +| `getPane()` | — | `IPaneApi` | Get pane where series lives | + +## Usage Notes + +- `setData()` replaces all data; `update()` is incremental (append or update last point) +- `update()` with a time equal to the last bar updates that bar; a later time appends +- `historicalUpdate` flag on `update()` allows inserting data before the last bar +- `pop()` returns the removed items +- Price lines persist until explicitly removed with `removePriceLine()` diff --git a/plugins/tradingview-lightweight/notes/api-reference/series-types.md b/plugins/tradingview-lightweight/notes/api-reference/series-types.md new file mode 100644 index 000000000..19b9c0f30 --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/series-types.md @@ -0,0 +1,172 @@ +# Series Data Types & Style Options + +## Data Interfaces + +### SingleValueData (base for Line, Area, Baseline, Histogram) + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `time` | `Time` | Yes | Timestamp | +| `value` | `number` | Yes | Price value | +| `customValues?` | `Record` | No | Custom data for plugins | + +### OhlcData (base for Candlestick, Bar) + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `time` | `Time` | Yes | Timestamp | +| `open` | `number` | Yes | Open price | +| `high` | `number` | Yes | High price | +| `low` | `number` | Yes | Low price | +| `close` | `number` | Yes | Close price | +| `customValues?` | `Record` | No | Custom data for plugins | + +### LineData (extends SingleValueData) +Additional per-point overrides: +- `color?` — line color for this point + +### AreaData (extends SingleValueData) +Additional per-point overrides: +- `lineColor?` — line color +- `topColor?` — top fill color +- `bottomColor?` — bottom fill color + +### BaselineData (extends SingleValueData) +Additional per-point overrides: +- `topFillColor1?`, `topFillColor2?`, `topLineColor?` +- `bottomFillColor1?`, `bottomFillColor2?`, `bottomLineColor?` + +### HistogramData (extends SingleValueData) +Additional per-point overrides: +- `color?` — bar color for this point + +### CandlestickData (extends OhlcData) +Additional per-point overrides: +- `color?` — candle body color +- `borderColor?` — border color +- `wickColor?` — wick color + +### BarData (extends OhlcData) +Additional per-point overrides: +- `color?` — bar color + +--- + +## SeriesOptionsCommon (shared by ALL series types) + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `lastValueVisible` | `boolean` | `true` | Show label with latest price on price scale | +| `title` | `string` | `''` | Series name (shown on label) | +| `priceScaleId?` | `string` | `'right'` | Target price scale ID | +| `visible` | `boolean` | `true` | Series visibility (hides everything when false) | +| `priceLineVisible` | `boolean` | `true` | Show horizontal last-price line | +| `priceLineSource` | `PriceLineSource` | `LastBar` | Source for price line value | +| `priceLineWidth` | `LineWidth` | `1` | Price line width | +| `priceLineColor` | `string` | `''` | Price line color (empty = last bar color) | +| `priceLineStyle` | `LineStyle` | `Dashed` | Price line style | +| `priceFormat` | `PriceFormat` | `{ type: 'price', precision: 2, minMove: 0.01 }` | Price formatting | +| `baseLineVisible` | `boolean` | `true` | Baseline visibility (percentage/indexed modes) | +| `baseLineColor` | `string` | `'#B2B5BE'` | Baseline color | +| `baseLineWidth` | `LineWidth` | `1` | Baseline width | +| `baseLineStyle` | `LineStyle` | `Solid` | Baseline style | +| `autoscaleInfoProvider?` | `AutoscaleInfoProvider` | — | Custom autoscaling | +| `conflationThresholdFactor?` | `number` | — | Series-specific conflation | + +--- + +## Line Style Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `color` | `string` | `'#2196f3'` | Line color | +| `lineStyle` | `LineStyle` | `Solid` | Line style | +| `lineWidth` | `LineWidth` | `3` | Width (px) | +| `lineType` | `LineType` | `Simple` | Simple/stepped/curved | +| `lineVisible` | `boolean` | `true` | Show line | +| `pointMarkersVisible` | `boolean` | `false` | Circle markers on each point | +| `pointMarkersRadius?` | `number` | — | Marker radius (px) | +| `crosshairMarkerVisible` | `boolean` | `true` | Show crosshair marker | +| `crosshairMarkerRadius` | `number` | `4` | Marker radius (px) | +| `crosshairMarkerBorderColor` | `string` | `''` | Border color (empty = series color) | +| `crosshairMarkerBackgroundColor` | `string` | `''` | Background color (empty = series color) | +| `crosshairMarkerBorderWidth` | `number` | `2` | Border width (px) | +| `lastPriceAnimation` | `LastPriceAnimationMode` | `Disabled` | Animation mode | + +--- + +## Area Style Options + +Inherits all Line Style Options plus: + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `topColor` | `string` | `'rgba(46, 220, 135, 0.4)'` | Top fill color | +| `bottomColor` | `string` | `'rgba(40, 221, 100, 0)'` | Bottom fill color | +| `lineColor` | `string` | `'#33D778'` | Line color | +| `relativeGradient` | `boolean` | `false` | Gradient relative to base value | +| `invertFilledArea` | `boolean` | `false` | Fill above line instead | + +--- + +## Baseline Style Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `baseValue` | `BaseValuePrice` | `{ type: 'price', price: 0 }` | Base value | +| `topFillColor1` | `string` | `'rgba(38, 166, 154, 0.28)'` | Top area top fill | +| `topFillColor2` | `string` | `'rgba(38, 166, 154, 0.05)'` | Top area bottom fill | +| `topLineColor` | `string` | `'rgba(38, 166, 154, 1)'` | Top area line | +| `bottomFillColor1` | `string` | `'rgba(239, 83, 80, 0.05)'` | Bottom area top fill | +| `bottomFillColor2` | `string` | `'rgba(239, 83, 80, 0.28)'` | Bottom area bottom fill | +| `bottomLineColor` | `string` | `'rgba(239, 83, 80, 1)'` | Bottom area line | +| `lineWidth` | `LineWidth` | `3` | Width (px) | +| `lineStyle` | `LineStyle` | `Solid` | Style | +| `lineType` | `LineType` | `Simple` | Type | +| `lineVisible` | `boolean` | `true` | Show line | +| `relativeGradient` | `boolean` | `false` | Gradient relative to base | +| `pointMarkersVisible` | `boolean` | `false` | Point markers | +| `pointMarkersRadius?` | `number` | — | Marker radius | +| `crosshairMarkerVisible` | `boolean` | `true` | Show crosshair marker | +| `crosshairMarkerRadius` | `number` | `4` | Radius | +| `crosshairMarkerBorderColor` | `string` | `''` | Border color | +| `crosshairMarkerBackgroundColor` | `string` | `''` | Background color | +| `crosshairMarkerBorderWidth` | `number` | `2` | Border width | +| `lastPriceAnimation` | `LastPriceAnimationMode` | `Disabled` | Animation mode | + +--- + +## Candlestick Style Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `upColor` | `string` | `'#26a69a'` | Rising candle body | +| `downColor` | `string` | `'#ef5350'` | Falling candle body | +| `wickVisible` | `boolean` | `true` | Show wicks | +| `borderVisible` | `boolean` | `true` | Show borders | +| `borderColor` | `string` | `'#378658'` | Default border | +| `borderUpColor` | `string` | `'#26a69a'` | Rising border | +| `borderDownColor` | `string` | `'#ef5350'` | Falling border | +| `wickColor` | `string` | `'#737375'` | Default wick | +| `wickUpColor` | `string` | `'#26a69a'` | Rising wick | +| `wickDownColor` | `string` | `'#ef5350'` | Falling wick | + +--- + +## Bar Style Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `upColor` | `string` | `'#26a69a'` | Rising bar | +| `downColor` | `string` | `'#ef5350'` | Falling bar | +| `openVisible` | `boolean` | `true` | Show open tick | +| `thinBars` | `boolean` | `true` | Thin stick style | + +--- + +## Histogram Style Options + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `color` | `string` | `'#26a69a'` | Column color | +| `base` | `number` | `0` | Base level for columns | diff --git a/plugins/tradingview-lightweight/notes/api-reference/time-scale-api.md b/plugins/tradingview-lightweight/notes/api-reference/time-scale-api.md new file mode 100644 index 000000000..53e976d01 --- /dev/null +++ b/plugins/tradingview-lightweight/notes/api-reference/time-scale-api.md @@ -0,0 +1,134 @@ +# ITimeScaleApi & Time Types + +## ITimeScaleApi + +Returned by `chart.timeScale()`. 22 methods total. + +### Scrolling & Position + +| Method | Signature | Description | +|--------|-----------|-------------| +| `scrollPosition()` | `() → number` | Distance in bars from right edge to latest bar | +| `scrollToPosition()` | `(position, animated) → void` | Scroll to bar position | +| `scrollToRealTime()` | `() → void` | Restore default scroll (always animated) | + +### Visible Range + +| Method | Signature | Description | +|--------|-----------|-------------| +| `getVisibleRange()` | `() → Range