Spaces:
Sleeping
Sleeping
import gradio as gr | |
import yfinance as yf | |
import pandas as pd | |
import numpy as np | |
import plotly.graph_objects as go | |
from transformers import pipeline | |
from datetime import datetime | |
import requests | |
from bs4 import BeautifulSoup | |
import feedparser | |
# ------------------- Initialize Models ------------------- | |
sentiment_analyzer = pipeline("text-classification", model="ProsusAI/finbert") | |
news_summarizer = pipeline("summarization", model="facebook/bart-large-cnn") | |
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ur-en") | |
# ------------------- Technical Analysis Functions ------------------- | |
def calculate_rsi(data, window=14): | |
delta = data['Close'].diff() | |
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean() | |
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean() | |
rs = gain / loss | |
return 100 - (100 / (1 + rs)) | |
def calculate_macd(data, slow=26, fast=12, signal=9): | |
exp1 = data['Close'].ewm(span=fast, adjust=False).mean() | |
exp2 = data['Close'].ewm(span=slow, adjust=False).mean() | |
macd = exp1 - exp2 | |
signal_line = macd.ewm(span=signal, adjust=False).mean() | |
return macd, signal_line | |
# ------------------- Data Fetching & Processing ------------------- | |
def get_psx_data(ticker): | |
try: | |
stock = yf.Ticker(f"{ticker}.KA") | |
data = stock.history(period="1y") | |
if data.empty: | |
return None, "Invalid ticker or no data available" | |
# Calculate indicators | |
data['RSI'] = calculate_rsi(data) | |
data['MACD'], data['Signal'] = calculate_macd(data) | |
data['MA50'] = data['Close'].rolling(window=50).mean() | |
data['MA200'] = data['Close'].rolling(window=200).mean() | |
return data, None | |
except Exception as e: | |
return None, str(e) | |
# ------------------- News & Sentiment Analysis ------------------- | |
def analyze_psx_news(): | |
news_items = [] | |
try: | |
feed = feedparser.parse("https://www.dawn.com/feeds/pakistan") | |
for entry in feed.entries[:5]: # Limit to 5 articles | |
try: | |
# Translate Urdu content to English | |
if any(char in entry.title for char in ['\u0600', '\u0800']): # Detect Urdu characters | |
translated = translator(entry.title)[0]['translation_text'] | |
title = f"[URDU] {translated}" | |
else: | |
title = entry.title | |
# Analyze sentiment | |
sentiment = sentiment_analyzer(title)[0] | |
news_items.append({ | |
'title': title, | |
'sentiment': sentiment['label'], | |
'score': sentiment['score'], | |
'link': entry.link | |
}) | |
except: | |
continue | |
except: | |
pass | |
return news_items | |
# ------------------- Gradio Interface ------------------- | |
def analyze_stock(ticker): | |
# Get stock data | |
data, error = get_psx_data(ticker) | |
if error: | |
return error, None, None, None | |
# Create price chart | |
fig = go.Figure() | |
fig.add_trace(go.Candlestick(x=data.index, | |
open=data['Open'], | |
high=data['High'], | |
low=data['Low'], | |
close=data['Close'], | |
name='Price')) | |
fig.add_trace(go.Scatter(x=data.index, y=data['MA50'], line=dict(color='orange', width=1), name='MA50')) | |
fig.add_trace(go.Scatter(x=data.index, y=data['MA200'], line=dict(color='blue', width=1), name='MA200')) | |
fig.update_layout(title=f"{ticker} Technical Analysis", xaxis_rangeslider_visible=False) | |
# Generate signals | |
latest = data.iloc[-1] | |
rsi_signal = "Oversold" if latest['RSI'] < 30 else "Overbought" if latest['RSI'] > 70 else "Neutral" | |
macd_signal = "Bullish" if latest['MACD'] > latest['Signal'] else "Bearish" | |
# News analysis | |
news = analyze_psx_news() | |
news_html = "<h3>Market News & Sentiment</h3>" | |
for item in news: | |
news_html += f""" | |
<div style="margin-bottom: 15px; padding: 10px; border: 1px solid #eee; border-radius: 5px;"> | |
<b>{item['title']}</b><br> | |
Sentiment: {item['sentiment']} ({item['score']:.2f})<br> | |
<a href="{item['link']}" target="_blank" style="color: #007bff;">Read more</a> | |
</div> | |
""" | |
# Generate recommendation | |
recommendation = f""" | |
<div style="padding: 20px; background: {'#d4edda' if macd_signal == 'Bullish' else '#f8d7da'}; border-radius: 5px;"> | |
<h4>Recommendation for {ticker}</h4> | |
<p>RSI: {latest['RSI']:.2f} ({rsi_signal})</p> | |
<p>MACD: {macd_signal}</p> | |
<p>50-Day MA: {latest['MA50']:.2f}</p> | |
<p>200-Day MA: {latest['MA200']:.2f}</p> | |
<h4 style="color: {'green' if macd_signal == 'Bullish' else 'red'};">{'Consider Buying' if macd_signal == 'Bullish' else 'Consider Selling'}</h4> | |
</div> | |
""" | |
return recommendation, fig.to_html(), news_html | |
# ------------------- App Configuration ------------------- | |
iface = gr.Interface( | |
fn=analyze_stock, | |
inputs=gr.Textbox(label="Enter PSX Ticker (e.g., HBL, LUCK, OGDC)"), | |
outputs=[ | |
gr.HTML(label="Recommendation"), | |
gr.HTML(label="Technical Analysis"), | |
gr.HTML(label="Market News") | |
], | |
title="π PSX Smart Trading Assistant", | |
description="Real-time Pakistan Stock Exchange Analysis with AI-powered Insights", | |
examples=[["HBL"], ["LUCK"], ["OGDC"]], | |
allow_flagging="never", | |
theme=gr.themes.Soft() | |
) | |
if __name__ == "__main__": | |
iface.launch(server_name="0.0.0.0", server_port=7860) |