Spaces:
Runtime error
Runtime error
| # core/stock_analysis.py | |
| import requests | |
| import json | |
| from datetime import datetime, timedelta | |
| from tradingview_ta import TA_Handler, Interval | |
| from langchain_community.document_loaders import WebBaseLoader | |
| from langchain_core.documents.base import Document | |
| from bs4 import BeautifulSoup | |
| from GoogleNews import GoogleNews | |
| from langchain_core.prompts import PromptTemplate | |
| # New, correct imports: | |
| from langchain.chains import LLMChain | |
| from langchain.chains.combine_documents.stuff import StuffDocumentsChain | |
| def clean_google_news_url(url: str): | |
| for ext in [".html", ".cms"]: | |
| if ext in url: | |
| return url.split(ext)[0] + ext | |
| return url.split("&")[0] | |
| def get_google_news_documents(query: str, max_articles: int = 10, timeout: int = 10): | |
| googlenews = GoogleNews(lang="en") | |
| end_date = datetime.today() | |
| start_date = end_date - timedelta(days=2) | |
| googlenews.set_time_range(start_date.strftime("%m/%d/%Y"), end_date.strftime("%m/%d/%Y")) | |
| googlenews.search(query) | |
| articles = googlenews.result() | |
| documents = [] | |
| for article in articles[:max_articles]: | |
| url = clean_google_news_url(article.get("link")) | |
| try: | |
| response = requests.get(url, timeout=timeout, headers={"User-Agent": "Mozilla/5.0"}) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.text, "html.parser") | |
| paragraphs = soup.find_all("p") | |
| content = "\n".join([p.get_text(strip=True) for p in paragraphs if p.get_text(strip=True)]) | |
| if content and len(content) > 200: | |
| doc = Document( | |
| page_content=content, | |
| metadata={ | |
| "source": "Google News", | |
| "title": article.get("title", ""), | |
| "published": article.get("date", ""), | |
| "link": url, | |
| } | |
| ) | |
| documents.append(doc) | |
| except Exception: | |
| continue | |
| return documents | |
| def analyze_stock(ticker, llm): | |
| try: | |
| handler = TA_Handler(symbol=ticker, screener="india", exchange="NSE", interval=Interval.INTERVAL_1_DAY) | |
| summary = handler.get_analysis().summary | |
| except Exception: | |
| return {"error": "Invalid ticker or failed to fetch trading data"} | |
| urls = [ | |
| f"https://www.google.com/finance/quote/{ticker}:NSE?hl=en", | |
| f"https://in.tradingview.com/symbols/NSE-{ticker}/", | |
| f"https://in.tradingview.com/symbols/NSE-{ticker}/news/", | |
| f"https://in.tradingview.com/symbols/NSE-{ticker}/minds/" | |
| ] | |
| loader = WebBaseLoader(urls) | |
| web_docs = loader.load() | |
| news_docs = get_google_news_documents(f"Trending News for {ticker}", max_articles=10) | |
| docs = web_docs + news_docs | |
| 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. | |
| Using your expertise, please analyze the stock based on the provided context below. | |
| Context: | |
| {input_documents} | |
| Task: | |
| Summarize the stock based on its historical and current data. Keep it CONCISE & BRIEF. | |
| Evaluate the stock on the following parameters: | |
| 1. Company Fundamentals: Assess the stock's intrinsic value, growth potential, and financial health. | |
| 2. Current & Future Price Trends: Analyze historical price movements and current price trends. | |
| 3. News and Sentiment: Review recent news articles, press releases, and social media sentiment. | |
| 4. Red Flags: Identify any potential risks or warning signs. | |
| 5. Provide a rating for the stock on a scale of 1 to 10. | |
| 6. Advise if the stock is a good buy for the next 1,5, 10 weeks. | |
| 7. Suggest at what price we need to buy and hold or sell the stock | |
| PROVIDE THE DETAILS based on just the FACTS present in the document | |
| PROVIDE THE DETAILS IN an JSON Object. Stick to the below JSON object | |
| MAKE 100% SURE THAT THE "ticker" value is a valid ticker symbol from the documents from NSE India | |
| {{ | |
| "stock_summary": {{ | |
| "company_name": "", | |
| "ticker": "", | |
| "exchange": "", | |
| "description": "", | |
| "current_price": "", | |
| "market_cap": "", | |
| "historical_performance": {{ | |
| "5_day": "", | |
| "1_month": "", | |
| "6_months": "", | |
| "1_year": "", | |
| "5_years": "" | |
| }} | |
| }}, | |
| "evaluation_parameters": {{ | |
| "company_fundamentals": {{ | |
| "assessment": "", | |
| "key_metrics": {{ | |
| "pe_ratio": "", | |
| "volume":"", | |
| "revenue_growth_yoy": "", | |
| "net_income_growth_yoy": "", | |
| "eps_growth_yoy": "", | |
| "dividend_yield": "", | |
| "balance_sheet": "", | |
| "return_on_capital": "" | |
| }} | |
| }}, | |
| "current_and_future_price_trends": {{ | |
| "assessment": "", | |
| "historical_trends": "", | |
| "current_trends": "", | |
| "technical_analysis_notes": "", | |
| "technical_indicators":"" | |
| }}, | |
| "news_and_sentiment": {{ | |
| "assessment": "", | |
| "positive_sentiment": [ | |
| "", | |
| "", | |
| "" | |
| ], | |
| "negative_sentiment": [ | |
| "", | |
| "", | |
| "" | |
| ] | |
| }}, | |
| "red_flags": [ | |
| {{ | |
| "flag": "", | |
| "details": "" | |
| }}, | |
| {{ | |
| "flag": "", | |
| "details": "" | |
| }}, | |
| {{ | |
| "flag": "", | |
| "details": "" | |
| }} | |
| ] | |
| }}, | |
| "overall_rating": {{ | |
| "rating": "ranging from 1 to 10, 1 being low rated, 10 being highly rated", | |
| "justification": "" | |
| }}, | |
| "investment_advice": {{ | |
| "next_1_weeks_outlook": "", | |
| "next_5_weeks_outlook": "", | |
| "next_10_weeks_outlook": "", | |
| "price_action_suggestions": {{ | |
| "buy": "", | |
| "hold": "", | |
| "sell": "" | |
| }} | |
| }} | |
| }} | |
| """ | |
| prompt = PromptTemplate.from_template(prompt_template) | |
| chain = StuffDocumentsChain(llm_chain=LLMChain(llm=llm, prompt=prompt), document_variable_name="input_documents") | |
| response = chain.invoke({"input_documents": docs}) | |
| raw = response["output_text"].strip() | |
| # Clean code block markdown if present | |
| if raw.startswith("```json"): | |
| raw = raw[len("```json"):] | |
| if raw.endswith("```"): | |
| raw = raw[:-3] | |
| try: | |
| return json.loads(raw.strip()) | |
| except json.JSONDecodeError: | |
| return {"error": "Failed to parse model output", "raw": raw} | |