If you’re a trader or developer working with Indian stock market data, you’ve likely faced one of two problems:
- Struggling to visualize stock data effectively
- Wrestling with APIs or charting libraries that are overly complex
In this guide, we combine the OpenAlgo API with TradingView-style Lightweight Charts in Python to solve both.
We’ll walk through seven different examples, each focusing on a use case—from simple candlesticks to dynamic symbols, drawing tools, and multi-symbol comparison.
This article is code-heavy and practical. By the end, you’ll be able to build high-performance, interactive financial charts using Python with Indian market data.
What Is OpenAlgo?
OpenAlgo is a powerful platform that provides APIs for 22+ Indian brokers like Angel One, Zerodha, Fyers, Upstox, Dhan, Kotak, and more. You can fetch historical and live market data, place orders, access Realtime streaming quotes, and much more.

For these examples, we use client.history() to fetch historical bar data for NSE stocks.
What Are Lightweight Charts?
Lightweight Charts by TradingView is a modern charting library optimized for performance and clarity. The Python wrapper we use enables native integration with Pandas data and UI interactivity in one line.

Prerequisites
Install the following packages:
pip install openalgo lightweight-charts pandas
Make sure your OpenAlgo server is running locally (or remotely), and you have a valid api_key.
Example 1: Basic Candlestick Chart
This is the simplest version. It downloads data for RELIANCE using OpenAlgo and renders it in a clean chart.
What you get:
- Full OHLCV data
- No overlays or indicators
- JSON-serializable time formatting
This is perfect as a starting template or sanity check for your data.

Python Code
import pandas as pd
from datetime import datetime, timedelta
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(api_key='your-openalgo-apikey', host='http://127.0.0.1:5000')
def prepare_openalgo_chart_data(symbol="RELIANCE", exchange="NSE", interval="5m", days=5):
from datetime import datetime, timedelta
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
df = client.history(
symbol=symbol,
exchange=exchange,
interval=interval,
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index)
df_reset = df.reset_index()
# Detect the datetime column
datetime_col = next(
(col for col in df_reset.columns if pd.api.types.is_datetime64_any_dtype(df_reset[col])),
None
)
if datetime_col is None:
raise ValueError("No datetime column found")
has_time = any(df_reset[datetime_col].dt.hour != 0)
df_reset['time'] = df_reset[datetime_col].dt.strftime(
'%Y-%m-%d %H:%M:%S' if has_time else '%Y-%m-%d'
)
result_df = pd.DataFrame({
'time': df_reset['time'],
'open': df_reset['open'],
'high': df_reset['high'],
'low': df_reset['low'],
'close': df_reset['close'],
'volume': df_reset['volume']
})
return result_df
if __name__ == "__main__":
print("🔁 OpenAlgo Python Bot is Downloading Data.")
# Prepare data for the chart
chart_data = prepare_openalgo_chart_data(symbol="RELIANCE", exchange="NSE", interval="5m", days=30)
# Plot using lightweight-charts
chart = Chart()
chart.set(chart_data)
chart.show(block=True)
Example 2: Add Simple Moving Average (SMA)
Here we calculate a 50-period SMA and overlay it on the chart as a colored line.
This is useful for:
- Trend-following strategies
- Technical analysis
- Visual support/resistance detection
The overlay is clean, optimized for performance, and uses Pandas’ rolling().mean() under the hood.

