- Added async methods to polygon.
- The `requests` library is no longer required, with `urllib` being used instead.
- Added the `get_bar_data` function, which returns a dataframe of aggregate data from polygon.
- Opened up the `subscribe` and `unsubscribe` functions

Enhancements:
- Tables will now scroll when the rows exceed table height.

Bugs:
- Fixed a bug preventing async functions being used with horizontal line event.
- Fixed a bug causing the legend to show duplicate lines if the line was created after the legend.
- Fixed a bug causing the line hide icon to persist within the legend after deletion (#75)
- Fixed a bug causing the search box to be unfocused when the chart is loaded.
This commit is contained in:
louisnw
2023-08-27 00:20:05 +01:00
parent 34ce3f7199
commit f72baf95ba
49 changed files with 43156 additions and 1895 deletions

View File

@ -0,0 +1,160 @@
# Topbar & Events
This section gives an overview of how events are handled across the library.
## How to use events
Take a look at this minimal example, which uses the [`search`](#AbstractChart.Events) event:
```python
from lightweight_charts import Chart
def on_search(chart, string):
print(f'Search Text: "{string}" | Chart/SubChart ID: "{chart.id}"')
if __name__ == '__main__':
chart = Chart()
# Subscribe the function above to search event
chart.events.search += on_search
chart.show(block=True)
```
Upon searching in a pane, the expected output would be akin to:
```
Search Text: "AAPL" | Chart/SubChart ID: "window.blyjagcr"
```
The ID shown above will change depending upon which pane was used to search, allowing for access to the object in question.
```{important}
* When using `show` rather than `show_async`, block should be set to `True` (`chart.show(block=True)`).
* Event callables can be either coroutines, methods, or functions.
```
___
## Topbar events
Events can also be emitted from the topbar:
```python
from lightweight_charts import Chart
def on_button_press(chart):
new_button_value = 'On' if chart.topbar['my_button'].value == 'Off' else 'Off'
chart.topbar['my_button'].set(new_button_value)
print(f'Turned something {new_button_value.lower()}.')
if __name__ == '__main__':
chart = Chart()
chart.topbar.button('my_button', 'Off', func=on_button_press)
chart.show(block=True)
```
In this example, we are passing `on_button_press` to the `func` parameter.
When the button is pressed, the function will be emitted the `chart` object as with the previous example, allowing access to the topbar dictionary.
The `switcher` is typically used for timeframe selection:
```python
from lightweight_charts import Chart
def on_timeframe_selection(chart):
print(f'Getting data with a {chart.topbar["my_switcher"].value} timeframe.')
if __name__ == '__main__':
chart = Chart()
chart.topbar.switcher(
name='my_switcher',
options=('1min', '5min', '30min'),
default='5min',
func=on_timeframe_selection)
chart.show(block=True)
```
___
## Async clock
There are many use cases where we will need to run our own code whilst the GUI loop continues to listen for events. Let's demonstrate this by using the `textbox` widget to display a clock:
```python
import asyncio
from datetime import datetime
from lightweight_charts import Chart
async def update_clock(chart):
while chart.is_alive:
await asyncio.sleep(1-(datetime.now().microsecond/1_000_000))
chart.topbar['clock'].set(datetime.now().strftime('%H:%M:%S'))
async def main():
chart = Chart()
chart.topbar.textbox('clock')
await asyncio.gather(chart.show_async(block=True), update_clock(chart))
if __name__ == '__main__':
asyncio.run(main())
```
This is how the library is intended to be used with live data (option #2 [described here]()).
___
## Live data, topbar & events
Now we can create an asyncio program which updates chart data whilst allowing the GUI loop to continue processing events, based the [Live data](live_chart.md) example:
```python
import asyncio
import pandas as pd
from lightweight_charts import Chart
async def data_loop(chart):
ticks = pd.read_csv('ticks.csv')
for i, tick in ticks.iterrows():
if not chart.is_alive:
return
chart.update_from_tick(ticks.iloc[i])
await asyncio.sleep(0.03)
i += 1
def on_new_bar(chart):
print('New bar event!')
def on_timeframe_selection(chart):
print(f'Selected timeframe of {chart.topbar["timeframe"].value}')
async def main():
chart = Chart()
chart.events.new_bar += on_new_bar
chart.topbar.switcher('timeframe', ('1min', '5min'), func=on_timeframe_selection)
df = pd.read_csv('ohlc.csv')
chart.set(df)
await asyncio.gather(chart.show_async(block=True), data_loop(chart))
if __name__ == '__main__':
asyncio.run(main())
```

View File

@ -0,0 +1,85 @@
# Getting Started
## Installation
To install the library, use pip:
```text
pip install lightweight-charts
```
Pywebview's installation can differ depending on OS. Please refer to their [documentation](https://pywebview.flowrl.com/guide/installation.html#installation).
___
## A simple static chart
```python
import pandas as pd
from lightweight_charts import Chart
```
Download this
[`ohlcv.csv`](../../../examples/1_setting_data/ohlcv.csv)
file for this tutorial.
In this example, we are reading a csv file using pandas:
```text
date open high low close volume
0 2010-06-29 1.2667 1.6667 1.1693 1.5927 277519500.0
1 2010-06-30 1.6713 2.0280 1.5533 1.5887 253039500.0
2 2010-07-01 1.6627 1.7280 1.3513 1.4640 121461000.0
3 2010-07-02 1.4700 1.5500 1.2473 1.2800 75871500.0
4..
```
..which can be used as data for the `Chart` object:
```python
if __name__ == '__main__':
chart = Chart()
df = pd.read_csv('ohlcv.csv')
chart.set(df)
chart.show(block=True)
```
The `block` parameter is set to `True` in this case, as we do not want the program to exit.
```{warning}
Due to the library's use of multiprocessing, instantiations of `Chart` should be encapsulated within an `if __name__ == '__main__'` block.
```
## Adding a line
Now lets add a moving average to the chart using the following function:
```python
def calculate_sma(df, period: int = 50):
return pd.DataFrame({
'time': df['date'],
f'SMA {period}': df['close'].rolling(window=period).mean()
}).dropna()
```
`calculate_sma` derives the data column from `f'SMA {period}'`, which we will use as the name of our line:
```python
if __name__ == '__main__':
chart = Chart()
line = chart.create_line(name='SMA 50')
df = pd.read_csv('ohlcv.csv')
sma_df = calculate_sma(df, period=50)
chart.set(df)
line.set(sma_df)
chart.show(block=True)
```