Compare commits
19 Commits
3a859c97fc
...
c4356bef3a
| Author | SHA1 | Date | |
|---|---|---|---|
| c4356bef3a | |||
| 7986aa9195 | |||
| 35f029714b | |||
| 2b9f238a42 | |||
| bbbd37520d | |||
| 51fc616f82 | |||
| 197936d69f | |||
| 789d27c54b | |||
| f90e7789ab | |||
| eb2c24e157 | |||
| c27401a59d | |||
| da029fcbb7 | |||
| ea2f53b794 | |||
| 19b1834a6d | |||
| 6de9ba9c33 | |||
| 105ea66731 | |||
| 9b8e43e1e8 | |||
| 9f9f22eb93 | |||
| eb56a889a9 |
115
README.md
115
README.md
@ -1,17 +1,118 @@
|
||||
Fork of lightweight-charts with enhancements and supporting proprietary workflow
|
||||
* colored legends
|
||||
* self picking colors
|
||||
* support for left price scale
|
||||
* support from pd series as input to set series
|
||||
Fork of the original [lightweight-charts](louisnw01/lightweight-charts-python) with enhancements and supporting vectorbtpro workflow
|
||||
* legend color matching each line color
|
||||
* automatic color assignment if not provided
|
||||
* support for multiple scales (right, left, middle1, middle2, histogram)
|
||||
* accepts df,pd.series or vectorbtpro indicator object (including unpacking multi outputs)
|
||||
* new markers_set method allowing to set pd.series or dataframe as markers input
|
||||
* allows vbt indicators as input for set() method (extracting real values series from that)
|
||||
* for quick display supports simple df/sr accessors `close.lw.plot()` for quick visualization of single panel chart
|
||||
* df accessor unpacks dataframe columns and display them accordingly (ohlcv as ohlcv, vwap on the right, rsi on the left scale etc.)
|
||||
* multipanes support `ch = chart([pane1, pane2], sync=True, title="Title", size="m")` to quickly display chart with N panes (`Panels`). Also supports syncing the Panels `sync=True` or using xloc.
|
||||
|
||||
|
||||
<img width="1005" alt="image" src="https://github.com/drew2323/lightweight-charts-python/assets/28433232/856c32aa-e0ff-4de0-b4a2-befc34adb571">
|
||||
|
||||
## Instalation
|
||||
Directly from the repository
|
||||
|
||||
```pip install git+https://github.com/drew2323/lightweight-charts-python.git```
|
||||
|
||||
## Examples
|
||||
|
||||
```python
|
||||
from lightweight_charts import chart, Panel, PlotSRAccessor, PlotDFAccessor
|
||||
|
||||
#one liner, displays close series as line on single Panel
|
||||
close_sr.lw.plot()
|
||||
```
|
||||

|
||||
```python
|
||||
close_sr.lw.plot(size="m") #on medium panesize
|
||||
close_se.lw.plot(histogram=(trade_series, "trades")) #number of trades as histogram is displayed on top of that
|
||||
```
|
||||

|
||||
```python
|
||||
#one liner to display OHLCV
|
||||
ohlcv_df.lw.plot() #if dataframe contains other columns they are displayed too - based on standard settings (rsi-on the left, vwap - right etc.)
|
||||
```
|
||||

|
||||
```python
|
||||
ohlcv_df.lw.plot(left=[(angle_series, "angle_momentum")]) #Another line is displayed on top of OHLCV on left scale
|
||||
```
|
||||

|
||||
```python
|
||||
ohlcv_complex_df.lw.plot() #df containing ohlcv and other columns
|
||||
```
|
||||