Python Code
import pandas as pd
from datetime import datetime, timedelta
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(api_key='your-openalgo-apikey', host='http://127.0.0.1:5000')
def fetch_openalgo_data(symbol="RELIANCE", exchange="NSE", interval="1d", days=365):
"""
Fetch historical data from OpenAlgo
"""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
response = client.history(
symbol=symbol,
exchange=exchange,
interval=interval,
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
# Check if response is valid DataFrame
if not isinstance(response, pd.DataFrame):
print("❌ Failed to fetch data:", response)
raise ValueError("OpenAlgo did not return a DataFrame")
if response.empty:
raise ValueError("Received empty data from OpenAlgo.")
# Ensure datetime index
if not isinstance(response.index, pd.DatetimeIndex):
response.index = pd.to_datetime(response.index)
return response
def prepare_data_for_chart(df):
"""
Format OpenAlgo DataFrame for lightweight-charts
"""
df_reset = df.reset_index()
# Find datetime column
datetime_col = next(
(col for col in df_reset.columns if pd.api.types.is_datetime64_any_dtype(df_reset[col])),
None
)
if datetime_col is None:
raise ValueError("No datetime column found.")
df_reset['time'] = df_reset[datetime_col].dt.strftime('%Y-%m-%d')
return pd.DataFrame({
'time': df_reset['time'],
'open': df_reset['open'],
'high': df_reset['high'],
'low': df_reset['low'],
'close': df_reset['close'],
'volume': df_reset['volume']
})
def calculate_sma(df, period=50):
"""
Calculate Simple Moving Average for lightweight-charts
"""
sma_values = df['close'].rolling(window=period).mean()
sma_df = pd.DataFrame({
'time': df.index.strftime('%Y-%m-%d'),
f'SMA {period}': sma_values
})
return sma_df.dropna()
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
# Fetch data
df = fetch_openalgo_data(symbol="RELIANCE", exchange="NSE", interval="D", days=365)
# Prepare chart data
chart_data = prepare_data_for_chart(df)
# Calculate SMA
sma50_data = calculate_sma(df, 50)
# Create chart
chart = Chart()
chart.legend(visible=True)
chart.set(chart_data)
# Create SMA line
sma_line = chart.create_line('SMA 50', '#FF5733')
sma_line.set(sma50_data)
chart.show(block=True)
Example 3: RSI with Subchart
This example adds a Relative Strength Index (RSI) indicator in a separate subpanel below the main chart.
Highlights:
- Uses subcharts for better separation of logic
- Shows RSI(14) values with horizontal markers at 30 and 70
- Watermarked with symbol and indicator name
Ideal for building momentum-based strategies or dashboards.

Python Code
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(
api_key='your-openalgo-apikey',
host='http://127.0.0.1:5000'
)
def fetch_openalgo_data(symbol="RELIANCE", exchange="NSE", interval="D", days=365):
"""
Fetch historical data from OpenAlgo
"""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
response = client.history(
symbol=symbol,
exchange=exchange,
interval=interval,
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
if not isinstance(response, pd.DataFrame):
print("❌ Failed to fetch data:", response)
raise ValueError("OpenAlgo did not return a DataFrame")
if not isinstance(response.index, pd.DatetimeIndex):
response.index = pd.to_datetime(response.index)
return response
def prepare_data_for_chart(df):
"""
Format OpenAlgo DataFrame for lightweight-charts
"""
df_reset = df.reset_index()
datetime_col = next(
(col for col in df_reset.columns if pd.api.types.is_datetime64_any_dtype(df_reset[col])),
None
)
df_reset['time'] = df_reset[datetime_col].dt.strftime('%Y-%m-%d')
return pd.DataFrame({
'time': df_reset['time'],
'open': df_reset['open'],
'high': df_reset['high'],
'low': df_reset['low'],
'close': df_reset['close'],
'volume': df_reset['volume']
})
def calculate_rsi(df, period=14):
"""
Calculate RSI from OpenAlgo close prices
"""
close = df['close']
delta = close.diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
rsi_df = pd.DataFrame({
'time': df.index.strftime('%Y-%m-%d'),
'RSI (14)': rsi
})
return rsi_df
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
symbol = "RELIANCE"
df = fetch_openalgo_data(symbol=symbol, exchange="NSE", interval="D", days=365)
chart_data = prepare_data_for_chart(df)
rsi_data = calculate_rsi(df, 14)
# Create main chart (candlestick + volume)
chart = Chart(inner_width=1, inner_height=0.7)
chart.legend(visible=True)
chart.layout(
background_color='#151924',
text_color='#FFFFFF',
font_size=14,
font_family='Arial'
)
chart.candle_style(
up_color='#26a69a',
down_color='#ef5350',
border_up_color='#26a69a',
border_down_color='#ef5350',
wick_up_color='#26a69a',
wick_down_color='#ef5350'
)
chart.volume_config(
up_color='rgba(38, 166, 154, 0.5)',
down_color='rgba(239, 83, 80, 0.5)'
)
# RSI Subchart (bottom panel)
rsi_subchart = chart.create_subchart(width=1, height=0.3, sync=True)
chart.set(chart_data)
rsi_line = rsi_subchart.create_line('RSI (14)', '#8A2BE2')
rsi_line.set(rsi_data)
rsi_subchart.horizontal_line(70, color='#FF6B6B')
rsi_subchart.horizontal_line(30, color='#4CAF50')
chart.watermark(symbol, color='rgba(255, 255, 255, 0.1)')
rsi_subchart.watermark('RSI (14)', color='rgba(255, 255, 255, 0.1)')
chart.show(block=True)
Example 4: Dual Chart Comparison (INFY vs TCS)
Want to compare two stocks side by side? This chart renders two candlestick charts—INFY and TCS—horizontally split.
Why it’s useful:
- Compare sector stocks (e.g., Infosys vs TCS)
- Visual divergence detection
- Independent navigation per chart
The layout remains responsive, and each chart maintains its styling and watermark.

Python Code
import pandas as pd
from datetime import datetime, timedelta
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(
api_key='your-openalgo-apikey',
host='http://127.0.0.1:5000'
)
def fetch_openalgo_data(symbol, exchange="NSE", interval="D", days=365):
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
df = client.history(
symbol=symbol,
exchange=exchange,
interval=interval,
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
if not isinstance(df, pd.DataFrame):
raise ValueError(f"Error fetching data for {symbol}: {df}")
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index)
return df
def prepare_data_for_chart(df):
df_reset = df.reset_index()
datetime_col = next(
(col for col in df_reset.columns if pd.api.types.is_datetime64_any_dtype(df_reset[col])),
None
)
df_reset['time'] = df_reset[datetime_col].dt.strftime('%Y-%m-%d')
return pd.DataFrame({
'time': df_reset['time'],
'open': df_reset['open'],
'high': df_reset['high'],
'low': df_reset['low'],
'close': df_reset['close'],
'volume': df_reset['volume']
})
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
# Fetch and prepare data for INFY and TCS
infy_df = fetch_openalgo_data("INFY", "NSE", "D", 365)
tcs_df = fetch_openalgo_data("TCS", "NSE", "D", 365)
infy_data = prepare_data_for_chart(infy_df)
tcs_data = prepare_data_for_chart(tcs_df)
# Create side-by-side charts
chart = Chart(inner_width=0.5, inner_height=1)
chart2 = chart.create_subchart(position='right', width=0.5, height=1)
# Styling
for c in [chart, chart2]:
c.layout(
background_color='#151924',
text_color='#FFFFFF',
font_size=14,
font_family='Arial'
)
c.candle_style(
up_color='#26a69a',
down_color='#ef5350',
border_up_color='#26a69a',
border_down_color='#ef5350',
wick_up_color='#26a69a',
wick_down_color='#ef5350'
)
c.volume_config(
up_color='rgba(38, 166, 154, 0.5)',
down_color='rgba(239, 83, 80, 0.5)'
)
c.legend(visible=True)
# Set data and labels
chart.set(infy_data)
chart2.set(tcs_data)
chart.watermark('INFY', color='rgba(255, 255, 255, 0.1)')
chart2.watermark('TCS', color='rgba(255, 255, 255, 0.1)')
chart.show(block=True)
Example 5: Toolbox with Drawing Tools
This version enables drawing tools for manual analysis:
- Trendlines
- Rays
- Horizontal lines
- Rectangles
And it can export drawings to JSON for later use.
This is ideal for traders who rely on manual annotations or want to simulate a TradingView-like UI.

Python Code
import pandas as pd
from datetime import datetime, timedelta
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(
api_key='your-openalgo-apikey',
host='http://127.0.0.1:5000'
)
def fetch_openalgo_data(symbol, exchange="NSE", interval="D", days=365):
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
df = client.history(
symbol=symbol,
exchange=exchange,
interval=interval,
start_date=start_date.strftime("%Y-%m-%d"),
end_date=end_date.strftime("%Y-%m-%d")
)
if not isinstance(df, pd.DataFrame):
raise ValueError(f"Error fetching data for {symbol}: {df}")
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index)
return df
def prepare_data_for_chart(df):
df_reset = df.reset_index()
datetime_col = next(
(col for col in df_reset.columns if pd.api.types.is_datetime64_any_dtype(df_reset[col])),
None
)
df_reset['time'] = df_reset[datetime_col].dt.strftime('%Y-%m-%d')
return pd.DataFrame({
'time': df_reset['time'],
'open': df_reset['open'],
'high': df_reset['high'],
'low': df_reset['low'],
'close': df_reset['close'],
'volume': df_reset['volume']
})
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
# Select symbol
symbol = "INFY" # Replace with "TCS", "SBIN", etc. if needed
# Fetch data
df = fetch_openalgo_data(symbol=symbol, exchange="NSE", interval="D", days=365)
chart_data = prepare_data_for_chart(df)
# Create chart with toolbox enabled
chart = Chart(toolbox=True)
chart.legend(visible=True)
chart.layout(
background_color='#151924',
text_color='#FFFFFF',
font_size=14,
font_family='Arial'
)
chart.candle_style(
up_color='#26a69a',
down_color='#ef5350',
border_up_color='#26a69a',
border_down_color='#ef5350',
wick_up_color='#26a69a',
wick_down_color='#ef5350'
)
chart.set(chart_data)
chart.watermark(symbol, color='rgba(255, 255, 255, 0.1)')
print("\n📐 Drawing Tools Available:")
print("1. Click the toolbox button in the top-right corner")
print("2. Select: Trendline, Horizontal Line, Ray, Rectangle")
print("3. Draw directly on the chart")
chart.show(block=True)
# Export drawings on close
chart.toolbox.export_drawings('drawings.json')
print("✅ Drawings saved to drawings.json")
Example 6: Dynamic Symbol + Timeframe Switcher
This is a fully dynamic, production-grade chart:
- Search box for changing symbols (e.g., INFY, SBIN)
- Switcher to toggle between
1m,5m,15m,1h,D - Uses only OpenAlgo-supported intervals
- Chart is auto-updated when symbol or timeframe changes
It also includes dynamic watermarking, JSON-safe time formatting, and drawing preservation.

Python Code
import pandas as pd
import datetime as dt
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo client
client = api(
api_key='your-openalgo-apikey',
host='http://127.0.0.1:5000'
)
def get_data_for_timeframe(symbol, timeframe):
"""Fetch OpenAlgo historical data for given symbol and timeframe (fixed NSE exchange)."""
end_date = dt.datetime.now()
days_map = {
'1m': 2,
'5m': 15,
'15m': 30,
'1h': 90,
'D': 730
}
start_date = end_date - dt.timedelta(days=days_map.get(timeframe, 30))
df = client.history(
symbol=symbol,
exchange="NSE",
interval=timeframe,
start_date=start_date.strftime('%Y-%m-%d'),
end_date=end_date.strftime('%Y-%m-%d')
)
if not isinstance(df, pd.DataFrame) or df.empty:
print(f"⚠️ No data for {symbol} [{timeframe}]")
return pd.DataFrame()
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index)
return df
def prepare_data_for_chart(df):
df = df.reset_index()
date_col = next((col for col in df.columns if pd.api.types.is_datetime64_any_dtype(df[col])), None)
if date_col is None:
return pd.DataFrame()
has_time = df[date_col].dt.hour.ne(0).any()
time_format = '%Y-%m-%d %H:%M:%S' if has_time else '%Y-%m-%d'
df['time'] = df[date_col].dt.strftime(time_format)
return df[['time', 'open', 'high', 'low', 'close', 'volume']]
def on_timeframe_selection(chart):
symbol = chart.topbar['symbol'].value
timeframe = chart.topbar['timeframe'].value
df = get_data_for_timeframe(symbol, timeframe)
if df.empty:
return
chart_data = prepare_data_for_chart(df)
chart.set(chart_data, keep_drawings=True)
chart.watermark(f"{symbol} - NSE - {timeframe}", color='rgba(255, 255, 255, 0.1)')
def on_symbol_search(chart, searched_string):
chart.topbar['symbol'].set(searched_string)
on_timeframe_selection(chart)
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
default_symbol = "RELIANCE"
default_timeframe = "D"
chart = Chart(inner_width=1, inner_height=1)
chart.topbar.textbox('symbol', default_symbol)
chart.topbar.switcher(
'timeframe', ('1m', '5m', '15m', '1h', 'D'),
default=default_timeframe,
func=on_timeframe_selection
)
chart.events.search += on_symbol_search
chart.layout(
background_color='#151924',
text_color='#FFFFFF',
font_size=12,
font_family='Arial'
)
chart.candle_style(
up_color='#26a69a',
down_color='#ef5350',
border_up_color='#26a69a',
border_down_color='#ef5350',
wick_up_color='#26a69a',
wick_down_color='#ef5350'
)
chart.volume_config(
up_color='rgba(38, 166, 154, 0.5)',
down_color='rgba(239, 83, 80, 0.5)'
)
# Load default data
df = get_data_for_timeframe(default_symbol, default_timeframe)
chart_data = prepare_data_for_chart(df)
chart.set(chart_data)
chart.watermark(f"{default_symbol} - NSE - {default_timeframe}", color='rgba(255, 255, 255, 0.1)')
chart.show(block=True)
Example 7: OpenAlgo Dynamic Symbols + Timeswitcher and Drawing Tool
The final example rewrites a Dynamic Symbols + Timeswitcher and Drawing Tool based TradingView chart to use OpenAlgo symbols and exchanges directly.
Benefits:
- Works for all NSE symbols like
TCS,INFY,BANKNIFTY, etc. - Fully mapped to OpenAlgo-compatible formats
This is the best way to future-proof your charting tool for real market data with OpenAlgo infrastructure.

