From 25b543b47d30b177ad9965f6429e82a8ab6424b9 Mon Sep 17 00:00:00 2001 From: addychai355-create Date: Tue, 12 May 2026 22:15:30 +0800 Subject: [PATCH] Add XAU/USD clean signal monitor (xau_monitor.py) --- dashboard/xau_monitor.py | 205 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 dashboard/xau_monitor.py diff --git a/dashboard/xau_monitor.py b/dashboard/xau_monitor.py new file mode 100644 index 0000000..b5d0965 --- /dev/null +++ b/dashboard/xau_monitor.py @@ -0,0 +1,205 @@ +""" +XAU/USD Gold Signals โ€” Clean Monitor +Shows: current signal, entry, SL, TP. Nothing else. +""" +import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parent.parent)) + +import warnings +warnings.filterwarnings("ignore") + +import streamlit as st +import pandas as pd +import numpy as np +import yfinance as yf +from datetime import datetime, timezone + +st.set_page_config(page_title="XAU Signals", page_icon="๐Ÿฅ‡", layout="centered") + +# Hide streamlit branding +st.markdown(""" + +""", unsafe_allow_html=True) + +# โ”€โ”€โ”€ Import strategy โ”€โ”€โ”€ +from strategies.xau_scalp import add_indicators_xau, generate_signals_xau, calculate_performance_xau + +# โ”€โ”€โ”€ Fetch XAU/USD data directly โ”€โ”€โ”€ +def fetch_gold(tf="5m", days=3): + raw = yf.download("GC=F", period=f"{max(1,days)}d", interval=tf, progress=False) + if raw is None or raw.empty: + return None + if isinstance(raw.columns, pd.MultiIndex): + raw.columns = raw.columns.get_level_values(0) + df = raw.reset_index() + df.columns = [c.lower().strip() for c in df.columns] + m = {"datetime":"time","date":"time","open":"open","high":"high","low":"low","close":"close","volume":"volume"} + df = df.rename(columns={k:v for k,v in m.items() if k in df.columns}) + df["time"] = pd.to_datetime(df["time"]) + return df.sort_values("time").reset_index(drop=True) + +def format_price(v): + return f"${v:,.2f}" if v == v else "โ€”" + +# โ”€โ”€โ”€ Load & compute โ”€โ”€โ”€ +df = fetch_gold("5m", 3) +if df is None or len(df) < 60: + st.error("Failed to load XAU/USD data. Try again in a minute.") + st.stop() + +df = add_indicators_xau(df) +df = generate_signals_xau(df, mom_threshold=0.55, atr_sl_mult=1.2, atr_tp_mult=2.0, max_hold_bars=4) + +latest = df.iloc[-1] +pos = latest.get("position", 0) +price = latest["close"] +rsi_val = latest.get("rsi", 50) +atr_val = latest.get("atr_pct", 0) + +# โ”€โ”€โ”€ Find latest signal โ”€โ”€โ”€ +signals = df[df["signal"] != 0] +last_signal = signals.iloc[-1] if not signals.empty else None + +# Also look at last 5 for history +recent_signals = signals.tail(10) if not signals.empty else pd.DataFrame() + +# โ”€โ”€โ”€ UI โ”€โ”€โ”€ +cols = st.columns([1, 2, 1]) +with cols[1]: + st.markdown(f"

๐Ÿฅ‡ XAU/USD

", unsafe_allow_html=True) + st.markdown(f"

{datetime.now(timezone.utc).strftime('%H:%M UTC')}

", unsafe_allow_html=True) + +# โ”€โ”€โ”€ Current Price โ”€โ”€โ”€ +st.markdown(f"

{format_price(price)}

