pylightcharts 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pylightcharts-0.1.0/LICENSE +26 -0
- pylightcharts-0.1.0/MANIFEST.in +10 -0
- pylightcharts-0.1.0/PKG-INFO +411 -0
- pylightcharts-0.1.0/README.md +370 -0
- pylightcharts-0.1.0/pylightcharts/__init__.py +54 -0
- pylightcharts-0.1.0/pylightcharts/abstract.py +1778 -0
- pylightcharts-0.1.0/pylightcharts/chart.py +265 -0
- pylightcharts-0.1.0/pylightcharts/compat.py +117 -0
- pylightcharts-0.1.0/pylightcharts/drawings.py +513 -0
- pylightcharts-0.1.0/pylightcharts/headless.py +164 -0
- pylightcharts-0.1.0/pylightcharts/indicators.py +228 -0
- pylightcharts-0.1.0/pylightcharts/indicators_api.py +309 -0
- pylightcharts-0.1.0/pylightcharts/js/bundle.js +1 -0
- pylightcharts-0.1.0/pylightcharts/js/index.html +17 -0
- pylightcharts-0.1.0/pylightcharts/js/lightweight-charts.js +7 -0
- pylightcharts-0.1.0/pylightcharts/js/styles.css +237 -0
- pylightcharts-0.1.0/pylightcharts/numeric.py +58 -0
- pylightcharts-0.1.0/pylightcharts/polygon.py +396 -0
- pylightcharts-0.1.0/pylightcharts/polygon_chart.py +93 -0
- pylightcharts-0.1.0/pylightcharts/price_scale.py +72 -0
- pylightcharts-0.1.0/pylightcharts/qt.py +65 -0
- pylightcharts-0.1.0/pylightcharts/shapes.py +146 -0
- pylightcharts-0.1.0/pylightcharts/table.py +138 -0
- pylightcharts-0.1.0/pylightcharts/toolbox.py +45 -0
- pylightcharts-0.1.0/pylightcharts/topbar.py +128 -0
- pylightcharts-0.1.0/pylightcharts/util.py +378 -0
- pylightcharts-0.1.0/pylightcharts/widgets.py +260 -0
- pylightcharts-0.1.0/pylightcharts.egg-info/PKG-INFO +411 -0
- pylightcharts-0.1.0/pylightcharts.egg-info/SOURCES.txt +32 -0
- pylightcharts-0.1.0/pylightcharts.egg-info/dependency_links.txt +1 -0
- pylightcharts-0.1.0/pylightcharts.egg-info/requires.txt +27 -0
- pylightcharts-0.1.0/pylightcharts.egg-info/top_level.txt +1 -0
- pylightcharts-0.1.0/pyproject.toml +50 -0
- pylightcharts-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 louisnw01 (lightweight-charts-python)
|
|
4
|
+
Copyright (c) 2025 pylightcharts contributors
|
|
5
|
+
|
|
6
|
+
This project is a derivative work based on lightweight-charts-python
|
|
7
|
+
(https://github.com/louisnw01/lightweight-charts-python, MIT).
|
|
8
|
+
It embeds TradingView Lightweight Charts™ (Apache-2.0), see NOTICE.
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Keep dev-only / reference trees out of the sdist.
|
|
2
|
+
# (The wheel is already limited by `packages = ["pylightcharts"]`.)
|
|
3
|
+
prune reference
|
|
4
|
+
prune jslib
|
|
5
|
+
prune examples
|
|
6
|
+
prune tests
|
|
7
|
+
prune dist
|
|
8
|
+
prune build
|
|
9
|
+
global-exclude *.py[cod]
|
|
10
|
+
global-exclude __pycache__/*
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pylightcharts
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: TradingView Lightweight Charts for Python (bridged, near-full API coverage)
|
|
5
|
+
Author: pylightcharts contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/your-org/pylightcharts
|
|
8
|
+
Keywords: financial-charting,charting,candlestick,tradingview,lightweight-charts
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pandas>=1.5
|
|
20
|
+
Requires-Dist: numpy>=1.23
|
|
21
|
+
Requires-Dist: pywebview>=5.0.5
|
|
22
|
+
Provides-Extra: qt
|
|
23
|
+
Requires-Dist: PySide6; extra == "qt"
|
|
24
|
+
Provides-Extra: jupyter
|
|
25
|
+
Requires-Dist: ipython; extra == "jupyter"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest; extra == "test"
|
|
28
|
+
Requires-Dist: pillow; extra == "test"
|
|
29
|
+
Provides-Extra: e2e
|
|
30
|
+
Requires-Dist: playwright; extra == "e2e"
|
|
31
|
+
Requires-Dist: pillow; extra == "e2e"
|
|
32
|
+
Provides-Extra: docs
|
|
33
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest; extra == "dev"
|
|
36
|
+
Requires-Dist: build; extra == "dev"
|
|
37
|
+
Requires-Dist: pillow; extra == "dev"
|
|
38
|
+
Requires-Dist: playwright; extra == "dev"
|
|
39
|
+
Requires-Dist: mkdocs-material; extra == "dev"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# pylightcharts
|
|
43
|
+
|
|
44
|
+
Python bindings for [TradingView Lightweight Charts™](https://github.com/tradingview/lightweight-charts),
|
|
45
|
+
aiming at **near-full API coverage** with a pythonic interface.
|
|
46
|
+
|
|
47
|
+
> Status: development (P0/P1/P2 hardening — 17 indicators, 13 drawing tools, numeric axes, formatters, CI with JS + Python tests and docs).
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
This is **not** a re-implementation of the charting engine in Python.
|
|
52
|
+
It embeds the official, battle-tested JavaScript renderer in a WebView
|
|
53
|
+
(pywebview / Qt WebEngine / wx / Jupyter / Streamlit) and drives it from Python.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Python API ──► JSON / JS bridge ──► Lib.Handler (TypeScript) ──► Lightweight Charts v5
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Because the pixels and interactions are produced by the upstream library,
|
|
60
|
+
visual fidelity and performance match the JS version.
|
|
61
|
+
|
|
62
|
+
## Acknowledgements / License
|
|
63
|
+
|
|
64
|
+
- Python layer, GUI backends and drawing plugins are derived from
|
|
65
|
+
[lightweight-charts-python](https://github.com/louisnw01/lightweight-charts-python) (MIT).
|
|
66
|
+
- The charting engine is
|
|
67
|
+
[TradingView Lightweight Charts™](https://github.com/tradingview/lightweight-charts) (Apache-2.0),
|
|
68
|
+
see `NOTICE`.
|
|
69
|
+
|
|
70
|
+
## Migrating from lightweight-charts-python
|
|
71
|
+
`pylightcharts` keeps every class, method and module-level name of the original
|
|
72
|
+
package (enforced by `tests/test_lwc_compat.py`), so existing code runs with a
|
|
73
|
+
one-line shim:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from pylightcharts.compat import install_alias
|
|
77
|
+
install_alias() # before any `import lightweight_charts`
|
|
78
|
+
|
|
79
|
+
import lightweight_charts # -> pylightcharts
|
|
80
|
+
lightweight_charts.widgets.QWebEngineView = MyPyQt6WebEngineView # patching still works
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or change the imports directly:
|
|
84
|
+
|
|
85
|
+
```diff
|
|
86
|
+
- from lightweight_charts.util import Events, JSEmitter
|
|
87
|
+
- from lightweight_charts.widgets import QtChart
|
|
88
|
+
+ from pylightcharts.util import Events, JSEmitter
|
|
89
|
+
+ from pylightcharts.widgets import QtChart
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Qt integration
|
|
93
|
+
|
|
94
|
+
Inside a desktop application, `QtChart` embeds the chart in a `QWebEngineView`:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from PyQt6.QtWidgets import QApplication
|
|
98
|
+
from pylightcharts.qt import prepare_qt
|
|
99
|
+
|
|
100
|
+
prepare_qt('PyQt6') # pick the binding *before* QApplication
|
|
101
|
+
app = QApplication([])
|
|
102
|
+
|
|
103
|
+
from pylightcharts.widgets import QtChart
|
|
104
|
+
chart = QtChart(toolbox=True)
|
|
105
|
+
chart.set(df)
|
|
106
|
+
chart.get_webview().show()
|
|
107
|
+
app.exec()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`QtWebEngineWidgets` must be imported before the `QApplication` exists, which is
|
|
111
|
+
why `prepare_qt()` comes first; `$PYLIGHTCHARTS_QT` chooses the binding without it.
|
|
112
|
+
Full details - multi-chart `sync()`, screenshots, the Chromium network noise -
|
|
113
|
+
are in `docs/guide/qt.md`.
|
|
114
|
+
|
|
115
|
+
## Examples
|
|
116
|
+
|
|
117
|
+
`examples/` in the repository holds ten self-contained scripts, each with its own
|
|
118
|
+
data: loading OHLCV, live bars, tick updates, indicator lines, styling,
|
|
119
|
+
callbacks, built-in indicators and panes, headless PNG rendering, custom series
|
|
120
|
+
and the PyQt6 window. Start with `examples/1_setting_data/setting_data.py`.
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# build the JS bridge + vendor the engine into pylightcharts/js/
|
|
126
|
+
cd jslib && npm install && npm run build
|
|
127
|
+
|
|
128
|
+
# install the python package in editable mode
|
|
129
|
+
cd .. && pip install -e .
|
|
130
|
+
|
|
131
|
+
# ...or use the requirement files (pyproject.toml stays the source of truth)
|
|
132
|
+
pip install -r requirements.txt # runtime only
|
|
133
|
+
pip install -r requirements-dev.txt # + tests, e2e, docs, build
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Testing
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# unit tests: assert on the JS generated by the python bridge (no browser)
|
|
140
|
+
python -m pytest -m "not slow"
|
|
141
|
+
|
|
142
|
+
# e2e: run the built bundle in headless Chromium and check rendered pixels
|
|
143
|
+
python tests/e2e/smoke.py
|
|
144
|
+
|
|
145
|
+
# headless rendering tests (Playwright or a local Chrome/Edge)
|
|
146
|
+
python -m pytest tests/test_headless.py
|
|
147
|
+
|
|
148
|
+
# full stack: real pywebview window + real chart engine (needs a desktop session)
|
|
149
|
+
python tests/e2e/full_stack.py
|
|
150
|
+
|
|
151
|
+
# performance: JSON vs binary bulk data transfer
|
|
152
|
+
python tests/e2e/benchmark.py 100000
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
CI (`.github/workflows/ci.yml`) builds the bundle, checks the committed artifacts
|
|
156
|
+
are up to date, runs the unit tests on Linux/Windows/macOS, renders in headless
|
|
157
|
+
Chromium and verifies the wheel ships the JS assets.
|
|
158
|
+
|
|
159
|
+
### Packaging
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cd jslib && npm run build # regenerate pylightcharts/js/*
|
|
163
|
+
cd .. && python -m build # sdist + wheel (JS assets are package-data)
|
|
164
|
+
twine upload dist/*
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The built `pylightcharts/js/` files are committed on purpose so that
|
|
168
|
+
`pip install` works without Node. Always run `npm run build` before committing.
|
|
169
|
+
|
|
170
|
+
### Bridge rules
|
|
171
|
+
|
|
172
|
+
- Fire-and-forget calls go through `Window.invoke` (the transport appends
|
|
173
|
+
`;undefined` so pywebview never serialises a live chart object).
|
|
174
|
+
- Methods that **return an object** must use `store_as=...` or, for primitives,
|
|
175
|
+
`invoke_get`. Returning a live object through `invoke_get` would explode.
|
|
176
|
+
- Round-trips are serialised and correlated by request id; JS errors raise
|
|
177
|
+
`pylightcharts.util.BridgeError` instead of returning `None`.
|
|
178
|
+
- Chart and series share method names (`apply_options`); they are deliberately
|
|
179
|
+
kept apart (`series_options`, `data_points`) to avoid MRO shadowing.
|
|
180
|
+
- Upgrading lightweight-charts: `npm pack lightweight-charts@X`, migrate the
|
|
181
|
+
breaking changes, `npm run build`, then run the e2e suite.
|
|
182
|
+
|
|
183
|
+
### The generic bridge
|
|
184
|
+
|
|
185
|
+
New features should not require touching TypeScript. Any method on any live
|
|
186
|
+
chart object can be called from Python:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
chart._invoke('addSeries', 'Area', 'my area', {'lineWidth': 2}, handle)
|
|
190
|
+
chart.win.invoke(f'{series.id}.series', 'applyOptions', {'lineWidth': 3})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Handles are either registered via `Lib.register(...)` or dotted window paths
|
|
194
|
+
(`window.abcdefgh.chart`). A `{'$ref': handle}` argument is resolved to the live
|
|
195
|
+
JS object, so object-taking APIs work too:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
series.attach_primitive('myPrimitive') # -> attachPrimitive({"$ref": "myPrimitive"})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
See `jslib/src/general/rpc.ts`.
|
|
202
|
+
|
|
203
|
+
### Full option coverage
|
|
204
|
+
|
|
205
|
+
`apply_options(**kwargs)` accepts any option of the underlying API and converts
|
|
206
|
+
`snake_case` keys to `camelCase` automatically:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
chart.apply_options(auto_size=True, localization={'price_format': {'precision': 4}})
|
|
210
|
+
chart.time_scale_options(right_offset=5, bar_spacing=8) # time scale
|
|
211
|
+
series.apply_options(line_width=3, crosshair_marker_visible=False)
|
|
212
|
+
get = chart.get_price_scale('left'); get.set_mode('logarithmic')
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Indicators
|
|
216
|
+
|
|
217
|
+
Pure-pandas implementations, no extra dependencies. Overlays go on the price
|
|
218
|
+
pane, oscillators get their own pane automatically:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
chart.add_sma('close', 20)
|
|
222
|
+
chart.add_ema('close', 50, color='#2196F3')
|
|
223
|
+
chart.add_bollinger('close', 20, 2) # -> (upper, middle, lower)
|
|
224
|
+
chart.add_donchian(20)
|
|
225
|
+
chart.add_vwap()
|
|
226
|
+
|
|
227
|
+
chart.add_rsi(14) # own pane + 70/30 guide lines
|
|
228
|
+
chart.add_macd() # own pane -> (macd, signal, histogram)
|
|
229
|
+
chart.add_stochastic() # own pane -> (%K, %D)
|
|
230
|
+
chart.add_atr(14)
|
|
231
|
+
chart.add_adx(14) # own pane -> (adx, +DI, -DI)
|
|
232
|
+
chart.add_obv() # own pane (needs volume)
|
|
233
|
+
chart.add_cci(20)
|
|
234
|
+
chart.add_williams_r(14)
|
|
235
|
+
chart.add_mfi(14)
|
|
236
|
+
chart.add_roc(12)
|
|
237
|
+
chart.add_keltner(20, 2.0) # overlay -> (upper, middle, lower)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Raw values: `from pylightcharts import indicators; indicators.rsi(close, 14)`.
|
|
241
|
+
RSI, OBV, CCI, %R, ROC, MFI and Bollinger match TA-Lib to floating-point
|
|
242
|
+
precision; ATR and ADX match within ~1e-4 and ~0.1 respectively (Wilder
|
|
243
|
+
accumulation rounding).
|
|
244
|
+
|
|
245
|
+
#### Indicators follow the data
|
|
246
|
+
|
|
247
|
+
Every indicator is recomputed automatically: a full re-send on `chart.set()`,
|
|
248
|
+
and a single-point update on `chart.update(bar)` (recomputed from a warm-up
|
|
249
|
+
window so recursive indicators stay numerically identical to a full run).
|
|
250
|
+
`add_computed_series(compute, name, ...)` adds your own.
|
|
251
|
+
|
|
252
|
+
#### Batching ticks
|
|
253
|
+
|
|
254
|
+
Each bridge call is one webview round-trip, so wrap bursts in `chart.batch()`:
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
with chart.batch():
|
|
258
|
+
for tick in ticks:
|
|
259
|
+
chart.update(tick) # flushed as a single script
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### Conflation (very large data)
|
|
263
|
+
|
|
264
|
+
Conflation is a plain series option, so the bridge already exposes it:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
chart.apply_options(enable_conflation=True, precompute_conflation_on_init=True)
|
|
268
|
+
series.apply_options(enable_conflation=True)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Custom series (declarative rendering)
|
|
272
|
+
|
|
273
|
+
The tricky part of a custom series is `draw()`, which runs synchronously every
|
|
274
|
+
frame - python cannot take part in that. So the protocol splits the work:
|
|
275
|
+
**python computes the shapes once per data update, one generic JS renderer draws
|
|
276
|
+
them every frame.**
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from pylightcharts import shapes
|
|
280
|
+
|
|
281
|
+
series = chart.add_custom_series('range bars', pane_index='new')
|
|
282
|
+
series.set(df, shapes=lambda row: shapes.range_bar(row['low'], row['high']))
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Shape builders: `rect` `band` `line` `circle` `text` `polyline`, plus presets
|
|
286
|
+
`range_bar` `box_plot` `error_bar`. Vertical anchors are prices, horizontal
|
|
287
|
+
offsets are in bar units (`-0.4..0.4` spans a bar).
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
shapes.box_plot(low, q1, median, q3, high)
|
|
291
|
+
shapes.polyline([(0.0, 1.0), (0.4, 2.0)], fill_color='rgba(0,0,0,0.2)')
|
|
292
|
+
shapes.text(price, 'label')
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Each data item may carry `value`, `low`, `high` (autoscale + last value),
|
|
296
|
+
`color`, and `shapes`.
|
|
297
|
+
|
|
298
|
+
### Price lines, data readback, events
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
line = series.create_price_line(105.0, color='#00e676', title='entry')
|
|
302
|
+
line.apply_options(line_visible=False)
|
|
303
|
+
line.remove()
|
|
304
|
+
|
|
305
|
+
series.price_to_coordinate(105) # <-> series.coordinate_to_price(y)
|
|
306
|
+
series.data_by_index(10) # individual bar
|
|
307
|
+
series.data_points() # everything the chart holds
|
|
308
|
+
series.pop(2); series.last_value_data(); series.bars_in_logical_range(0, 50)
|
|
309
|
+
series.series_type(); series.get_pane_index()
|
|
310
|
+
series.move_to_pane(2); series.series_order(); series.set_series_order(3)
|
|
311
|
+
|
|
312
|
+
chart.scroll_to_real_time(); chart.scroll_to_position(3, animated=False)
|
|
313
|
+
chart.reset_time_scale(); chart.set_visible_logical_range(0, 60)
|
|
314
|
+
chart.get_visible_range(); chart.get_visible_logical_range()
|
|
315
|
+
chart.time_to_coordinate(t); chart.coordinate_to_time(x)
|
|
316
|
+
chart.logical_to_coordinate(l); chart.coordinate_to_logical(x)
|
|
317
|
+
chart.pane_height(0); chart.set_pane_height(300, 0)
|
|
318
|
+
chart.pane_stretch_factor(0); chart.pane_size(); chart.pane_series_count(0)
|
|
319
|
+
chart.version(); chart.auto_size_active(); chart.remove()
|
|
320
|
+
chart.set_crosshair_position(100.0, some_time); chart.clear_crosshair_position()
|
|
321
|
+
|
|
322
|
+
chart.get_price_scale('right').get_visible_range()
|
|
323
|
+
chart.get_price_scale('right').set_auto_scale(False)
|
|
324
|
+
chart.pane_price_scale(0, 'left')
|
|
325
|
+
|
|
326
|
+
chart.events.crosshair_move += handler # handler(chart, time, price)
|
|
327
|
+
chart.events.dblclick += handler
|
|
328
|
+
chart.events.click.unsubscribe()
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Multi-chart sync
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
price = Chart(); volume = Chart()
|
|
335
|
+
price.sync(volume) # volume follows price pan/zoom
|
|
336
|
+
price.sync(volume, crosshairs_only=True)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Native panes (lightweight-charts v5)
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
chart.add_pane()
|
|
343
|
+
chart.create_area(name='close', pane_index=1)
|
|
344
|
+
chart.add_series('Line', 'ma20', pane_index=1, color='#0ff')
|
|
345
|
+
chart.set_pane_stretch(1, 1.5)
|
|
346
|
+
chart.pane_count()
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
`pane_index='new'` creates a fresh pane, and passing an index beyond the
|
|
350
|
+
current pane count creates the panes in between.
|
|
351
|
+
|
|
352
|
+
### Drawing tools
|
|
353
|
+
|
|
354
|
+
Trend line / horizontal line / vertical line / ray / box, plus:
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
chart.fibonacci(t1, p1, t2, p2, levels=(0, 0.382, 0.5, 0.618, 1))
|
|
358
|
+
chart.measure(t1, p1, t2, p2) # price %, bar count
|
|
359
|
+
chart.parallel_channel(t1, p1, t2, p2, offset=5) # second line 5 price units away
|
|
360
|
+
chart.position(t1, entry, t2, target, risk_ratio=1.5) # profit + stop zones
|
|
361
|
+
chart.long_position(t1, entry, t2, target) # aliases
|
|
362
|
+
chart.short_position(t1, entry, t2, target)
|
|
363
|
+
|
|
364
|
+
chart.andrews_pitchfork(t1, p1, t2, p2, t3, p3) # 3 points
|
|
365
|
+
chart.triangle(t1, p1, t2, p2, t3, p3) # 3 points
|
|
366
|
+
chart.fibonacci_extension(t1, p1, t2, p2, t3, p3) # impulse + retracement
|
|
367
|
+
chart.gann_fan(t1, p1, t2, p2) # 1x1 plus steeper/shallower rays
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
With `toolbox=True` these are also available interactively
|
|
371
|
+
(Alt+F / M / C / P / A / G / X / N).
|
|
372
|
+
|
|
373
|
+
### Numeric axes and formatters
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
from pylightcharts import YieldCurveChart, OptionsChart
|
|
377
|
+
|
|
378
|
+
curve = YieldCurveChart() # x axis = duration in months
|
|
379
|
+
series = curve.add_series('Line', 'rate')
|
|
380
|
+
series.set(pd.DataFrame({'time': [1, 3, 12], 'rate': [4.2, 4.0, 3.6]}))
|
|
381
|
+
|
|
382
|
+
surface = OptionsChart() # x axis = strike
|
|
383
|
+
|
|
384
|
+
chart.set_price_formatter(decimals=2, thousands=True, prefix='$')
|
|
385
|
+
chart.set_time_formatter('YYYY-MM-DD HH:mm')
|
|
386
|
+
chart.register_js_formatter('eur', "value => '\u20ac' + value.toFixed(2)")
|
|
387
|
+
chart.set_price_formatter(name='eur')
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Large data
|
|
391
|
+
|
|
392
|
+
DataFrames with 2000+ rows are transferred as a base64 column-major Float64
|
|
393
|
+
buffer and rebuilt in the browser (`Lib.decodeData`) instead of being shipped as
|
|
394
|
+
JavaScript source. Measured 100k bars: **1.56s -> 0.54s (~3x)**;
|
|
395
|
+
500k bars: **8.9s -> 3.2s**. Tune with `pylightcharts.util.BINARY_DATA_THRESHOLD`.
|
|
396
|
+
|
|
397
|
+
### Headless / server-side rendering
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
from pylightcharts.headless import HeadlessChart
|
|
401
|
+
|
|
402
|
+
chart = HeadlessChart(width=1200, height=700)
|
|
403
|
+
chart.set(df)
|
|
404
|
+
chart.add_sma('close', 20)
|
|
405
|
+
chart.add_rsi(14)
|
|
406
|
+
chart.render('report.png') # PNG bytes, no window required
|
|
407
|
+
chart.to_html() # or grab the standalone HTML
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Uses Playwright when installed, otherwise a local Chrome/Edge in headless mode
|
|
411
|
+
(`PYLIGHTCHARTS_CHROME` overrides the browser path).
|