|
||||
```python
|
||||
#quick few liner, displays close series with label "close" on right pricescale and rsi on left price scale, all on single Panel
|
||||
pane1 = Panel(
|
||||
right=[(close, "close")],
|
||||
left=[(rsi,"rsi")]
|
||||
)
|
||||
ch = chart([pane1])
|
||||
|
||||
# display two Panels
|
||||
# on first displays ohlcv data, orderimbalance volume as histogram with opacity, bbands on the right pricescale and
|
||||
# sma with short_signals and short_exits on the left pricescale
|
||||
pane1 = Panel(
|
||||
ohlcv=(t1data.data["BAC"],), #(series, entries, exits, other_markers)
|
||||
histogram=[(order_imbalance_allvolume, "oivol",None, 0.3)], # [(series, name, "rgba(53, 94, 59, 0.6)", opacity)]
|
||||
|
||||
#following attributes assign lineseries series to different priceScaleIds, format: # [(series, name, entries, exits, other_markers)]
|
||||
right=[(bbands)], #multioutput indicator, outputs are autom.extracted
|
||||
left=[(sma, "sma", short_signals, short_exits) #simple vbt indicator with markers in and outs
|
||||
(supertrend.trend, "ST_trend") #explicitly just one output of multioutput indicator
|
||||
],
|
||||
middle1=[],
|
||||
middle2=[],
|
||||
)
|
||||
#on second panel displays also ohlcv data, and sma on the left pricescale and histogram
|
||||
pane2 = Panel(
|
||||
ohlcv=(t1data.data["BAC"],),
|
||||
right=[],
|
||||
left=[(sma, "sma_below", short_signals, short_exits)],
|
||||
middle1=[],
|
||||
middle2=[],
|
||||
histogram=[(order_imbalance_sma, "oisma")],
|
||||
)
|
||||
|
||||
#display both Panels, sync them and pick size, use xloc
|
||||
ch = chart([pane1, pane2], sync=True, title="Title", size="l", xloc=slice("1-1-2024","1-2-2024"))
|
||||
|
||||
```
|
||||
|
||||
## Example with markers
|
||||
|
||||
```python
|
||||
|
||||
#assume i want to display simple entries or exits on series or ohlcv
|
||||
#based on tuple positions it determines entries or exits (and set colors and shape accordingly)
|
||||
pane1 = Panel(
|
||||
ohlcv=(ohlcv_df, clean_long_entries, clean_short_entries)
|
||||
)
|
||||
ch = chart([pane1], title="Chart with Entry/Exit Markers", session=None, size="s")
|
||||
```
|
||||
<img width="798" alt="image" src="https://github.com/drew2323/lightweight-charts-python/assets/28433232/0cdc3930-b8b1-40f8-af95-55467879148b">
|
||||
|
||||
```python
|
||||
#if you want to display more entries or exits, use tuples with their colors
|
||||
|
||||
# Create Panel with OHLC data and entry signals
|
||||
pane1 = Panel(
|
||||
ohlcv=(data.ohlcv.get(),
|
||||
[(clean_long_entries, "yellow"), (clean_short_entries, "pink")], #list of entries tuples with color
|
||||
[(clean_long_exits, "yellow"), (clean_short_exits, "pink")]), #list of exits tuples with color
|
||||
)
|
||||
|
||||
# # Create the chart with the panel
|
||||
ch = chart([pane1], title="Chart with EntryShort/ExitShort (yellow) and EntryLong/ExitLong markers (pink)", session=None, size="s")
|
||||
```
|
||||
<img width="800" alt="image" src="https://github.com/drew2323/lightweight-charts-python/assets/28433232/0acde2bf-600e-4f45-8db0-5077822d6993">
|
||||
|
||||
|
||||
<div align="center">
|
||||
|
||||
# lightweight-charts-python
|
||||
# lightweight-charts-python - forked from
|
||||
|
||||
[](https://pypi.org/project/lightweight-charts/)
|
||||
[](https://python.org "Go to Python homepage")
|
||||
|
||||
BIN
image-1.png
Normal file
BIN
image-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
BIN
image-2.png
Normal file
BIN
image-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
image-3.png
Normal file
BIN
image-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
image-4.png
Normal file
BIN
image-4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
image-5.png
Normal file
BIN
image-5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
@ -2,4 +2,4 @@ from .abstract import AbstractChart, Window
|
||||
from .chart import Chart
|
||||
from .widgets import JupyterChart
|
||||
from .polygon import PolygonChart
|
||||
from .helpers import chart, Panel, PlotAccessor
|
||||
from .helpers import chart, Panel, PlotSRAccessor, PlotDFAccessor
|
||||
@ -202,7 +202,7 @@ class SeriesCommon(Pane):
|
||||
self._set_interval(df)
|
||||
if not pd.api.types.is_datetime64_any_dtype(df['time']):
|
||||
df['time'] = pd.to_datetime(df['time'])
|
||||
df['time'] = df['time'].astype('int64') / 10 ** 9 #removed integer divison // 10 ** 9 to keep subseconds precision
|
||||
df['time'] = (df['time'].astype('int64') / 10 ** 9).astype(float)
|
||||
|
||||
# if 'updated' in df.columns:
|
||||
# df['updated'] = pd.to_datetime(df['updated']).astype('int64') / 10**9
|
||||
@ -213,7 +213,7 @@ class SeriesCommon(Pane):
|
||||
if col == 'time' or not pd.api.types.is_datetime64_any_dtype(df[col]):
|
||||
continue
|
||||
# Convert datetime to timestamp with nanosecond precision after the decimal
|
||||
df[col] = pd.to_datetime(df[col]).astype('int64') / 10**9
|
||||
df[col] = (pd.to_datetime(df[col]).astype('int64') / 10**9).astype(float)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
@ -4,15 +4,54 @@ from .util import (
|
||||
)
|
||||
import pandas as pd
|
||||
|
||||
def append_or_extend(target_list, value):
|
||||
if isinstance(value, list):
|
||||
target_list.extend(value) # Extend if it's a list
|
||||
else:
|
||||
target_list.append(value) # Append if it's a single value
|
||||
|
||||
def extend_kwargs(ohlcv, right, left, middle1, middle2, histogram, kwargs):
|
||||
"""
|
||||
Mutate lists based on kwargs for accessor.
|
||||
Used when user added additional series to kwargs when using accessor.
|
||||
"""
|
||||
if 'ohlcv' in kwargs:
|
||||
ohlcv = kwargs['ohlcv'] #ohlcv is only a tuple
|
||||
if 'left' in kwargs:
|
||||
append_or_extend(left, kwargs['left'])
|
||||
if 'right' in kwargs:
|
||||
append_or_extend(right, kwargs['right'])
|
||||
if 'histogram' in kwargs:
|
||||
append_or_extend(histogram, kwargs['histogram'])
|
||||
if 'middle1' in kwargs:
|
||||
append_or_extend(middle1, kwargs['middle1'])
|
||||
if 'middle2' in kwargs:
|
||||
append_or_extend(middle1, kwargs['middle2'])
|
||||
|
||||
return ohlcv #as tuple is immutable
|
||||
|
||||
# Register the custom accessor
|
||||
@pd.api.extensions.register_series_accessor("lw")
|
||||
class PlotAccessor:
|
||||
class PlotSRAccessor:
|
||||
"""
|
||||
Custom plot accessor for pandas series.
|
||||
Custom plot accessor for pandas series. Quickly displays series values as line on the single pane.
|
||||
|
||||
Also additional priceseries can be added on top of them. They can be added
|
||||
for each scale in the correct format - either as tuple(OHLCV) or as list of tuple (others)
|
||||
|
||||
# input parameter / expected format:
|
||||
# ohlcv=(), #(series, entries, exits, other_markers)
|
||||
# histogram=[], # [(series, name, "rgba(53, 94, 59, 0.6)", opacity)]
|
||||
# right=[],
|
||||
# left=[], #[(series, name, entries, exits, other_markers)]
|
||||
# middle1=[],
|
||||
# middle2=[],
|
||||
|
||||
|
||||
Usage: s
|
||||
series.lw.plot()
|
||||
series.lw.plot(size="m")
|
||||
series.lw.plot() #plot series as line
|
||||
series.lw.plot(size="m") #on medium panesize
|
||||
series.lw.plot(histogram=(trade_series, "trades")) #plot histogram with trades on top of that
|
||||
"""
|
||||
def __init__(self, pandas_obj):
|
||||
self._obj = pandas_obj
|
||||
@ -20,11 +59,123 @@ class PlotAccessor:
|
||||
def plot(self, **kwargs):
|
||||
if "size" not in kwargs:
|
||||
kwargs["size"] = "xs"
|
||||
|
||||
ohlcv = ()
|
||||
right = []
|
||||
left = []
|
||||
middle1 = []
|
||||
middle2 = []
|
||||
histogram = []
|
||||
|
||||
#if there are additional series in kwargs add them too
|
||||
#ohlcv is returned as it is tuple thus immutable
|
||||
ohlcv = extend_kwargs(ohlcv, right, left, middle1, middle2, histogram, kwargs)
|
||||
|
||||
right.append((self._obj,"line"))
|
||||
|
||||
pane1 = Panel(
|
||||
right=[(self._obj, "line")],
|
||||
)
|
||||
ohlcv=ohlcv,
|
||||
histogram=histogram,
|
||||
right=right,
|
||||
left=left,
|
||||
middle1=middle1,
|
||||
middle2=middle2
|
||||
)
|
||||
|
||||
ch = chart([pane1], **kwargs)
|
||||
|
||||
@pd.api.extensions.register_dataframe_accessor("lw")
|
||||
class PlotDFAccessor:
|
||||
"""
|
||||
Custom plot accessor for dataframe. Quickly displays all columns on the single pane.
|
||||
|
||||
Series type is automatically extracted for each column based on following setting:
|
||||
scale / columns
|
||||
ohlcv = ['close', 'volume', 'open', 'high', 'low']
|
||||
right = ['vwap']
|
||||
left = ['rsi']
|
||||
middle1 = []
|
||||
middle2 = []
|
||||
histogram = ['buyvolume', 'sellvolume', 'trades']
|
||||
|
||||
Also additional priceseries can be added on top of them as parameters. They can be added
|
||||
for each scale in the correct format - either as tuple(OHLCV) or as list of tuple (others)
|
||||
|
||||
# input parameter / expected format:
|
||||
# ohlcv=(), #(series, entries, exits, other_markers)
|
||||
# histogram=[], # [(series, name, "rgba(53, 94, 59, 0.6)", opacity)]
|
||||
# right=[],
|
||||
# left=[], #[(series, name, entries, exits, other_markers)]
|
||||
# middle1=[],
|
||||
# middle2=[],
|
||||
|
||||
|
||||
Usage:
|
||||
ohlcv_df.lw.plot()
|
||||
ohlcv_df.lw.plot(size="m")
|
||||
ohlcv_df.lw.plot(right=(rsi_series, "rsi"))
|
||||
ohlcv_df.lw.plot(right=[(rsi_series, "rsi"), (angle_series, "angle")])
|
||||
basic_data.data[SYMBOL].lw.plot(histogram=(basic_data.data[SYMBOL].close, "close"), size="m")
|
||||
"""
|
||||
def __init__(self, pandas_obj):
|
||||
self._obj = pandas_obj
|
||||
|
||||
def plot(self, **kwargs):
|
||||
if "size" not in kwargs:
|
||||
kwargs["size"] = "xs"
|
||||
|
||||
#default settings for each pricescale
|
||||
ohlcv_cols = ['close', 'volume', 'open', 'high', 'low']
|
||||
right_cols = ['vwap']
|
||||
left_cols = ['rsi']
|
||||
middle1_cols = []
|
||||
middle2_cols = []
|
||||
histogram_cols = ['buyvolume', 'sellvolume', 'trades']
|
||||
|
||||
ohlcv = ()
|
||||
right = []
|
||||
left = []
|
||||
middle1 = []
|
||||
middle2 = []
|
||||
histogram = []
|
||||
|
||||
for col in self._obj.columns:
|
||||
if col in right_cols:
|
||||
right.append((self._obj[col],col,))
|
||||
if col in histogram_cols:
|
||||
histogram.append((self._obj[col],col,))
|
||||
if col in left_cols:
|
||||
left.append((self._obj[col],col,))
|
||||
if col in middle1_cols:
|
||||
middle1_cols.append((self._obj[col],col,))
|
||||
if col in middle2_cols:
|
||||
middle2_cols.append((self._obj[col],col,))
|
||||
|
||||
ohlcv = (self._obj[ohlcv_cols],)
|
||||
|
||||
#if there are additional series in kwargs add them too
|
||||
ohlcv = extend_kwargs(ohlcv, right, left, middle1, middle2, histogram, kwargs)
|
||||
|
||||
pane1 = Panel(
|
||||
ohlcv=ohlcv,
|
||||
histogram=histogram,
|
||||
right=right,
|
||||
left=left,
|
||||
middle1=middle1,
|
||||
middle2=middle2
|
||||
)
|
||||
|
||||
ch = chart([pane1], **kwargs)
|
||||
|
||||
# pane1 = Panel(
|
||||
# ohlcv=(), #(series, entries, exits, other_markers)
|
||||
# histogram=[], # [(series, name, "rgba(53, 94, 59, 0.6)", opacity)]
|
||||
# right=[],
|
||||
# left=[], #[(series, name, entries, exits, other_markers)]
|
||||
# middle1=[],
|
||||
# middle2=[],
|
||||
# )
|
||||
|
||||
class Panel:
|
||||
"""
|
||||
A class to represent a panel in a chart.
|
||||
@ -118,7 +269,7 @@ class Panel:
|
||||
self.precision = precision
|
||||
|
||||
|
||||
def chart(panes: list[Panel], sync=False, title='', size="m", xloc=None, session: str="9:30:00", precision=None):
|
||||
def chart(panes: list[Panel], sync=False, title='', size="m", xloc=None, session: str="9:30:00, 09:30:05", precision=None, **kwargs):
|
||||
"""
|
||||
Function to fast render a chart with multiple panes. This function manipulates graphical
|
||||
output or interfaces with an external framework to display charts with synchronized
|
||||
|
||||
Reference in New Issue
Block a user