""" Pro Trading Signals - Finnhub Live Data Version """ import streamlit as st import pandas as pd import requests from datetime import datetime import time FINNHUB_API_KEY = "demo" try: import os FINNHUB_API_KEY = os.environ.get("FINNHUB_API_KEY", "demo") except: pass st.set_page_config( page_title="Pro Trading Signals", page_icon="📈", layout="centered", initial_sidebar_state="collapsed" ) st.markdown(""" """, unsafe_allow_html=True) st.markdown('
Live Finnhub Data • Futures & Forex
', unsafe_allow_html=True) SYMBOL_MAP = { "🥇 Gold (XAU/USD)": {"symbol": "XAUUSD", "type": "forex"}, "🥈 Silver (XAG/USD)": {"symbol": "XAGUSD", "type": "forex"}, "🛢️ Crude Oil (CL)": {"symbol": "CL", "type": "commodity"}, "⛽ Natural Gas (NG)": {"symbol": "NG", "type": "commodity"}, "🌽 Corn (ZC)": {"symbol": "ZC", "type": "commodity"}, "🌾 Wheat (ZW)": {"symbol": "ZW", "type": "commodity"}, "EUR/USD": {"symbol": "EURUSD", "type": "forex"}, "GBP/USD": {"symbol": "GBPUSD", "type": "forex"}, "USD/JPY": {"symbol": "USDJPY", "type": "forex"}, "USD/CHF": {"symbol": "USDCHF", "type": "forex"}, "AUD/USD": {"symbol": "AUDUSD", "type": "forex"}, "USD/CAD": {"symbol": "USDCAD", "type": "forex"}, "BTC/USD": {"symbol": "BTC-USD", "type": "crypto"}, "ETH/USD": {"symbol": "ETH-USD", "type": "crypto"}, "AAPL": {"symbol": "AAPL", "type": "stock"}, "TSLA": {"symbol": "TSLA", "type": "stock"}, "NVDA": {"symbol": "NVDA", "type": "stock"}, } TIMEFRAMES = { "1 Min": {"resolution": "1", "days": 1}, "5 Min": {"resolution": "5", "days": 5}, "15 Min": {"resolution": "15", "days": 5}, "30 Min": {"resolution": "30", "days": 10}, "1 Hour": {"resolution": "60", "days": 30}, "4 Hour": {"resolution": "240", "days": 60}, "Daily": {"resolution": "D", "days": 180}, } def get_finnhub_price(symbol: str) -> float: try: url = f"https://finnhub.io/api/v1/quote?symbol={symbol}&token={FINNHUB_API_KEY}" r = requests.get(url, timeout=5) data = r.json() if data.get('c'): return data['c'] except: pass return None def get_finnhub_candle(symbol: str, resolution: str, days: int) -> pd.DataFrame: try: to_time = int(datetime.now().timestamp()) from_time = to_time - (days * 24 * 60 * 60) url = f"https://finnhub.io/api/v1/stock/candle?symbol={symbol}&resolution={resolution}&from={from_time}&to={to_time}&token={FINNHUB_API_KEY}" r = requests.get(url, timeout=10) data = r.json() if data.get('s') == 'ok': df = pd.DataFrame({ 'Open': data['o'], 'High': data['h'], 'Low': data['l'], 'Close': data['c'], 'Volume': data['v'] }, index=pd.to_datetime(data['t'], unit='s')) return df except Exception as e: pass return pd.DataFrame() col1, col2, col3 = st.columns([2, 2, 1]) with col1: selected_pair = st.selectbox("📊 Asset", list(SYMBOL_MAP.keys()), label_visibility="collapsed") with col2: selected_tf = st.selectbox("⏱ Timeframe", list(TIMEFRAMES.keys()), label_visibility="collapsed") with col3: st.write("") analyze_btn = st.button("⚡ ANALYZE", use_container_width=True) if analyze_btn: with st.spinner("📡 Fetching Finnhub live data..."): try: start_time = time.time() asset = SYMBOL_MAP[selected_pair] symbol = asset["symbol"] tf = TIMEFRAMES[selected_tf] price = get_finnhub_price(symbol) df = get_finnhub_candle(symbol, tf["resolution"], tf["days"]) if df.empty or len(df) < 20: st.error("❌ No data. Try different asset or check API key.") else: close = df['Close'] df['sma9'] = close.rolling(9).mean() df['sma21'] = close.rolling(21).mean() df['sma50'] = close.rolling(50).mean() df['ema8'] = close.ewm(span=8, adjust=False).mean() df['ema21'] = close.ewm(span=21, adjust=False).mean() delta = close.diff() gain = delta.clip(lower=0) loss = (-delta).clip(lower=0) avg_gain = gain.ewm(alpha=1/14, adjust=False).mean() avg_loss = loss.ewm(alpha=1/14, adjust=False).mean() rs = avg_gain / loss.replace(0, 1e-12) df['rsi'] = 100 - (100 / (1 + rs)) ema12 = close.ewm(span=12, adjust=False).mean() ema26 = close.ewm(span=26, adjust=False).mean() df['macd'] = ema12 - ema26 df['macd_signal'] = df['macd'].ewm(span=9, adjust=False).mean() df['macd_hist'] = df['macd'] - df['macd_signal'] high = df['High'] low = df['Low'] prev_close = close.shift(1) tr = pd.concat([high - low, (high - prev_close).abs(), (low - prev_close).abs()], axis=1).max(axis=1) df['atr'] = tr.ewm(alpha=1/14, adjust=False).mean() up_move = high.diff() down_move = -low.diff() plus_dm = ((up_move > down_move) & (up_move > 0)) * up_move minus_dm = ((down_move > up_move) & (down_move > 0)) * down_move tr_s = tr.ewm(alpha=1/14, adjust=False).mean() p_dm_s = plus_dm.ewm(alpha=1/14, adjust=False).mean() m_dm_s = minus_dm.ewm(alpha=1/14, adjust=False).mean() tr_safe = tr_s.replace(0, 1e-12) df['plus_di'] = 100 * (p_dm_s / tr_safe) df['minus_di'] = 100 * (m_dm_s / tr_safe) di_sum = (df['plus_di'] + df['minus_di']).replace(0, 1e-12) dx = 100 * (df['plus_di'] - df['minus_di']).abs() / di_sum df['adx'] = dx.ewm(alpha=1/14, adjust=False).mean() last = df.iloc[-1] price = float(last['Close']) if not price else price atr = float(last['atr']) score_buy = 0 score_sell = 0 reasons = [] if price > last['sma50']: score_buy += 1 reasons.append("✓ Price > SMA50") else: score_sell += 1 reasons.append("✗ Price < SMA50") if last['sma21'] > last['sma50']: score_buy += 1 reasons.append("✓ SMA21 > SMA50") else: score_sell += 1 reasons.append("✗ SMA21 < SMA50") if last['ema8'] > last['ema21']: score_buy += 1 reasons.append("✓ EMA8 > EMA21") else: score_sell += 1 reasons.append("✗ EMA8 < EMA21") if last['macd'] > last['macd_signal']: score_buy += 1 reasons.append("✓ MACD bullish") else: score_sell += 1 reasons.append("✗ MACD bearish") if last['macd_hist'] > 0: score_buy += 1 reasons.append("✓ MACD histogram +") else: score_sell += 1 reasons.append("✗ MACD histogram -") rsi = last['rsi'] if 50 < rsi < 70: score_buy += 1 reasons.append(f"✓ RSI healthy ({rsi:.0f})") elif 30 < rsi < 50: score_sell += 1 reasons.append(f"✗ RSI weak ({rsi:.0f})") elif rsi >= 70: score_sell += 1 reasons.append(f"⚠ RSI overbought") elif rsi <= 30: score_buy += 1 reasons.append(f"✓ RSI oversold") adx = last['adx'] if adx > 20: if last['plus_di'] > last['minus_di']: score_buy += 2 reasons.append(f"✓ Strong uptrend (ADX:{adx:.0f})") else: score_sell += 2 reasons.append(f"✗ Strong downtrend (ADX:{adx:.0f})") else: reasons.append(f"○ Ranging market") if score_buy >= 5: prob = min(95, 55 + (score_buy * 7)) action = "🟢 BUY" color_class = "buy-signal" tp = round(price + (atr * 2), 2) sl = round(price - (atr * 1), 2) elif score_sell >= 5: prob = min(95, 55 + (score_sell * 7)) action = "🔴 SELL" color_class = "sell-signal" tp = round(price - (atr * 2), 2) sl = round(price + (atr * 1), 2) else: prob = max(40, 50 + (score_buy - score_sell) * 5) action = "🟡 WAIT" color_class = "wait-signal" tp = sl = round(price, 2) fetch_time = round(time.time() - start_time, 2) st.markdown(f"""WIN PROBABILITY • {fetch_time}s
CURRENT PRICE
TAKE PROFIT
STOP LOSS
{chr(10).join(reasons)}
{selected_pair} • {selected_tf} • {datetime.now().strftime('%H:%M:%S')}
Pro Trading Signals • Powered by Finnhub
', unsafe_allow_html=True)