import requests from datetime import datetime, timedelta def fetch_news_items(): """ Fetch the main TradingView news feed for XAUUSD and DXY, return it as a Python dictionary (JSON). """ url = ( "https://news-mediator.tradingview.com/news-flow/v2/news" "?filter=lang%3Aen&filter=symbol%3AOANDA%3AXAUUSD%2CTVC%3ADXY" "&client=screener&streaming=true" ) headers = { "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/138.0.0.0 Safari/537.36" ) } response = requests.get(url, headers=headers) response.raise_for_status() return response.json() def fetch_story_by_id(story_id): """ Given a story ID from the news feed, fetch its full content JSON (shortDescription, astDescription, etc.) from TradingView. """ base_url = "https://news-headlines.tradingview.com/v3/story" params = { "id": story_id, "lang": "en" } headers = { "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/138.0.0.0 Safari/537.36" ) } response = requests.get(base_url, headers=headers, params=params) response.raise_for_status() return response.json() def parse_ast_node(node): """ Recursively parse an AST node from the 'astDescription' field: - If it's a string, just return it. - If it's a dictionary with a known 'type', handle it. - Otherwise, parse children recursively. """ if isinstance(node, str): # Direct text return node if isinstance(node, dict): node_type = node.get("type", "") children = node.get("children", []) if node_type == "root": # 'root' typically contains multiple children; parse them all return "".join(parse_ast_node(child) for child in children) elif node_type == "p": # Paragraph node: parse children, add a newline paragraph_text = "".join(parse_ast_node(child) for child in children) return paragraph_text + "\n" elif node_type == "url": # Format a hyperlink: [text](url) params = node.get("params", {}) link_text = params.get("linkText", "") url = params.get("url", "") return f"{link_text} ({url})" elif node_type == "symbol": # Format a symbol mention params = node.get("params", {}) symbol = params.get("symbol", "") text = params.get("text", "") return text if text else symbol else: # Unknown or unhandled node type; parse children anyway return "".join(parse_ast_node(child) for child in children) # If not string or dict (e.g., None?), return empty string return "" def extract_full_content_from_story(story_data): """ Extract the full textual content from a story, handling both shortDescription and the more detailed astDescription if available. """ # Try to get the AST description first (more detailed) ast_description = story_data.get("astDescription") if ast_description: return parse_ast_node(ast_description) # Fall back to short description if AST not available return story_data.get("shortDescription", "No content available") def get_recent_news_items(hours=100): """ Fetch recent news items within the specified number of hours and return detailed information including publish time and full content. """ # Get current time and calculate the threshold now_utc = datetime.utcnow() time_threshold = now_utc - timedelta(hours=hours) # Fetch news data news_data = fetch_news_items() items = news_data.get("items", []) detailed_news = [] for item in items: item_id = item.get("id", "") published_ts = item.get("published") if not item_id or not published_ts: continue published_dt = datetime.utcfromtimestamp(published_ts) if published_dt >= time_threshold: # For each qualifying news item, fetch its full story content try: story_data = fetch_story_by_id(item_id) # Create a detailed news item detailed_item = { "id": item_id, "title": item.get("title", ""), "source": item.get("source", {}).get("name", ""), "published_time": published_dt.strftime("%Y-%m-%d %H:%M:%S UTC"), "timestamp": published_ts, "content": extract_full_content_from_story(story_data) } detailed_news.append(detailed_item) except Exception as e: print(f"Error fetching details for story {item_id}: {e}") # Sort by timestamp descending (newest first) detailed_news.sort(key=lambda x: x["timestamp"], reverse=True) return detailed_news def build_news_summary(news_items): """ Build a comprehensive summary of news items, including title, source, publication time, and full content. """ if not news_items: return "No recent news available." summaries = [] for item in news_items: summary = ( f"📰 {item['title']}\n" f"🔍 Source: {item['source']}\n" f"⏰ Published: {item['published_time']}\n" f"📝 Content:\n{item['content']}\n" f"{'=' * 50}" ) summaries.append(summary) return "\n\n".join(summaries) def get_formatted_news_summary(hours=24): """ Convenience function to get a formatted news summary for the specified time period. """ news_items = get_recent_news_items(hours) return build_news_summary(news_items) # Example usage: if __name__ == "__main__": print("Fetching recent gold and DXY news...") news_summary = get_formatted_news_summary(48) # Get news from the last 48 hours print(news_summary)