jasimali75's picture
Fix secrets error - use env var
5df980b verified
"""
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("""
<style>
.main-title { font-size: 2.5rem; font-weight: bold; color: #FFD700; text-align: center; }
.signal-box { background: #1a1a1a; border-radius: 15px; padding: 25px; margin: 10px 0; }
.prob-big { font-size: 4rem; font-weight: bold; text-align: center; }
.buy-signal { color: #00E676; }
.sell-signal { color: #FF5252; }
.wait-signal { color: #FFD740; }
</style>
""", unsafe_allow_html=True)
st.markdown('<h1 class="main-title">πŸ“ˆ PRO TRADING SIGNALS</h1>', unsafe_allow_html=True)
st.markdown('<p style="text-align:center;color:#888;">Live Finnhub Data β€’ Futures & Forex</p>', 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"""
<div class="signal-box">
<h2 class="{color_class}" style="text-align:center;">{action}</h2>
<h1 class="prob-big {color_class}">{prob}%</h1>
<p style="text-align:center;color:#888;">WIN PROBABILITY β€’ {fetch_time}s</p>
<hr style="border-color:#333;">
<div style="display:flex;justify-content:space-around;text-align:center;">
<div>
<p style="color:#888;">CURRENT PRICE</p>
<h3>${price:.2f}</h3>
</div>
<div>
<p style="color:#00E676;">TAKE PROFIT</p>
<h3>${tp:.2f}</h3>
</div>
<div>
<p style="color:#FF5252;">STOP LOSS</p>
<h3>${sl:.2f}</h3>
</div>
</div>
<hr style="border-color:#333;">
<h4 style="color:#FFD700;">πŸ“Š TECHNICAL ANALYSIS</h4>
<p style="font-family:monospace;color:#ccc;">{chr(10).join(reasons)}</p>
<p style="color:#888;text-align:center;">{selected_pair} β€’ {selected_tf} β€’ {datetime.now().strftime('%H:%M:%S')}</p>
</div>
""", unsafe_allow_html=True)
except Exception as e:
st.error(f"Error: {str(e)}")
st.markdown("---")
st.markdown('<p style="text-align:center;color:#555;font-size:12px;">Pro Trading Signals β€’ Powered by Finnhub</p>', unsafe_allow_html=True)