stock-ai-agent/backend/diagnose_astock.py
2026-03-11 00:01:18 +08:00

204 lines
7.1 KiB
Python
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
"""
A股短期题材选股 - 详细诊断版本
显示每个股票的筛选过程
"""
import asyncio
import sys
import os
from datetime import datetime, timedelta
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from app.utils.logger import logger
from app.config import get_settings
from app.astock_agent.tushare_client import get_tushare_client
async def diagnose_sector_stocks():
"""诊断板块成分股的筛选过程"""
print("\n" + "=" * 60)
print("🔍 A股选股详细诊断")
print("=" * 60)
settings = get_settings()
ts_client = get_tushare_client(settings.tushare_token)
# 1. 测试获取一个板块的成分股
print("\n【测试】获取智能电网板块成分股...")
try:
# 使用智能电网板块代码(与选股器一致)
sector_code = "885311.TI"
members_df = ts_client.get_sector_members(sector_code)
if members_df.empty:
print("❌ 无法获取板块成分股")
return
stock_codes = members_df['con_code'].tolist()[:10] # 只测试前10只
print(f"✓ 获取到 {len(stock_codes)} 只成分股测试前10只")
print(f"股票代码: {stock_codes}")
# 2. 获取这些股票的实时行情
print("\n【测试】获取实时行情...")
today = datetime.now().strftime('%Y%m%d')
yesterday = (datetime.now() - timedelta(days=10)).strftime('%Y%m%d')
all_stocks_data = []
for stock_code in stock_codes:
try:
daily_df = ts_client.pro.daily(
ts_code=stock_code,
start_date=yesterday,
end_date=today
)
if daily_df.empty:
print(f" ⚠️ {stock_code}: 无历史数据")
continue
daily_df = daily_df.sort_values('trade_date')
latest = daily_df.iloc[-1]
stock_info = {
'ts_code': stock_code,
'name': latest.get('name', ''),
'close': float(latest['close']),
'pct_chg': float(latest['pct_chg']),
'vol': float(latest['vol']),
'amount': float(latest['amount']) * 1000,
'trade_date': str(latest['trade_date'])
}
all_stocks_data.append(stock_info)
except Exception as e:
print(f"{stock_code}: 获取失败 - {e}")
continue
print(f"\n✓ 成功获取 {len(all_stocks_data)} 只股票的行情")
# 3. 获取每日指标
print("\n【测试】获取每日指标(换手率等)...")
basic_df = ts_client.pro.daily_basic(
ts_code=','.join(stock_codes),
trade_date=all_stocks_data[0]['trade_date'],
fields='ts_code,trade_date,turnover_rate,pe,pb'
)
if basic_df.empty:
print("⚠️ 无法获取每日指标数据")
else:
print(f"✓ 获取到 {len(basic_df)} 只股票的每日指标")
# 4. 逐个检查筛选条件
print("\n【测试】逐个检查筛选条件...")
print("=" * 80)
for stock_info in all_stocks_data:
stock_code = stock_info['ts_code']
name = stock_info['name']
close = stock_info['close']
pct_chg = stock_info['pct_chg']
vol = stock_info['vol']
amount = stock_info['amount']
print(f"\n🔍 {name}({stock_code}):")
print(f" 日期: {stock_info['trade_date']}")
print(f" 现价: ¥{close:.2f}, 涨跌幅: {pct_chg:+.2f}%")
# 检查1: ST股票
if 'ST' in name or '退' in name:
print(f" ❌ ST/退市股,被过滤")
continue
print(f" ✓ 不是ST/退市股")
# 检查2: 换手率
basic_row = basic_df[basic_df['ts_code'] == stock_code]
if not basic_row.empty:
turnover = float(basic_row.iloc[0].get('turnover_rate', 0))
print(f" 换手率: {turnover:.2f}%")
if 1.0 <= turnover <= 20.0:
print(f" ✓ 换手率符合")
else:
print(f" ❌ 换手率不符合需要1%-20%")
continue
else:
print(f" ⚠️ 无换手率数据")
turnover = 0
# 检查3: MA多头排列
try:
start_date = (datetime.now() - timedelta(days=60)).strftime('%Y%m%d')
daily_df = ts_client.pro.daily(
ts_code=stock_code,
start_date=start_date,
end_date=today
)
if daily_df.empty or len(daily_df) < 30:
print(f" ❌ 历史数据不足需要30天以上无法计算MA")
continue
daily_df = daily_df.sort_values('trade_date').reset_index(drop=True)
close_series = daily_df['close']
vol_series = daily_df['vol']
ma5 = close_series.rolling(window=5).mean().iloc[-1]
ma10 = close_series.rolling(window=10).mean().iloc[-1]
ma20 = close_series.rolling(window=20).mean().iloc[-1]
print(f" MA5: ¥{ma5:.2f}, MA10: ¥{ma10:.2f}, MA20: ¥{ma20:.2f}")
if ma5 > ma20:
print(f" ✓ MA趋势符合MA5 > MA20")
else:
print(f" ❌ MA趋势不符合需要 MA5 > MA20")
continue
# 检查4: 量能
ma5_vol = vol_series.rolling(window=5).mean().iloc[-1]
volume_ratio = vol / ma5_vol if ma5_vol > 0 else 1
print(f" 量比: {volume_ratio:.2f}")
if volume_ratio >= 0.7:
print(f" ✓ 量能符合≥0.7")
else:
print(f" ❌ 量能不足量比需要≥0.7")
continue
# 检查5: 市值
if turnover > 0:
market_cap = amount / (turnover / 100)
market_cap_yi = market_cap / 100000000
print(f" 市值: {market_cap_yi:.2f}亿")
if 30 <= market_cap_yi <= 1000:
print(f" ✓ 市值符合")
else:
print(f" ❌ 市值不符合需要30-1000亿")
continue
print(f" ✅✅✅ {name}({stock_code}) 通过所有筛选条件!")
except Exception as e:
print(f" ❌ 计算技术指标失败: {e}")
import traceback
print(traceback.format_exc())
except Exception as e:
print(f"❌ 诊断失败: {e}")
import traceback
traceback.print_exc()
async def main():
"""主函数"""
await diagnose_sector_stocks()
print("\n" + "=" * 60)
print("诊断完成")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())