Python Code
import datetime as dt
import pandas as pd
from lightweight_charts import Chart
from openalgo import api
# Initialize OpenAlgo API
client = api(
api_key='your-openalgo-apikey',
host='http://127.0.0.1:5000'
)
def prepare_data_for_chart(df, verbose=False):
df = df.copy()
# Ensure datetime index
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index)
# Reset index to get datetime column
df = df.reset_index()
df = df.rename(columns={df.columns[0]: 'time'})
# Convert to string for lightweight_charts
df['time'] = df['time'].dt.strftime('%Y-%m-%d %H:%M:%S' if df['time'].dt.hour.ne(0).any() else '%Y-%m-%d')
return df[['time', 'open', 'high', 'low', 'close', 'volume']]
def get_bar_data(symbol, timeframe):
"""Fetch bar data from OpenAlgo"""
now = dt.datetime.now()
days_map = {
'1m': 2,
'5m': 15,
'30m': 30,
'D': 365,
'W': 730
}
interval_map = {
'1m': '1m',
'5m': '5m',
'30m': '30m',
'1d': 'D',
'1wk': 'W'
}
interval = interval_map.get(timeframe)
if not interval:
print(f"⚠ Unsupported timeframe: {timeframe}")
return False
start_date = now - dt.timedelta(days=days_map[interval])
chart.spinner(True)
try:
df = client.history(
symbol=symbol,
exchange='NSE',
interval=interval,
start_date=start_date.strftime('%Y-%m-%d'),
end_date=now.strftime('%Y-%m-%d')
)
except Exception as e:
print(f"❌ Error fetching data: {e}")
chart.spinner(False)
return False
chart.spinner(False)
if not isinstance(df, pd.DataFrame) or df.empty:
print(f"⚠ No data received for {symbol}")
return False
chart_data = prepare_data_for_chart(df)
chart.set(chart_data)
return True
def on_search(chart, searched_string):
if get_bar_data(searched_string, chart.topbar['timeframe'].value):
chart.topbar['symbol'].set(searched_string)
def on_timeframe_selection(chart):
get_bar_data(chart.topbar['symbol'].value, chart.topbar['timeframe'].value)
if __name__ == '__main__':
print("🔁 OpenAlgo Python Bot is Downloading Data.")
chart = Chart(toolbox=True)
chart.legend(True)
chart.events.search += on_search
chart.topbar.textbox('symbol', 'TCS')
chart.topbar.switcher(
'timeframe',
('1m', '5m', '30m', '1d', '1wk'),
default='5m',
func=on_timeframe_selection
)
# Load default data at startup
get_bar_data('TCS', '5m')
chart.show(block=True)
Supported Timeframes in OpenAlgo
Only these intervals are officially supported:
- Seconds:
5s,10s,15s,30s,45s - Minutes:
1m,2m,3m,5m,10m,15m,20m,30m - Hours:
1h,2h,4h - Daily:
D - Weekly:
W - Monthly:
M
All charts shown in this guide use 1m, 5m, 15m, 1h, and D to avoid API compatibility issues. Different brokers support different timeframes. Check your broker supported interval and enter the timeframe value accordingly.
With OpenAlgo and lightweight-charts, you can now build:
- High-speed chart dashboards
- Strategy testers with overlays
- Real-time market visualizers
- Personal trading terminals
For production apps, you can integrate these with Flask, FastAPI, or any Electron frontend.
Where to Go Next?
- 📘 Official Docs: https://docs.openalgo.in
- 💬 Developer Community: https://openalgo.in/discord