#!/usr/bin/env python3 """ 美股手动分析脚本 用法: python3 scripts/analyze_stock.py AAPL # 分析单只股票 python3 scripts/analyze_stock.py AAPL TSLA # 分析多只股票 python3 scripts/analyze_stock.py # 分析配置的所有股票 环境: 需要在 backend 目录下运行,或设置 PYTHONPATH """ import sys import os import asyncio from datetime import datetime # 添加项目路径 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'backend')) from app.services.yfinance_service import get_yfinance_service from app.crypto_agent.llm_signal_analyzer import LLMSignalAnalyzer from app.config import get_settings from app.utils.logger import logger async def analyze_stock(symbol: str): """ 分析单只股票 Args: symbol: 股票代码 """ print("\n" + "=" * 80) print(f"📊 分析 {symbol}") print("=" * 80) try: # 1. 获取服务 yf_service = get_yfinance_service() llm_analyzer = LLMSignalAnalyzer() settings = get_settings() # 2. 获取当前行情 print(f"\n📈 获取当前行情...") ticker = yf_service.get_ticker(symbol) if not ticker: print(f"❌ 无法获取 {symbol} 的行情数据") return current_price = ticker['lastPrice'] price_change = ticker['priceChange'] price_change_percent = ticker['priceChangePercent'] print(f" 最新价格: ${current_price:,.2f}") print(f" 涨跌额: ${price_change:+,.2f}") print(f" 涨跌幅: {price_change_percent:+.2f}%") print(f" 成交量: {ticker['volume']:,}") # 3. 获取 K 线数据 print(f"\n📊 获取 K 线数据...") data = yf_service.get_multi_timeframe_data(symbol) if not data: print(f"❌ 无法获取 {symbol} 的 K 线数据") return for tf, df in data.items(): print(f" {tf}: {len(df)} 条数据") # 4. LLM 分析 print(f"\n🤖 LLM 分析中...") print("-" * 80) result = await llm_analyzer.analyze( symbol, data, symbols=[symbol], position_info=None ) # 5. 输出分析结果 print("\n📋 分析结果:") print("-" * 80) # 市场状态 summary = result.get('analysis_summary', '无') print(f"市场状态: {summary}") # 新闻情绪 news_sentiment = result.get('news_sentiment', '') if news_sentiment: sentiment_map = {'positive': '📈 积极', 'negative': '📉 消极', 'neutral': '➖ 中性'} print(f"新闻情绪: {sentiment_map.get(news_sentiment, news_sentiment)}") news_impact = result.get('news_impact', '') if news_impact: print(f"消息影响: {news_impact}") # 关键价位 levels = result.get('key_levels', {}) if levels.get('support') or levels.get('resistance'): print(f"\n关键价位:") if levels.get('support'): support_str = ', '.join([f"${s:,.2f}" for s in levels.get('support', [])[:3]]) print(f" 支撑位: {support_str}") if levels.get('resistance'): resistance_str = ', '.join([f"${r:,.2f}" for r in levels.get('resistance', [])[:3]]) print(f" 阻力位: {resistance_str}") # 信号 signals = result.get('signals', []) if not signals: print(f"\n⏸️ 结论: 无交易信号,继续观望") else: print(f"\n🎯 发现 {len(signals)} 个信号:") print("-" * 80) for sig in signals: signal_type = sig.get('type', 'unknown') type_map = {'short_term': '短线', 'medium_term': '中线', 'long_term': '长线'} type_text = type_map.get(signal_type, signal_type) action = sig.get('action', 'wait') action_map = {'buy': '🟢 做多', 'sell': '🔴 做空', 'wait': '⏸️ 观望'} action_text = action_map.get(action, action) grade = sig.get('grade', 'D') confidence = sig.get('confidence', 0) grade_icon = {'A': '⭐⭐⭐', 'B': '⭐⭐', 'C': '⭐', 'D': ''}.get(grade, '') print(f"\n{type_text} {action_text} [{grade}级{grade_icon}] {confidence}%") entry = sig.get('entry_price', 0) sl = sig.get('stop_loss', 0) tp = sig.get('take_profit', 0) if entry and sl and tp: print(f" 入场: ${entry:,.2f}") print(f" 止损: ${sl:,.2f} ({((sl - entry) / entry * 100):+.1f}%)") print(f" 止盈: ${tp:,.2f} ({((tp - entry) / entry * 100):+.1f}%)") reason = sig.get('reason', '') if reason: print(f" 理由: {reason}") risk_warning = sig.get('risk_warning', '') if risk_warning: print(f" 风险提示: {risk_warning}") # 6. 格式化通知 if signals: print("\n" + "=" * 80) print("📱 通知预览:") print("-" * 80) for sig in signals: if sig.get('grade', 'D') != 'D': formatted = llm_analyzer.format_signal_for_notification(symbol, sig) print(f"\n{formatted['title']}") print(formatted['content']) except Exception as e: print(f"\n❌ 分析 {symbol} 失败: {e}") import traceback traceback.print_exc() async def main(): """主函数""" import argparse parser = argparse.ArgumentParser(description='美股手动分析脚本') parser.add_argument('symbols', nargs='*', help='股票代码(留空则分析配置的所有股票)') args = parser.parse_args() # 确定要分析的股票 if args.symbols: symbols = [s.upper() for s in args.symbols] else: settings = get_settings() symbols = settings.stock_symbols.split(',') if settings.stock_symbols else [] if not symbols or not symbols[0]: print("❌ 未指定股票代码,且配置文件中未配置 STOCK_SYMBOLS") print("\n用法:") print(" python3 scripts/analyze_stock.py AAPL") print(" python3 scripts/analyze_stock.py AAPL TSLA NVDA") print(" python3 scripts/analyze_stock.py # 分析配置的所有股票") sys.exit(1) print("\n" + "=" * 80) print("🤖 美股手动分析脚本") print("=" * 80) print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print(f"股票: {', '.join(symbols)}") print("=" * 80) # 逐个分析 for symbol in symbols: await analyze_stock(symbol) print("\n" + "=" * 80) print("✅ 分析完成!") print("=" * 80) if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print("\n\n⚠️ 用户中断") sys.exit(0)