import gradio as gr
import yfinance as yf
import plotly.graph_objs as go
import pandas as pd
STYLE_BLOCK = """
"""
def fetch_data(symbol, req_type):
try:
ticker = yf.Ticker(symbol)
# Info block as cards + big boxes
if req_type.lower() == "info":
info = ticker.info
if not info:
return "
No info available
"
long_summary = info.pop("longBusinessSummary", None)
officers = info.pop("companyOfficers", None)
cards = "".join(
f""
for key, value in info.items()
)
extra_sections = ""
if long_summary:
extra_sections += f"Business Summary
{long_summary}
"
if officers:
officer_rows = "".join(
f"| {o.get('name','')} | {o.get('title','')} | {o.get('age','')} |
"
for o in officers
)
officer_table = f"| Name | Title | Age |
{officer_rows}
"
extra_sections += f"Company Officers
{officer_table}"
return f"{STYLE_BLOCK}{cards}{extra_sections}"
# Daily chart
elif req_type.lower() == "daily":
df = yf.download(symbol, period="1y", interval="1d").round(2)
if df.empty:
return f"No daily data for {symbol}
"
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
low_price = df["Low"].min()
high_price = df["High"].max()
price_range = high_price - low_price
vol_band_min = low_price - (price_range / 5)
vol_band_max = low_price
vol_max = df["Volume"].max()
vol_scale = (vol_band_max - vol_band_min) / vol_max if vol_max > 0 else 1
fig = go.Figure()
fig.add_trace(go.Candlestick(
x=df.index, open=df["Open"], high=df["High"],
low=df["Low"], close=df["Close"], name="Price"
))
fig.add_trace(go.Bar(
x=df.index,
y=df["Volume"] * vol_scale + vol_band_min,
name="Volume", marker_color="lightblue",
customdata=df["Volume"],
hovertemplate="Volume: %{customdata}"
))
fig.update_layout(
xaxis_title="Date", yaxis_title="Price",
yaxis=dict(range=[vol_band_min, high_price]),
xaxis_rangeslider_visible=False, height=600
)
chart_html = fig.to_html(full_html=False)
table_html = df.tail(30).to_html(classes="styled-table", border=0)
return f"{chart_html}Recent Daily Data (last 30 rows)
{STYLE_BLOCK}{table_html}"
# Intraday chart
elif req_type.lower() == "intraday":
df = yf.download(symbol, period="1d", interval="5m").round(2)
if df.empty:
return f"No intraday data for {symbol}
"
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
low_price = df["Low"].min()
high_price = df["High"].max()
price_range = high_price - low_price
vol_band_min = low_price - (price_range / 5)
vol_band_max = low_price
vol_max = df["Volume"].max()
vol_scale = (vol_band_max - vol_band_min) / vol_max if vol_max > 0 else 1
fig = go.Figure()
fig.add_trace(go.Candlestick(
x=df.index, open=df["Open"], high=df["High"],
low=df["Low"], close=df["Close"], name="Price"
))
fig.add_trace(go.Bar(
x=df.index,
y=df["Volume"] * vol_scale + vol_band_min,
name="Volume", marker_color="orange",
customdata=df["Volume"],
hovertemplate="Volume: %{customdata}"
))
fig.update_layout(
xaxis_title="Time", yaxis_title="Price",
yaxis=dict(range=[vol_band_min, high_price]),
xaxis_rangeslider_visible=False, height=600
)
chart_html = fig.to_html(full_html=False)
table_html = df.tail(50).to_html(classes="styled-table", border=0)
return f"{chart_html}Recent Intraday Data (last 50 rows)
{STYLE_BLOCK}{table_html}"
# Financial sections
elif req_type.lower() == "qresult":
df = ticker.quarterly_financials
return f"Quarterly Results
{STYLE_BLOCK}{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No quarterly results available
"
elif req_type.lower() == "result":
df = ticker.financials
return f"Annual Results
{STYLE_BLOCK}{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No annual results available
"
elif req_type.lower() == "balance":
df = ticker.balance_sheet
return f"Balance Sheet
{STYLE_BLOCK}{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No balance sheet available
"
elif req_type.lower() == "cashflow":
df = ticker.cashflow
return f"Cash Flow
{STYLE_BLOCK}{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No cashflow available
"
elif req_type.lower() == "dividend":
s = ticker.dividends
return f"Dividend History
{STYLE_BLOCK}{s.to_frame('Dividend').to_html(classes='styled-table', border=0)}" if not s.empty else "No dividend history available
"
elif req_type.lower() == "split":
s = ticker.splits
return f"Split History
{STYLE_BLOCK}{s.to_frame('Split').to_html(classes='styled-table', border=0)}" if not s.empty else "No split history available
"
elif req_type.lower() == "other":
df = ticker.earnings
return f"Earnings
{STYLE_BLOCK}{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No earnings data available
"
else:
return f"No handler for {req_type}
"
except Exception as e:
return f"Error
{str(e)}
"
iface = gr.Interface(
fn=fetch_data,
inputs=[
gr.Textbox(label="Stock Symbol", value="PNB.NS"),
gr.Dropdown(
label="Request Type",
choices=[
"info",
"intraday",
"daily",
"qresult",
"result",
"balance",
"cashflow",
"dividend",
"split",
"other"
],
value="info"
)
],
outputs=gr.HTML(label="Full HTML Output"),
title="Stock Data API (Full)",
description="Fetch data from NSE and yfinance",
api_name="fetch_data"
)
if __name__ == "__main__":
iface.launch(server_name="0.0.0.0", server_port=7860)