#!/usr/bin/env python3 """ Daily market briefing job (PM). Runs at 4:00 PM CT after market close. """ import sys import os from datetime import datetime # Add workspace to path sys.path.insert(0, "/home/hoffmann_admin/.openclaw/workspace") from core.market import ( get_watchlist_with_metadata, get_top_stories, get_insider_sentiment_summary, get_earnings_this_week, format_news_headline, check_staleness, should_skip_briefing, load_user_watchlist ) from core.market.news import fetch_ticker_news, extract_top_headlines def format_price(price: float, change: float, change_pct: float) -> str: """Format price with change indicator.""" sign = "+" if change >= 0 else "" emoji = "🟢" if change >= 0 else "🔴" return f"${price:.2f} ({sign}{change:.2f} / {sign}{change_pct:.2f}%) {emoji}" def generate_daily_briefing() -> str: """Generate the daily post-market briefing.""" today = datetime.now().strftime("%A, %B %d, %Y") # Check for stale data stale = check_staleness() stale_warning = "" if any(stale.values()): stale_warning = "⚠️ Some data may be stale\n" # Check if we should skip (critical data too old) if should_skip_briefing(): return f"⚠️ Market Briefing Skipped\n\nData is too stale to provide reliable briefing.\nLast successful fetch: check logs." # Get watchlist data watchlist_data = get_watchlist_with_metadata() user_tickers = watchlist_data["user"] dynamic_tickers = watchlist_data["dynamic"] all_symbols = watchlist_data["all_symbols"] # Calculate daily stats gainers = [t for t in user_tickers + dynamic_tickers if t["change"] > 0] losers = [t for t in user_tickers + dynamic_tickers if t["change"] < 0] # Best and worst performers best = max(gainers, key=lambda x: x["change_pct"]) if gainers else None worst = min(losers, key=lambda x: x["change_pct"]) if losers else None # Build watchlist section watchlist_lines = [] # User tickers for ticker in user_tickers: symbol = ticker["symbol"] price_str = format_price( ticker["price"], ticker["change"], ticker["change_pct"] ) # Get news for this ticker news = fetch_ticker_news(symbol) top_news = extract_top_headlines(news, 1) news_str = "" if top_news: news_str = f"\n {format_news_headline(symbol, top_news[0])}" watchlist_lines.append(f"• {symbol}: {price_str}{news_str}") # Dynamic tickers with reasons for ticker in dynamic_tickers: symbol = ticker["symbol"] price_str = format_price( ticker["price"], ticker["change"], ticker["change_pct"] ) reason = ticker.get("reason", "Trending") # Get news for this ticker news = fetch_ticker_news(symbol) top_news = extract_top_headlines(news, 1) news_str = "" if top_news: news_str = f"\n {format_news_headline(symbol, top_news[0])}" watchlist_lines.append(f"• {symbol}: {price_str} {reason}{news_str}") # Get top stories across watchlist top_stories = get_top_stories(all_symbols, count=5) stories_lines = [] for story in top_stories[:3]: # Top 3 ticker = story.get("_ticker", "") headline = story.get("headline", "") source = story.get("source", "Unknown") if len(headline) > 90: headline = headline[:87] + "..." stories_lines.append(f"• [{ticker}] {headline} ({source})") if not stories_lines: stories_lines.append("• No major market-moving news today") # Get insider sentiment insider = get_insider_sentiment_summary(all_symbols) # Get earnings earnings = get_earnings_this_week(all_symbols) # Performance summary performance_lines = [] if best: performance_lines.append(f"🏆 Best: {best['symbol']} (+{best['change_pct']:.2f}%)") if worst: performance_lines.append(f"📉 Worst: {worst['symbol']} ({worst['change_pct']:.2f}%)") # Build the briefing briefing = f"""📈 Market Close Brief — {today} {stale_warning} 📊 Watchlist Performance: {chr(10).join(watchlist_lines)} {chr(10).join(performance_lines)} 📰 Today's Top Stories: {chr(10).join(stories_lines)} 🎯 Insider Sentiment: {chr(10).join(insider)} 📅 This Week: {chr(10).join(earnings)} """ return briefing def main(): """Run the daily briefing.""" try: briefing = generate_daily_briefing() print(briefing) # Send to Telegram if configured chat_id = os.environ.get("MARKET_BRIEFING_CHAT_ID", "8386527252") if chat_id: try: # Try to use Telegram API if available import requests bot_token = os.environ.get("TELEGRAM_BOT_TOKEN") if bot_token and len(briefing) < 4000: url = f"https://api.telegram.org/bot{bot_token}/sendMessage" payload = { "chat_id": chat_id, "text": briefing, "parse_mode": "HTML" } requests.post(url, json=payload, timeout=30) except Exception as e: print(f"Failed to send Telegram message: {e}") return 0 except Exception as e: print(f"Error generating briefing: {e}") import traceback traceback.print_exc() return 1 if __name__ == "__main__": sys.exit(main())