Safwanahmad619 commited on
Commit
aa14fca
Β·
verified Β·
1 Parent(s): fee2f77

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -77
app.py CHANGED
@@ -1,114 +1,145 @@
1
  import gradio as gr
2
  import yfinance as yf
3
  import pandas as pd
 
4
  import plotly.graph_objects as go
5
  from transformers import pipeline
6
- from datetime import datetime, timedelta
7
  import requests
8
  from bs4 import BeautifulSoup
9
  import feedparser
10
 
11
- # ------------------- Hugging Face Models -------------------
12
  sentiment_analyzer = pipeline("text-classification", model="ProsusAI/finbert")
13
  news_summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
14
- ner_model = pipeline("ner", model="dslim/bert-base-NER")
15
  translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ur-en")
16
 
17
- # ------------------- Technical Analysis -------------------
18
  def calculate_rsi(data, window=14):
19
  delta = data['Close'].diff()
20
  gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
21
  loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
22
  rs = gain / loss
23
- rsi = 100 - (100 / (1 + rs))
24
- return rsi
25
 
26
- # ------------------- Fetch PSX Data -------------------
27
- def get_stock_data(ticker, period="1y"):
 
 
 
 
 
 
 
28
  try:
29
- stock = yf.Ticker(f"{ticker}.KAR")
30
- data = stock.history(period=period)
31
  if data.empty:
32
- return None, "Error: Ticker not found or no data."
 
 
33
  data['RSI'] = calculate_rsi(data)
 
 
 
 
34
  return data, None
35
  except Exception as e:
36
- return None, f"Error: {str(e)}"
37
-
38
- # ------------------- Sentiment & News Analysis -------------------
39
- def analyze_sentiment(text):
40
- return sentiment_analyzer(text)[0]['label']
41
-
42
- def summarize_news(url):
43
- response = requests.get(url)
44
- soup = BeautifulSoup(response.text, 'html.parser')
45
- paragraphs = soup.find_all('p')
46
- article = ' '.join([p.get_text() for p in paragraphs[:5]])
47
- summary = news_summarizer(article, max_length=100, min_length=30)[0]['summary_text']
48
- return summary
49
 
50
- def get_geo_news():
51
- feed = feedparser.parse("https://www.dawn.com/feeds/pakistan")
52
- news = []
53
- for entry in feed.entries[:3]:
54
- summary = summarize_news(entry.link)
55
- sentiment = analyze_sentiment(entry.title)
56
- news.append({"title": entry.title, "summary": summary, "sentiment": sentiment})
57
- return news
58
-
59
- # ------------------- Generate Signal -------------------
60
- def generate_signal(rsi, sentiment_score, news_score):
61
- if rsi < 30 and sentiment_score > 0.5 and news_score > 0.5:
62
- return "STRONG BUY 🟒"
63
- elif rsi > 70 or sentiment_score < -0.5:
64
- return "STRONG SELL πŸ”΄"
65
- else:
66
- return "HOLD 🟑"
 
 
 
 
 
 
 
 
 
 
67
 
68
  # ------------------- Gradio Interface -------------------
69
  def analyze_stock(ticker):
70
- # Fetch Data
71
- data, error = get_stock_data(ticker)
72
  if error:
