stock-ai-agent/scripts/test_stock.py
2026-02-19 21:20:20 +08:00

162 lines
5.1 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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⚠️ 用户中断")