", unsafe_allow_html=True) + +# โ”€โ”€โ”€ Signal Badge โ”€โ”€โ”€ +if pos == 1: + signal_color = "#00C853" + signal_text = "๐ŸŸข BUY" + signal_bg = "#003D1A" +elif pos == -1: + signal_color = "#FF1744" + signal_text = "๐Ÿ”ด SHORT" + signal_bg = "#3D0010" +else: + signal_color = "#757575" + signal_text = "โšช WAIT" + signal_bg = "#1A1A1A" + +st.markdown(f""" +
+ {signal_text} +
+""", unsafe_allow_html=True) + +# โ”€โ”€โ”€ SL / TP โ”€โ”€โ”€ +if last_signal is not None: + entry_px = last_signal["close"] + sl_px = last_signal.get("sl_price", np.nan) + tp_px = last_signal.get("tp_price", np.nan) + + pos2 = last_signal.get("position", last_signal.get("signal", 0)) + if pos2 == 0: + pos2 = last_signal["signal"] + + if pos2 == 1: + sl_label = "๐Ÿ›‘ Stop Loss" + tp_label = "๐ŸŽฏ Take Profit" + sl_color = "#FF5252" + tp_color = "#69F0AE" + elif pos2 == -1: + sl_label = "๐Ÿ›‘ Stop Loss" + tp_label = "๐ŸŽฏ Take Profit" + sl_color = "#FF5252" + tp_color = "#69F0AE" + else: + sl_label = "SL" + tp_label = "TP" + sl_color = "#757575" + tp_color = "#757575" + + col_sl, col_tp = st.columns(2) + with col_sl: + sl_val = format_price(sl_px) if sl_px == sl_px else "โ€”" + st.markdown(f""" +
+
{sl_label}
+
{sl_val}
+
+ """, unsafe_allow_html=True) + with col_tp: + tp_val = format_price(tp_px) if tp_px == tp_px else "โ€”" + if pos2 == 1: + diff_px = tp_px - entry_px + diff_pct = diff_px / entry_px * 100 + tp_detail = f"+${diff_px:.2f} (+{diff_pct:.2f}%)" if diff_px == diff_px else "" + elif pos2 == -1: + diff_px = entry_px - tp_px + diff_pct = diff_px / entry_px * 100 + tp_detail = f"+${diff_px:.2f} (+{diff_pct:.2f}%)" if diff_px == diff_px else "" + else: + tp_detail = "" + st.markdown(f""" +
+
{tp_label}
+
{tp_val}
+
{tp_detail}
+
+ """, unsafe_allow_html=True) + +else: + st.markdown(f""" +
+ No active signal. Waiting for setup conditions... +
+ """, unsafe_allow_html=True) + +# โ”€โ”€โ”€ Context row โ”€โ”€โ”€ +st.markdown("---") +col_rsi, col_atr, col_vol = st.columns(3) +with col_rsi: + rsi_c = "#00C853" if 40 <= rsi_val <= 60 else "#FF5252" + st.markdown(f"
RSI
{rsi_val:.1f}
", unsafe_allow_html=True) +with col_atr: + st.markdown(f"
ATR%
{atr_val:.3f}%
", unsafe_allow_html=True) +with col_vol: + vol = latest.get("volume", 0) + st.markdown(f"
Volume
{int(vol):,}
", unsafe_allow_html=True) + +# โ”€โ”€โ”€ Mini Price Line โ”€โ”€โ”€ +st.markdown("---") +st.markdown("

Price (last 50 candles)

", unsafe_allow_html=True) + +chart_data = df[["time", "close"]].tail(50).copy() +chart_data.columns = ["t", "price"] +st.line_chart(chart_data.set_index("t"), height=150, color="#FFD600") + +# โ”€โ”€โ”€ Recent Signal History โ”€โ”€โ”€ +if not recent_signals.empty: + st.markdown("---") + st.markdown("

Recent Signals

", unsafe_allow_html=True) + + hist = recent_signals[["time", "close", "signal", "exit_reason"]].copy() + hist["time"] = hist["time"].dt.strftime("%H:%M") + hist["signal"] = hist["signal"].map({1: "๐ŸŸข BUY", -1: "๐Ÿ”ด SELL"}) + hist = hist.rename(columns={"time": "T", "close": "Price", "signal": "Sig", "exit_reason": "Exit"}) + hist["Exit"] = hist["Exit"].replace("", "โ€”") + st.dataframe(hist, use_container_width=True, hide_index=True, height=200) +else: + st.markdown("---") + st.markdown("

No signals generated in recent data.

", unsafe_allow_html=True) + +# โ”€โ”€โ”€ Footer โ”€โ”€โ”€ +st.markdown("---") +st.markdown("

Auto-refresh every 60s ยท Data: Yahoo Finance GC=F

", unsafe_allow_html=True) + +# Auto-refresh +st.rerun(60)