In this tutorial, we’ll build a real-time stock market heatmap that visualize all 50 stocks from the NIFTY 50 index. The heatmap displays each stock’s daily performance using color gradients—bright green for top gainers, deep red for biggest losers, and shades in between for everything else.

By the end of this tutorial, you’ll have a script that fetches live market data, processes it into a sorted grid, and generates a publication-ready visualization like the one shown above.
Prerequisites
Before we begin, ensure you have the following installed:
pip install openalgo pandas plotly kaleido
You’ll also need a running OpenAlgo server with a valid API key. OpenAlgo connects to 25+ Indian stock brokers and provides a unified API for fetching market data.
Ensure from openalgo, Goto openalgo-> click on profile icon -> Select API Key and Copy the OpenAlgo API Key and keep it secure
Understanding the Building Blocks
Our heatmap solution uses three key libraries:
OpenAlgo handles the connection to your broker and fetches live market quotes. It abstracts away broker-specific APIs, giving you a single interface to work with.
Pandas manages our data in tabular format. We’ll use DataFrames to store stock symbols, calculate percentage changes, and prepare data for visualization.
Plotly Express creates the interactive heatmap. It provides the imshow function which is perfect for grid-based visualizations with color gradients.
Step 1: Initialize the OpenAlgo Client
The first step is establishing a connection to your OpenAlgo server:
from openalgo import api
import pandas as pd
import plotly.express as px
# Initialize OpenAlgo client
client = api(
api_key="your_api_key_here",
host="http://127.0.0.1:5000"
)
print("OpenAlgo Python Bot is running.")
Replace your_api_key_here with your actual API key from the OpenAlgo dashboard. The host parameter points to your local OpenAlgo server—adjust this if you’re running it on a different machine or port.
Step 2: Define NIFTY 50 Symbols
Create a list containing all 50 stocks from the NIFTY 50 index:
symbols = [
"INDIGO", "TRENT", "HINDUNILVR", "HCLTECH", "WIPRO", "INFY", "TATACONSUM",
"TATASTEEL", "ITC", "ASIANPAINT", "SBILIFE", "LT", "SHRIRAMFIN", "BEL", "SBIN",
"COALINDIA", "KOTAKBANK", "TCS", "SUNPHARMA", "MAXHEALTH", "NESTLEIND",
"RELIANCE", "ETERNAL", "APOLLOHOSP", "ICICIBANK", "GRASIM", "ULTRACEMCO",
"ADANIENT", "AXISBANK", "DRREDDY", "TECHM", "TMPV", "JIOFIN", "NTPC",
"BAJFINANCE", "BHARTIARTL", "POWERGRID", "HINDALCO", "HDFCBANK", "TITAN",
"HDFCLIFE", "MARUTI", "BAJAJFINSV", "ADANIPORTS", "CIPLA", "JSWSTEEL",
"BAJAJ-AUTO", "ONGC", "EICHERMOT", "M&M"
]
Note that NIFTY 50 constituents change periodically. NSE updates the index composition based on market capitalization and liquidity. Always verify the current list from NSE India’s official website.
Step 3: Fetch Live Market Quotes
OpenAlgo’s multiquotes function allows you to fetch data for multiple symbols in a single API call:
# Prepare symbols for API request
quote_symbols = [{"symbol": s, "exchange": "NSE"} for s in symbols]
# Fetch live quotes
response = client.multiquotes(symbols=quote_symbols)
The multiquotes function expects a list of dictionaries, each containing a symbol and exchange key. This is more efficient than making 50 separate API calls.
Step 4: Calculate Percentage Change
Extract the Last Traded Price (LTP) and previous close from each response, then calculate the percentage change:
rows = []
print("\nLive Market Data:")
for item in response["results"]:
symbol = item["symbol"]
ltp = item["data"]["ltp"]
prev_close = item["data"]["prev_close"]
# Calculate percentage change
change_pct = round(((ltp - prev_close) / prev_close) * 100, 2)
print(f"{symbol} | LTP: {ltp} | Change: {change_pct}%")
rows.append([symbol, change_pct])
The formula ((ltp - prev_close) / prev_close) * 100 gives us the percentage change from yesterday’s closing price. We round to 2 decimal places for cleaner display.
Step 5: Prepare Data for Heatmap Grid
Transform the data into a grid format suitable for the heatmap:
# Create DataFrame
df = pd.DataFrame(rows, columns=["Symbol", "Change"])
# Sort by change: top gainers first, bottom losers last
df = df.sort_values("Change", ascending=False).reset_index(drop=True)
# Create 10x5 grid layout
cols = 10
df["row"] = df.index // cols
df["col"] = df.index % cols
# Pivot for heatmap
pivot_values = df.pivot(index="row", columns="col", values="Change")
pivot_labels = df.pivot(index="row", columns="col", values="Symbol")
Let’s break down the grid logic:
The expression df.index // cols performs integer division to determine the row number. For indices 0-9, this gives row 0; for indices 10-19, row 1; and so on.
The expression df.index % cols uses the modulo operator to determine the column position within each row. Index 0 goes to column 0, index 11 goes to column 1, etc.
The pivot function reshapes our linear data into a 2D grid where rows and columns represent positions on the heatmap.
Step 6: Create the Heatmap Visualization
Use Plotly Express to generate the heatmap:
fig = px.imshow(
pivot_values,
color_continuous_scale="RdYlGn",
aspect="auto"
)
fig.update_traces(
text=pivot_labels.values,
texttemplate="%{text}<br>%{z:.2f}%",
hovertemplate="Symbol: %{text}<br>Change: %{z:.2f}%"
)
fig.update_layout(
title="NIFTY 50 Sorted Heatmap (%)",
xaxis=dict(type="category", title=""),
yaxis=dict(type="category", autorange="reversed", title=""),
template="plotly_dark",
height=600
)
Key configuration options explained:
color_continuous_scale=”RdYlGn” uses a Red-Yellow-Green color scale. Negative values appear red, values near zero appear yellow, and positive values appear green.
texttemplate controls what appears inside each cell. The %{text} placeholder shows the symbol name, <br> adds a line break, and %{z:.2f}% displays the percentage value with 2 decimal places.
template=”plotly_dark” applies a dark theme that makes the colors pop and is easier on the eyes during market hours.
Step 7: Save the Heatmap
Export the visualization as a high-resolution PNG image:
fig.write_image(
"nifty50_heatmap.png",
width=1200,
height=600,
scale=2
)
print("\nHeatmap saved as nifty50_heatmap.png")
The scale=2 parameter doubles the resolution, producing a crisp 2400×1200 pixel image. This requires the kaleido package for static image export.
Nifty 50 Heatmap – Full Python Code
from openalgo import api
import pandas as pd
import plotly.express as px
# ---------------------------------------------------
# OpenAlgo Client
# ---------------------------------------------------
client = api(
api_key="7371cc58b9d30204e5fee1d143dc8cd926bcad90c24218201ad81735384d2752",
host="http://127.0.0.1:5000"
)
print("OpenAlgo Python Bot is running.")
# ---------------------------------------------------
# NIFTY 50 SYMBOLS
# ---------------------------------------------------
symbols = [
"INDIGO","TRENT","HINDUNILVR","HCLTECH","WIPRO","INFY","TATACONSUM",
"TATASTEEL","ITC","ASIANPAINT","SBILIFE","LT","SHRIRAMFIN","BEL","SBIN",
"COALINDIA","KOTAKBANK","TCS","SUNPHARMA","MAXHEALTH","NESTLEIND",
"RELIANCE","ETERNAL","APOLLOHOSP","ICICIBANK","GRASIM","ULTRACEMCO",
"ADANIENT","AXISBANK","DRREDDY","TECHM","TMPV","JIOFIN","NTPC",
"BAJFINANCE","BHARTIARTL","POWERGRID","HINDALCO","HDFCBANK","TITAN",
"HDFCLIFE","MARUTI","BAJAJFINSV","ADANIPORTS","CIPLA","JSWSTEEL",
"BAJAJ-AUTO","ONGC","EICHERMOT","M&M"
]
# ---------------------------------------------------
# FETCH LIVE QUOTES
# ---------------------------------------------------
quote_symbols = [{"symbol": s, "exchange": "NSE"} for s in symbols]
response = client.multiquotes(symbols=quote_symbols)
rows = []
print("\n📊 Live Market Data:")
for item in response["results"]:
symbol = item["symbol"]
ltp = item["data"]["ltp"]
prev_close = item["data"]["prev_close"]
change_pct = round(((ltp - prev_close) / prev_close) * 100, 2)
# Print immediately (rule)
print(f"{symbol} | LTP: {ltp} | Change: {change_pct}%")
rows.append([symbol, change_pct])
# ---------------------------------------------------
# PREPARE + SORT DATA
# ---------------------------------------------------
df = pd.DataFrame(rows, columns=["Symbol", "Change"])
# SORT: TOP GAINERS → BOTTOM LOSERS
df = df.sort_values("Change", ascending=False).reset_index(drop=True)
# Grid: 10 columns x 5 rows
cols = 10
df["row"] = df.index // cols
df["col"] = df.index % cols
pivot_values = df.pivot(index="row", columns="col", values="Change")
pivot_labels = df.pivot(index="row", columns="col", values="Symbol")
# ---------------------------------------------------
# HEATMAP PLOT
# ---------------------------------------------------
fig = px.imshow(
pivot_values,
color_continuous_scale="RdYlGn",
aspect="auto"
)
fig.update_traces(
text=pivot_labels.values,
texttemplate="%{text}<br>%{z:.2f}%",
hovertemplate="Symbol: %{text}<br>Change: %{z:.2f}%"
)
fig.update_layout(
title="NIFTY 50 Sorted Heatmap (%)",
xaxis=dict(type="category", title=""),
yaxis=dict(type="category", autorange="reversed", title=""),
template="plotly_dark",
height=600
)
# ---------------------------------------------------
# SAVE IMAGE (NO HTML OUTPUT)
# ---------------------------------------------------
fig.write_image(
"nifty50_heatmap.png",
width=1200,
height=600,
scale=2
)
print("\nHeatmap saved as nifty50_heatmap.png")