#!/usr/bin/env python3 """ 美股分析脚本(修复版) 用法: python3 scripts/test_stock.py AAPL python3 scripts/test_stock.py AAPL TSLA NVDA """ import sys import os # 确保路径正确 script_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(script_dir) backend_dir = os.path.join(project_root, 'backend') sys.path.insert(0, backend_dir) import asyncio from app.services.yfinance_service import get_yfinance_service from app.services.feishu_service import get_feishu_service from app.services.telegram_service import get_telegram_service from app.crypto_agent.llm_signal_analyzer import LLMSignalAnalyzer from app.utils.logger import logger async def analyze(symbol: str, send_notification: bool = True): """分析单只股票 Args: symbol: 股票代码 send_notification: 是否发送通知(默认True) """ print(f"\n{'='*60}") print(f"📊 分析 {symbol}") print(f"{'='*60}") try: # 获取服务 yf_service = get_yfinance_service() llm = LLMSignalAnalyzer() feishu = get_feishu_service() telegram = get_telegram_service() # 获取行情 print(f"获取行情...") ticker = yf_service.get_ticker(symbol) if not ticker: print(f"❌ 无法获取 {symbol} 行情") return price = ticker['lastPrice'] change = ticker['priceChangePercent'] print(f"价格: ${price:,.2f} ({change:+.2f}%)") print(f"成交量: {ticker['volume']:,}") # 获取K线 print(f"获取K线数据...") data = yf_service.get_multi_timeframe_data(symbol) if not data: print(f"❌ 无法获取K线数据") return print(f"时间周期: {', '.join(data.keys())}") # LLM分析 print(f"\n🤖 LLM分析中...\n") result = await llm.analyze(symbol, data, symbols=[symbol], position_info=None) # 输出结果 summary = result.get('analysis_summary', '') signals = result.get('signals', []) print(f"市场状态: {summary}") if signals: print(f"\n🎯 发现 {len(signals)} 个信号:") for sig in signals: action = sig.get('action', 'wait') grade = sig.get('grade', 'D') conf = sig.get('confidence', 0) action_text = {'buy': '🟢 做多', 'sell': '🔴 做空'}.get(action, action) grade_icon = {'A': '⭐⭐⭐', 'B': '⭐⭐', 'C': '⭐'}.get(grade, '') print(f"\n{action_text} [{grade}{grade_icon}] {conf}%") entry = sig.get('entry_price') sl = sig.get('stop_loss') tp = sig.get('take_profit') if entry and sl and tp: print(f" 入场: ${entry:,.2f}") print(f" 止损: ${sl:,.2f}") print(f" 止盈: ${tp:,.2f}") reason = sig.get('reason', '') if reason: # 限制理由长度 short_reason = reason[:80] + "..." if len(reason) > 80 else reason print(f" 理由: {short_reason}") # 发送通知(仅发送置信度 >= 60% 的信号) if send_notification: best_signal = None for sig in signals: if sig.get('confidence', 0) >= 60 and sig.get('grade', 'D') != 'D': best_signal = sig break if best_signal: # 使用正确的方法格式化通知 card = llm.format_feishu_card(best_signal, symbol) title = card['title'] content = card['content'] # 发送通知 await feishu.send_markdown(title, content) await telegram.send_message(llm.format_signal_message(best_signal, symbol)) print(f"\n📬 通知已发送:{title}") else: print(f"\n⏸️ 置信度不足,不发送通知") else: print(f"\n⏸️ 无交易信号") except Exception as e: print(f"❌ 错误: {e}") import traceback traceback.print_exc() async def main(): # 从命令行参数获取股票代码 if len(sys.argv) < 2: print("用法: python3 scripts/test_stock.py AAPL [TSLA] [NVDA] ...") print("\n示例:") print(" python3 scripts/test_stock.py AAPL") print(" python3 scripts/test_stock.py AAPL TSLA NVDA") sys.exit(1) symbols = sys.argv[1:] print("="*60) print("🤖 美股分析脚本") print("="*60) print(f"股票: {', '.join(symbols)}") print(f"时间: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") for symbol in symbols: await analyze(symbol.upper()) print("\n" + "="*60) print("✅ 分析完成") print("="*60) if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print("\n\n⚠️ 用户中断")