#!/usr/bin/env python3 """ Pre-market briefing job (AM). Runs at 8:00 AM CT before market open. """ 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 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_premarket_briefing() -> str: """Generate the pre-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"] # 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 from core.market.news import fetch_ticker_news, extract_top_headlines 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 from core.market.news import fetch_ticker_news, extract_top_headlines 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) # Build the briefing briefing = f"""🌅 Pre-Market Brief — {today} {stale_warning} 📊 Watchlist: {chr(10).join(watchlist_lines)} 📰 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 pre-market briefing.""" try: briefing = generate_premarket_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())