trading.ai/test_weekly_sectors.py
2025-09-23 16:12:18 +08:00

258 lines
9.9 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
"""
测试使用Tushare找出本周强势板块
"""
import sys
from pathlib import Path
import pandas as pd
from datetime import datetime, timedelta
# 添加项目根目录到路径
current_dir = Path(__file__).parent
sys.path.insert(0, str(current_dir))
from src.data.tushare_fetcher import TushareFetcher
from loguru import logger
def get_this_week_dates():
"""获取本周的开始和结束日期"""
today = datetime.now()
# 获取本周一
monday = today - timedelta(days=today.weekday())
# 获取本周五(或今天如果还没到周五)
friday = monday + timedelta(days=4)
if friday > today:
friday = today
return monday.strftime('%Y%m%d'), friday.strftime('%Y%m%d')
def analyze_sector_performance(fetcher: TushareFetcher):
"""分析行业板块表现"""
try:
logger.info("开始分析本周强势板块...")
# 获取本周日期范围
start_date, end_date = get_this_week_dates()
logger.info(f"分析时间范围: {start_date}{end_date}")
if not fetcher.pro:
logger.error("需要Tushare Pro权限才能获取行业数据")
return
# 直接使用概念和行业数据分析
logger.info("通过个股数据分析板块表现...")
# 获取股票基本信息(包含行业分类)
try:
stock_basic = fetcher.pro.stock_basic(
exchange='',
list_status='L',
fields='ts_code,symbol,name,area,industry,market'
)
logger.info(f"获取到 {len(stock_basic)} 只股票基本信息")
except Exception as e:
logger.error(f"获取股票基本信息失败: {e}")
return
# 按行业分组分析
industry_performance = {}
# 取样分析避免API请求过多
sample_stocks = stock_basic.sample(min(200, len(stock_basic))) # 随机取200只股票
logger.info(f"随机抽样 {len(sample_stocks)} 只股票进行分析...")
for _, stock in sample_stocks.iterrows():
ts_code = stock['ts_code']
industry = stock['industry']
stock_name = stock['name']
if pd.isna(industry) or industry == '':
continue
try:
# 获取个股本周数据
stock_data = fetcher.pro.daily(
ts_code=ts_code,
start_date=start_date,
end_date=end_date
)
if not stock_data.empty and len(stock_data) >= 1:
# 获取最新价格和前一个交易日价格
if len(stock_data) >= 2:
latest_close = stock_data.iloc[0]['close']
prev_close = stock_data.iloc[1]['close']
else:
# 如果只有一天数据,获取开盘价作为对比
latest_close = stock_data.iloc[0]['close']
prev_close = stock_data.iloc[0]['open']
if prev_close > 0:
change_pct = (latest_close - prev_close) / prev_close * 100
# 按行业归类
if industry not in industry_performance:
industry_performance[industry] = {
'stock_changes': [],
'stock_count': 0,
'stock_names': []
}
industry_performance[industry]['stock_changes'].append(change_pct)
industry_performance[industry]['stock_count'] += 1
industry_performance[industry]['stock_names'].append(f"{stock_name}({change_pct:+.2f}%)")
logger.debug(f"{stock_name} ({industry}): {change_pct:+.2f}%")
except Exception as e:
logger.debug(f"分析个股 {ts_code} 失败: {e}")
continue
# 计算各行业平均表现
industry_results = []
for industry, data in industry_performance.items():
if data['stock_count'] >= 3: # 至少要有3只股票才参与排名
avg_change = sum(data['stock_changes']) / len(data['stock_changes'])
industry_results.append({
'industry_name': industry,
'avg_change_pct': avg_change,
'stock_count': data['stock_count'],
'best_stocks': sorted(data['stock_names'], key=lambda x: float(x.split('(')[1].split('%')[0]), reverse=True)[:3]
})
# 3. 分析结果
if industry_results:
df_performance = pd.DataFrame(industry_results)
# 按平均涨跌幅排序
df_performance = df_performance.sort_values('avg_change_pct', ascending=False)
logger.info("\n" + "="*80)
logger.info("📈 本周强势板块排行榜(基于抽样股票分析)")
logger.info("="*80)
print(f"{'排名':<4} {'行业名称':<20} {'平均涨跌幅':<12} {'样本数量':<8} {'代表个股':<30}")
print("-" * 80)
for i, (_, row) in enumerate(df_performance.head(15).iterrows()):
rank = i + 1
industry_name = row['industry_name'][:18] + '..' if len(row['industry_name']) > 18 else row['industry_name']
change_pct = f"{row['avg_change_pct']:+.2f}%"
stock_count = f"{row['stock_count']}"
best_stock = row['best_stocks'][0] if row['best_stocks'] else "无数据"
print(f"{rank:<4} {industry_name:<20} {change_pct:<12} {stock_count:<8} {best_stock:<30}")
# 输出强势板块涨幅前5
top_sectors = df_performance.head(5)
logger.info(f"\n🚀 本周TOP5强势板块:")
for i, (_, sector) in enumerate(top_sectors.iterrows()):
logger.info(f" {i+1}. {sector['industry_name']}: {sector['avg_change_pct']:+.2f}% (样本{sector['stock_count']}只)")
for j, stock in enumerate(sector['best_stocks'][:3]):
logger.info(f" └─ {stock}")
# 输出弱势板块跌幅前5
weak_sectors = df_performance.tail(5)
logger.info(f"\n📉 本周TOP5弱势板块:")
for i, (_, sector) in enumerate(weak_sectors.iterrows()):
logger.info(f" {i+1}. {sector['industry_name']}: {sector['avg_change_pct']:+.2f}% (样本{sector['stock_count']}只)")
else:
logger.warning("未获取到有效的行业表现数据")
except Exception as e:
logger.error(f"分析行业表现失败: {e}")
def get_sector_top_stocks(fetcher: TushareFetcher, industry_code: str, industry_name: str, limit: int = 5):
"""获取指定板块的强势个股"""
try:
logger.info(f"获取 {industry_name} 板块的强势个股...")
if not fetcher.pro:
return
# 获取该行业的成分股
try:
constituents = fetcher.pro.index_member(index_code=industry_code)
if constituents.empty:
logger.warning(f"{industry_name} 行业无成分股数据")
return
stock_codes = constituents['con_code'].tolist()[:20] # 取前20只股票测试
logger.info(f"{industry_name} 行业共 {len(constituents)} 只成分股,分析前 {len(stock_codes)}")
except Exception as e:
logger.error(f"获取 {industry_name} 成分股失败: {e}")
return
# 获取本周日期
start_date, end_date = get_this_week_dates()
# 分析各股票本周表现
stock_performance = []
for stock_code in stock_codes[:10]: # 限制分析数量
try:
# 获取个股本周数据
stock_data = fetcher.pro.daily(
ts_code=stock_code,
start_date=start_date,
end_date=end_date
)
if not stock_data.empty and len(stock_data) >= 2:
latest_close = stock_data.iloc[0]['close']
week_start_close = stock_data.iloc[-1]['close']
week_change = (latest_close - week_start_close) / week_start_close * 100
# 获取股票名称
stock_name = fetcher.get_stock_name(stock_code.split('.')[0])
stock_performance.append({
'stock_code': stock_code,
'stock_name': stock_name,
'week_change_pct': week_change,
'latest_close': latest_close
})
except Exception as e:
logger.debug(f"分析个股 {stock_code} 失败: {e}")
continue
# 输出该板块强势个股
if stock_performance:
df_stocks = pd.DataFrame(stock_performance)
df_stocks = df_stocks.sort_values('week_change_pct', ascending=False)
logger.info(f"\n📊 {industry_name} 板块强势个股 TOP{limit}:")
for _, stock in df_stocks.head(limit).iterrows():
logger.info(f" {stock['stock_name']} ({stock['stock_code']}): {stock['week_change_pct']:+.2f}%")
except Exception as e:
logger.error(f"获取 {industry_name} 板块个股失败: {e}")
def main():
"""主函数"""
logger.info("开始测试Tushare获取本周强势板块...")
# 初始化Tushare数据获取器
token = "0ed6419a00d8923dc19c0b58fc92d94c9a0696949ab91a13aa58a0cc"
fetcher = TushareFetcher(token=token)
# 分析板块表现
analyze_sector_performance(fetcher)
# 分析某个强势板块的个股(示例)
# get_sector_top_stocks(fetcher, "801010.SI", "农林牧渔")
logger.info("测试完成!")
if __name__ == "__main__":
main()