Spaces:
Sleeping
Sleeping
Create market_stock_sentiment.py
Browse files- core/market_stock_sentiment.py +109 -0
core/market_stock_sentiment.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
from datetime import datetime, timedelta
|
4 |
+
from tradingview_ta import TA_Handler, Interval
|
5 |
+
from langchain.document_loaders import WebBaseLoader
|
6 |
+
from langchain.docstore.document import Document
|
7 |
+
from bs4 import BeautifulSoup
|
8 |
+
from GoogleNews import GoogleNews
|
9 |
+
from langchain.prompts import PromptTemplate
|
10 |
+
from langchain.chains import StuffDocumentsChain, LLMChain
|
11 |
+
|
12 |
+
def clean_google_news_url(url: str):
|
13 |
+
for ext in [".html", ".cms"]:
|
14 |
+
if ext in url:
|
15 |
+
return url.split(ext)[0] + ext
|
16 |
+
return url.split("&")[0]
|
17 |
+
|
18 |
+
def get_google_news_documents(query: str, max_articles: int = 10, timeout: int = 10):
|
19 |
+
googlenews = GoogleNews(lang="en")
|
20 |
+
end_date = datetime.today()
|
21 |
+
start_date = end_date - timedelta(days=2)
|
22 |
+
googlenews.set_time_range(start_date.strftime("%m/%d/%Y"), end_date.strftime("%m/%d/%Y"))
|
23 |
+
googlenews.search(query)
|
24 |
+
articles = googlenews.result()
|
25 |
+
|
26 |
+
documents = []
|
27 |
+
for article in articles[:max_articles]:
|
28 |
+
url = clean_google_news_url(article.get("link"))
|
29 |
+
try:
|
30 |
+
response = requests.get(url, timeout=timeout, headers={"User-Agent": "Mozilla/5.0"})
|
31 |
+
response.raise_for_status()
|
32 |
+
soup = BeautifulSoup(response.text, "html.parser")
|
33 |
+
paragraphs = soup.find_all("p")
|
34 |
+
content = "\n".join([p.get_text(strip=True) for p in paragraphs if p.get_text(strip=True)])
|
35 |
+
if content and len(content) > 200:
|
36 |
+
doc = Document(
|
37 |
+
page_content=content,
|
38 |
+
metadata={
|
39 |
+
"source": "Google News",
|
40 |
+
"title": article.get("title", ""),
|
41 |
+
"published": article.get("date", ""),
|
42 |
+
"link": url,
|
43 |
+
}
|
44 |
+
)
|
45 |
+
documents.append(doc)
|
46 |
+
except Exception:
|
47 |
+
continue
|
48 |
+
return documents
|
49 |
+
|
50 |
+
def get_market_stock_sentiment(ticker, llm):
|
51 |
+
urls = [
|
52 |
+
f"https://economictimes.indiatimes.com/markets/stocks/news",
|
53 |
+
f"https://www.livemint.com/market/stock-market-news/",
|
54 |
+
f"https://in.tradingview.com/ideas/editors-picks/?type=trade",
|
55 |
+
f"https://pulse.zerodha.com/",
|
56 |
+
"https://upstox.com/news/market-news/stocks/",
|
57 |
+
]
|
58 |
+
|
59 |
+
loader = WebBaseLoader(urls)
|
60 |
+
web_docs = loader.load()
|
61 |
+
|
62 |
+
google_docs = get_google_news_documents("Indian Stock market news NSE, Stocks in Action, Stocks in News, Stocks to Buy in next few weeks", max_articles=10)
|
63 |
+
web_docs.extend(google_docs)
|
64 |
+
|
65 |
+
prompt_template = """You are an expert Stock Market Trader specializing in stock market insights derived from fundamental analysis, analytical trends, profit-based evaluations, news indicators from different sites and detailed company financials.
|
66 |
+
You will receive stock market news articles or stocks in news from various news websites which have India stock news feed. For the below context/input_documents, perform the following tasks:
|
67 |
+
Context:
|
68 |
+
{input_documents}
|
69 |
+
1. **Top picks**: After analyzing all provided data, rank the top 5-10 stocks to look at this week, including tickers, current sentiment, and why they made the list.
|
70 |
+
2. **Identify the stock(s)** mentioned (by ticker and company name).
|
71 |
+
3. **Sentiment analysis**: classify as Bullish, Bearish, or Neutral.
|
72 |
+
4. **Extract critical news**: What is the main event or update? (e.g., earnings beat, regulatory approval, management change, major contract or macro impact).
|
73 |
+
5. **Summarize impact**: Briefly explain how this news might affect stock price and investor behavior (e.g., “could boost investor confidence”, “sign indicates profit pressure”, etc.).
|
74 |
+
6. **Actionable signal**: Based on the sentiment and news, suggest whether this is a “Buy”, “Sell”, “Hold”, or “Watch” recommendation, and the rationale.
|
75 |
+
PROVIDE THE DETAILS based on just the FACTS present in the document. Do NOT DUPLICATE the Output & hallucinate.
|
76 |
+
***Format your output as JSON*** with the following structure:
|
77 |
+
|
78 |
+
```json
|
79 |
+
{{
|
80 |
+
"top_picks": [
|
81 |
+
{{
|
82 |
+
"ticker": "TICKER",
|
83 |
+
"company": "Company Name",
|
84 |
+
"sentiment": "Bullish|Bearish|Neutral",
|
85 |
+
"critical_news": "Brief summary of the key event",
|
86 |
+
"impact_summary": "How this may affect the stock",
|
87 |
+
"action": "Buy|Sell|Hold|Watch",
|
88 |
+
"reason": "Why this stock ranks among top picks"
|
89 |
+
}},
|
90 |
+
...
|
91 |
+
]
|
92 |
+
}}
|
93 |
+
"""
|
94 |
+
|
95 |
+
prompt = PromptTemplate.from_template(prompt_template)
|
96 |
+
chain = StuffDocumentsChain(llm_chain=LLMChain(llm=llm, prompt=prompt), document_variable_name="input_documents")
|
97 |
+
response = chain.invoke({"input_documents": docs})
|
98 |
+
raw = response["output_text"].strip()
|
99 |
+
|
100 |
+
# Clean code block markdown if present
|
101 |
+
if raw.startswith("```json"):
|
102 |
+
raw = raw[len("```json"):]
|
103 |
+
if raw.endswith("```"):
|
104 |
+
raw = raw[:-3]
|
105 |
+
|
106 |
+
try:
|
107 |
+
return json.loads(raw.strip())
|
108 |
+
except json.JSONDecodeError:
|
109 |
+
return {"error": "Failed to parse model output", "raw": raw}
|