TradingView Charts¶
PyWry provides a full TradingView Lightweight Charts integration — show OHLCV candlestick charts with built-in toolbars, drawing tools, indicators, theming, layout persistence, and an optional datafeed protocol for dynamic symbol search and real-time streaming.
For the complete configuration API, see the TVChartConfig reference. For all events and payloads, see the TradingView events reference.
Basic Usage¶
Pass OHLCV data (DataFrame or list of dicts) to show_tvchart():
import pandas as pd
from pywry import PyWry
app = PyWry()
df = pd.DataFrame({
"date": pd.date_range("2024-01-01", periods=100),
"open": [100 + i * 0.5 for i in range(100)],
"high": [102 + i * 0.5 for i in range(100)],
"low": [99 + i * 0.5 for i in range(100)],
"close": [101 + i * 0.5 for i in range(100)],
"volume": [1000 + i * 10 for i in range(100)],
})
handle = app.show_tvchart(df, title="My Chart")
Column names are auto-detected — any of date/time/timestamp for time, and standard open/high/low/close/volume names work.
Chart & Series Options¶
Customize chart appearance with chart_options and series_options:
handle = app.show_tvchart(
df,
chart_options={
"layout": {"background": {"color": "#1a1a2e"}},
"crosshair": {"mode": 0}, # CrosshairMode.NORMAL
"timeScale": {"timeVisible": True},
},
series_options={
"upColor": "#26a69a",
"downColor": "#ef5350",
"wickUpColor": "#26a69a",
"wickDownColor": "#ef5350",
},
)
Or use the Pydantic models for type-safe configuration:
from pywry.tvchart import TVChartConfig, CrosshairConfig, CrosshairMode
config = TVChartConfig(
crosshair=CrosshairConfig(mode=CrosshairMode.NORMAL),
)
handle = app.show_tvchart(
df,
chart_options=config.to_chart_options(),
series_options=config.to_series_options(),
)
Events¶
Listen for chart interactions:
def on_click(data):
print(f"Clicked at time={data['time']}")
def on_crosshair(data):
print(f"Crosshair at {data['prices']}")
handle = app.show_tvchart(
df,
callbacks={
"tvchart:click": on_click,
"tvchart:crosshair-move": on_crosshair,
},
)
Real-Time Updates¶
Stream bar updates to a live chart:
handle = app.show_tvchart(df)
# Replace all data
handle.update_series(new_df)
# Stream a single bar tick
handle.update_bar({
"time": 1704153600,
"open": 150.0,
"high": 152.5,
"low": 149.0,
"close": 151.5,
"volume": 5000,
})
Indicators¶
Add overlay indicator series:
# Add a simple moving average
sma_data = [{"time": bar["time"], "value": bar["close"]} for bar in bars]
handle.add_indicator(
sma_data,
series_id="sma-20",
series_type="Line",
series_options={"color": "#2196F3", "lineWidth": 2},
)
# Remove it later
handle.remove_indicator("sma-20")
Markers & Price Lines¶
# Add buy/sell markers
handle.add_marker([
{"time": 1704153600, "position": "belowBar", "color": "#26a69a",
"shape": "arrowUp", "text": "BUY"},
{"time": 1704240000, "position": "aboveBar", "color": "#ef5350",
"shape": "arrowDown", "text": "SELL"},
])
# Add a horizontal price line
handle.add_price_line(150.0, color="#FF9800", title="Target")
Datafeed Protocol¶
For dynamic symbol search, resolution switching, and server-driven data loading, use the datafeed protocol. This replaces static data with a request/response flow where the frontend asks Python for data.
Custom DatafeedProvider¶
Implement the DatafeedProvider ABC to connect any data source:
from pywry.tvchart.datafeed import DatafeedProvider
class MyDatafeed(DatafeedProvider):
async def get_config(self):
return {
"supported_resolutions": ["1", "5", "60", "D"],
"exchanges": [{"value": "", "name": "All", "desc": ""}],
}
async def search_symbols(self, query, symbol_type="", exchange="", limit=30):
# Return list of {symbol, full_name, description, exchange, type}
return [{"symbol": "AAPL", "full_name": "Apple Inc",
"description": "Apple Inc", "exchange": "NASDAQ", "type": "stock"}]
async def resolve_symbol(self, symbol):
return {
"name": symbol,
"full_name": symbol,
"description": f"{symbol} stock",
"type": "stock",
"session": "0930-1600",
"exchange": "NASDAQ",
"timezone": "America/New_York",
"format": "price",
"pricescale": 100,
"minmov": 1,
"has_intraday": True,
"supported_resolutions": ["1", "5", "60", "D"],
}
async def get_bars(self, symbol, resolution, from_ts, to_ts, countback=None):
bars = await fetch_bars_from_your_api(symbol, resolution, from_ts, to_ts)
return {"bars": bars, "status": "ok", "no_data": len(bars) == 0}
feed = MyDatafeed()
handle = app.show_tvchart(provider=feed, symbol="AAPL", resolution="D")
The DatafeedProvider has optional methods for marks, timescale marks, server time, and real-time subscriptions. Override only what your data source supports and set the corresponding feature-flag properties. See the DatafeedProvider API reference.
UDF Adapter¶
For servers that implement the TradingView UDF protocol, use UDFAdapter:
from pywry.tvchart.udf import UDFAdapter
udf = UDFAdapter(
"https://demo-feed-data.tradingview.com",
poll_interval=60, # poll /history every 60s for real-time updates
)
udf.connect(app, symbol="AAPL", resolution="D")
UDFAdapter auto-discovers server capabilities via /config and wires all datafeed events automatically. See the UDFAdapter API reference.
Toolbars¶
Charts include built-in toolbars for interval selection, chart type, drawing tools, indicators, and more. You can also add custom toolbars:
from pywry.toolbar import Toolbar, Button, Select, Option
custom_toolbar = Toolbar(
id="chart-controls",
position="top",
items=[
Select(
id="symbol-select",
label="Symbol",
event="app:symbol-change",
options=[
Option(label="AAPL", value="AAPL"),
Option(label="GOOGL", value="GOOGL"),
Option(label="MSFT", value="MSFT"),
],
),
Button(id="refresh-btn", label="↻ Refresh", event="app:refresh"),
],
)
handle = app.show_tvchart(df, toolbars=[custom_toolbar])
Layout Persistence¶
Charts support saving and loading layouts (drawings, indicators, settings). The built-in save/load toolbar buttons wire to a ChartStore backend:
- MemoryChartStore — in-memory (default, lost on restart)
- FileChartStore — JSON files on disk
- RedisChartStore — Redis for multi-worker deploy mode
Drawing Tools¶
Built-in drawing tools are available in the toolbar:
- Trend Line — click two points to draw a line
- Horizontal Line — click to place a horizontal level
- Vertical Line — click to place a vertical marker
- Rectangle — click two corners
- Parallel Channel — three-point channel
Drawing events (tvchart:drawing-added, tvchart:drawing-deleted) are emitted to Python for persistence or analysis.
Theming¶
Charts automatically follow the PyWry theme (dark/light). Toggle at runtime:
Or set it at creation:
API Reference¶
| Module | Description |
|---|---|
| TVChartConfig | Configuration models (enums, chart options, templates, themes) |
| Models | Datafeed request/response protocol models |
| DatafeedProvider | Abstract base class for data sources |
| UDFAdapter | UDF HTTP server adapter |
| TVChartStateMixin | Python ↔ JS bridge methods |
| Events | All 52 tvchart:* events |