73
- return error, None, None
74
-
75
- # Technical Analysis
76
- latest_rsi = data['RSI'].iloc[-1]
77
-
78
- # Sentiment & News Analysis
79
- news = get_geo_news()
80
- sentiment_scores = [1 if n['sentiment'] == 'positive' else -1 for n in news]
81
- sentiment_score = sum(sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0
82
-
83
- # Generate Signal
84
- signal = generate_signal(latest_rsi, sentiment_score, 0.5)
85
-
86
- # Plot
87
- fig = go.Figure(data=[go.Candlestick(x=data.index,
88
- open=data['Open'], high=data['High'],
89
- low=data['Low'], close=data['Close'])])
90
- fig.update_layout(title=f"{ticker} Price Chart")
91
-
92
- # News Summary
93
- news_html = "<h3>Latest Geopolitical News:</h3>"
94
- for n in news:
95
- news_html += f"<p><b>{n['title']}</b> ({n['sentiment']})<br>{n['summary']}</p>"
96
-
97
- return signal, fig.to_html(), news_html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
- # ------------------- Launch Gradio App -------------------
100
  iface = gr.Interface(
101
  fn=analyze_stock,
102
- inputs=gr.Textbox(label="Enter PSX Stock Ticker (e.g., HBL, LUCK)"),
103
  outputs=[
104
- gr.Textbox(label="Recommendation"),
105
- gr.HTML(label="Price Chart"),
106
- gr.HTML(label="News Analysis")
107
  ],
108
- title="🟒 PSX Stock Analysis Chatbot πŸ”΄",
109
- description="Real-time Technical, Sentiment, and News Analysis for Pakistan Stock Exchange",
110
- allow_flagging="never"
 
 
111
  )
112
 
113
  if __name__ == "__main__":
114
- iface.launch(share=True) # Set share=True for public URL
 
1
  import gradio as gr
2
  import yfinance as yf
3
  import pandas as pd
4
+ import numpy as np
5
  import plotly.graph_objects as go
6
  from transformers import pipeline
7
+ from datetime import datetime
8
  import requests
9
  from bs4 import BeautifulSoup
10
  import feedparser
11
 
12
+ # ------------------- Initialize Models -------------------
13
  sentiment_analyzer = pipeline("text-classification", model="ProsusAI/finbert")
14
  news_summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
 
15
  translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ur-en")
16
 
17
+ # ------------------- Technical Analysis Functions -------------------
18
  def calculate_rsi(data, window=14):
19
  delta = data['Close'].diff()
20
  gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
21
  loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
22
  rs = gain / loss
23
+ return 100 - (100 / (1 + rs))
 
24
 
25
+ def calculate_macd(data, slow=26, fast=12, signal=9):
26
+ exp1 = data['Close'].ewm(span=fast, adjust=False).mean()
27
+ exp2 = data['Close'].ewm(span=slow, adjust=False).mean()
28
+ macd = exp1 - exp2
29
+ signal_line = macd.ewm(span=signal, adjust=False).mean()
30
+ return macd, signal_line
31
+
32
+ # ------------------- Data Fetching & Processing -------------------
33
+ def get_psx_data(ticker):
34
  try:
35
+ stock = yf.Ticker(f"{ticker}.KA")
36
+ data = stock.history(period="1y")
37
  if data.empty:
38
+ return None, "Invalid ticker or no data available"
39
+
40
+ # Calculate indicators
41
  data['RSI'] = calculate_rsi(data)
42
+ data['MACD'], data['Signal'] = calculate_macd(data)
43
+ data['MA50'] = data['Close'].rolling(window=50).mean()
44
+ data['MA200'] = data['Close'].rolling(window=200).mean()
45
+
46
  return data, None
47
  except Exception as e:
48
+ return None, str(e)
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ # ------------------- News & Sentiment Analysis -------------------
51
+ def analyze_psx_news():
52
+ news_items = []
53
+ try:
54
+ feed = feedparser.parse("https://www.dawn.com/feeds/pakistan")
55
+ for entry in feed.entries[:5]: # Limit to 5 articles
56
+ try:
57
+ # Translate Urdu content to English
58
+ if any(char in entry.title for char in ['\u0600', '\u0800']): # Detect Urdu characters
59
+ translated = translator(entry.title)[0]['translation_text']
60
+ title = f"[URDU] {translated}"
61
+ else:
62
+ title = entry.title
63
+
64
+ # Analyze sentiment
65
+ sentiment = sentiment_analyzer(title)[0]
66
+ news_items.append({
67
+ 'title': title,
68
+ 'sentiment': sentiment['label'],
69
+ 'score': sentiment['score'],
70
+ 'link': entry.link
71
+ })
72
+ except:
73
+ continue
74
+ except:
75
+ pass
76
+ return news_items
77
 
78
  # ------------------- Gradio Interface -------------------
79
  def analyze_stock(ticker):
80
+ # Get stock data
81
+ data, error = get_psx_data(ticker)
82
  if error:
83
+ return error, None, None, None
84
+
85
+ # Create price chart
86
+ fig = go.Figure()
87
+ fig.add_trace(go.Candlestick(x=data.index,
88
+ open=data['Open'],
89
+ high=data['High'],
90
+ low=data['Low'],
91
+ close=data['Close'],
92
+ name='Price'))
93
+ fig.add_trace(go.Scatter(x=data.index, y=data['MA50'], line=dict(color='orange', width=1), name='MA50'))
94
+ fig.add_trace(go.Scatter(x=data.index, y=data['MA200'], line=dict(color='blue', width=1), name='MA200'))
95
+ fig.update_layout(title=f"{ticker} Technical Analysis", xaxis_rangeslider_visible=False)
96
+
97
+ # Generate signals
98
+ latest = data.iloc[-1]
99
+ rsi_signal = "Oversold" if latest['RSI'] < 30 else "Overbought" if latest['RSI'] > 70 else "Neutral"
100
+ macd_signal = "Bullish" if latest['MACD'] > latest['Signal'] else "Bearish"
101
+
102
+ # News analysis
103
+ news = analyze_psx_news()
104
+ news_html = "<h3>Market News & Sentiment</h3>"
105
+ for item in news:
106
+ news_html += f"""
107
+ <div style="margin-bottom: 15px; padding: 10px; border: 1px solid #eee; border-radius: 5px;">
108
+ <b>{item['title']}</b><br>
109
+ Sentiment: {item['sentiment']} ({item['score']:.2f})<br>
110
+ <a href="{item['link']}" target="_blank" style="color: #007bff;">Read more</a>
111
+ </div>
112
+ """
113
+
114
+ # Generate recommendation
115
+ recommendation = f"""
116
+ <div style="padding: 20px; background: {'#d4edda' if macd_signal == 'Bullish' else '#f8d7da'}; border-radius: 5px;">
117
+ <h4>Recommendation for {ticker}</h4>
118
+ <p>RSI: {latest['RSI']:.2f} ({rsi_signal})</p>
119
+ <p>MACD: {macd_signal}</p>
120
+ <p>50-Day MA: {latest['MA50']:.2f}</p>
121
+ <p>200-Day MA: {latest['MA200']:.2f}</p>
122
+ <h4 style="color: {'green' if macd_signal == 'Bullish' else 'red'};">{'Consider Buying' if macd_signal == 'Bullish' else 'Consider Selling'}</h4>
123
+ </div>
124
+ """
125
+
126
+ return recommendation, fig.to_html(), news_html
127
 
128
+ # ------------------- App Configuration -------------------
129
  iface = gr.Interface(
130
  fn=analyze_stock,
131
+ inputs=gr.Textbox(label="Enter PSX Ticker (e.g., HBL, LUCK, OGDC)"),
132
  outputs=[
133
+ gr.HTML(label="Recommendation"),
134
+ gr.HTML(label="Technical Analysis"),
135
+ gr.HTML(label="Market News")
136
  ],
137
+ title="πŸš€ PSX Smart Trading Assistant",
138
+ description="Real-time Pakistan Stock Exchange Analysis with AI-powered Insights",
139
+ examples=[["HBL"], ["LUCK"], ["OGDC"]],
140
+ allow_flagging="never",
141
+ theme=gr.themes.Soft()
142
  )
143
 
144
  if __name__ == "__main__":
145
+ iface.launch(server_name="0.0.0.0", server_port=7860)