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):
yfsymbol=symbol+".NS"
try:
ticker = yf.Ticker(yfsymbol)
content_html = ""
# Info block as cards + big boxes
if req_type.lower() == "info":
info = ticker.info
if not info:
content_html = "
No info available
"
else:
info_categories = {
"Company Overview": [
"longName", "symbol", "exchange", "quoteType", "sector", "industry",
"fullTimeEmployees", "website", "address1", "city", "state", "zip", "country", "phone"
],
"Valuation Metrics": [
"marketCap", "enterpriseValue", "trailingPE", "forwardPE", "pegRatio",
"priceToSalesTrailing12Months", "enterpriseToRevenue", "enterpriseToEbitda"
],
"Key Financials": [
"fiftyTwoWeekHigh", "fiftyTwoWeekLow", "fiftyDayAverage", "twoHundredDayAverage",
"trailingAnnualDividendRate", "trailingAnnualDividendYield", "dividendRate", "dividendYield",
"exDividendDate", "lastSplitFactor", "lastSplitDate", "lastDividendValue", "payoutRatio",
"beta", "sharesOutstanding", "impliedSharesOutstanding"
],
"Operational Details": [
"auditRisk", "boardRisk", "compensationRisk", "shareHolderRightsRisk", "overallRisk",
"governanceEpochDate", "compensationAsOfEpochDate"
],
"Trading Information": [
"open", "previousClose", "dayLow", "dayHigh", "volume", "averageVolume", "averageVolume10days",
"fiftyTwoWeekChange", "SandP52WeekChange", "currency", "regularMarketDayLow",
"regularMarketDayHigh", "regularMarketOpen", "regularMarketPreviousClose",
"regularMarketPrice", "regularMarketVolume", "regularMarketChange", "regularMarketChangePercent"
],
"Analyst & Target": [
"targetMeanPrice", "numberOfAnalystOpinions", "recommendationKey", "recommendationMean"
]
}
long_summary = info.pop("longBusinessSummary", None)
officers = info.pop("companyOfficers", None)
categorized_html = ""
for category_name, keys in info_categories.items():
category_key_value_html = "" # Collect key-value pairs for this category
for key in keys:
if key in info and info[key] is not None and info[key] != []:
value = info[key]
# Format values as appropriate
if isinstance(value, (int, float)) and key not in ['longName', 'symbol', 'exchange', 'quoteType', 'sector', 'industry', 'website', 'address1', 'city', 'state', 'zip', 'country', 'phone', 'longBusinessSummary', 'recommendationKey']:
if 'marketCap' in key.lower() or 'value' in key.lower() or 'volume' in key.lower():
value = f"{value:,.0f}" # Format large numbers
elif 'percent' in key.lower() or 'ratio' in key.lower() or 'yield' in key.lower() or 'beta' in key.lower() or 'payoutRatio' in key.lower():
value = f"{value:.2%}" # Format percentages
elif 'price' in key.lower() or 'dividend' in key.lower() or 'average' in key.lower():
value = f"{value:.2f}" # Format currency/prices
category_key_value_html += f"{key.replace('_', ' ').title()}
{value}
"
if category_key_value_html: # Only add category header and card if there is content in it
categorized_html += f"{category_name}
{category_key_value_html}
"
extra_sections = ""
if long_summary:
extra_sections += f"Business Summary
{long_summary}
"
if officers:
officer_rows = "".join(
f"| {o.get('name','')}"f" | {o.get('title','')}"f" | {o.get('age','')}"f" |
"
for o in officers
)
officer_table = f"| Name | Title | Age |
{officer_rows}
"
extra_sections += f"Company Officers
{officer_table}"
content_html = f"{categorized_html}{extra_sections}"
# Daily chart
elif req_type.lower() == "daily":
df = yf.download(yfsymbol, period="1y", interval="1d").round(2)
if df.empty:
content_html = f"No daily data for {symbol}
"
else:
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)
content_html = f"{chart_html}Recent Daily Data (last 30 rows)
{table_html}"
# Intraday chart
elif req_type.lower() == "intraday":
df = yf.download(yfsymbol, period="1d", interval="5m").round(2)
if df.empty:
content_html = f"No intraday data for {symbol}
"
else:
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)
content_html = f"{chart_html}Recent Intraday Data (last 50 rows)
{table_html}"
# Financial sections
elif req_type.lower() == "qresult":
df = ticker.quarterly_financials
content_html = f"Quarterly Results
{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
content_html = f"Annual Results
{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
content_html = f"Balance Sheet
{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
content_html = f"Cash Flow
{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No cashflow available
"
elif req_type.lower() == "dividend":
s = ticker.dividends
content_html = f"Dividend History
{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
content_html = f"Split History
{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
content_html = f"Earnings
{df.to_html(classes='styled-table', border=0)}" if not df.empty else "No earnings data available
"
else:
content_html = f"No handler for {req_type}
"
except Exception as e:
content_html = f"Error
{str(e)}
"
# Wrap the content_html in a complete HTML document structure
full_html_output = f"""
Stock Data for {symbol}
{STYLE_BLOCK}
{content_html}
"""
return full_html_output
iface = gr.Interface(
fn=fetch_data,
inputs=[
gr.Textbox(label="Stock Symbol", value="PNB"),
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)