print("Loading commodities.ui ...")
import logging
from datetime import datetime
import plotly.express as px
import plotly.graph_objects as go
import streamlit as st
from commodities.logic import build_commodities_frame
from utils.db import log_audit, register_scan, save_scan_results
logger = logging.getLogger(__name__)
# ─────────────────────────────────────────────
# Colour mapping for conviction labels
# ─────────────────────────────────────────────
LABEL_COLOR = {
"STRONG BUY": "#00c853",
"BUY": "#64dd17",
"HOLD": "#ffd600",
"UNDERPERFORMER":"#ff6d00",
"AVOID": "#d50000",
}
DISPLAY_COLS = [
"Conviction Emoji", "Commodity", "Conviction Score", "Conviction Label",
"Price (₹)", "Trend", "ATR Regime", "1M Return %", "3M Return %",
"Spread %", "USDINR",
]
def _scorecard(row: dict):
"""Render a single commodity conviction card."""
label = row.get("Conviction Label", "HOLD")
emoji = row.get("Conviction Emoji", "🟡")
score = row.get("Conviction Score", 50)
color = LABEL_COLOR.get(label, "#ffd600")
decision = row.get("Decision", "")
st.markdown(
f"""
{emoji} {row.get('Commodity','—')}
{label} • {score}/100
{decision}
Price
₹ {row.get("Price (₹)", 0):,.2f}
Trend
{row.get("Trend","—")}
1M Return
{row.get("1M Return %",0):+.2f}%
ATR Regime
{row.get("ATR Regime","—")}
Spread
{row.get("Spread %",0):+.2f}%
USDINR
{row.get("USDINR",84.0):.2f}
""",
unsafe_allow_html=True,
)
def render(broker_choice="Zerodha"):
st.header("🌍 Commodities Intelligence Terminal")
commodity = st.sidebar.selectbox("Commodity", ["All", "Gold", "Silver", "Crude", "Copper"])
debug_mode = st.sidebar.toggle("Commodities Debug Mode", value=False)
# ── Load data ────────────────────────────────────────────────────────
try:
with st.spinner("Loading commodities data…"):
df = build_commodities_frame(None if commodity == "All" else commodity)
except Exception as e:
logger.error(f"commodities error: {e}")
st.warning("Data load failed — retry or check logs")
return
if df.empty:
st.warning("No commodity data available right now.")
return
# ── Conviction summary bar ────────────────────────────────────────────
st.subheader("📊 Conviction Summary")
if "Conviction Score" in df.columns:
summary_cols = st.columns(len(df))
for i, (_, row) in enumerate(df.iterrows()):
with summary_cols[i]:
score = row.get("Conviction Score", 50)
label = row.get("Conviction Label", "HOLD")
emoji = row.get("Conviction Emoji", "🟡")
color = LABEL_COLOR.get(label, "#ffd600")
st.markdown(
f"""
{emoji}
{row.get('Commodity','—')}
{score}
{label}
""",
unsafe_allow_html=True,
)
st.markdown("---")
# ── Conviction cards ─────────────────────────────────────────────────
st.subheader("🎯 Decision Cards")
for _, row in df.iterrows():
_scorecard(row.to_dict())
st.markdown("---")
# ── Data table ───────────────────────────────────────────────────────
with st.expander("📋 Full Data Table", expanded=False):
show_cols = [c for c in DISPLAY_COLS if c in df.columns]
st.dataframe(df[show_cols], use_container_width=True, hide_index=True)
# ── Heatmap ────────────────────────────────────────────────────────
with st.expander("🔥 Conviction & Spread Heatmap", expanded=False):
heat_data = df.set_index("Commodity")[["Conviction Score", "Spread %", "1M Return %", "3M Return %"]]
heat = px.imshow(
heat_data.T,
aspect="auto",
color_continuous_scale="RdYlGn",
title="Commodity Intelligence Heatmap",
labels={"color": "Value"},
)
heat.update_xaxes(tickvals=list(range(len(df))), ticktext=df["Commodity"].tolist())
st.plotly_chart(heat, use_container_width=True)
# ── Price Momentum Chart ──────────────────────────────────────────────
with st.expander("📈 Return Comparison", expanded=False):
ret_cols = [c for c in ["1M Return %", "3M Return %", "6M Return %"] if c in df.columns]
if ret_cols:
fig = go.Figure()
for col in ret_cols:
fig.add_trace(go.Bar(name=col, x=df["Commodity"], y=df[col]))
fig.update_layout(
barmode="group",
title="Return Comparison across Time Horizons",
template="plotly_dark",
legend=dict(orientation="h", y=1.1),
)
st.plotly_chart(fig, use_container_width=True)
# ── Export ────────────────────────────────────────────────────────────
st.download_button(
"⬇️ Export Commodities CSV",
df.to_csv(index=False).encode("utf-8"),
f"commodities_{datetime.now().strftime('%Y%m%d')}.csv",
"text/csv",
)
# ── Save to DB ────────────────────────────────────────────────────────
try:
scan_id = register_scan(
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
universe="Commodities", scan_type="COMMODITY", status="Completed",
)
save_scan_results(scan_id, df)
log_audit("Commodity scan", "Commodities", f"Rows logged: {len(df)}")
except Exception as e:
logger.error(f"commodities DB error: {e}")
if debug_mode:
st.markdown("### 🔍 Debug — Raw DataFrame")
st.dataframe(df, use_container_width=True)