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

268 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
"""
使用东财概念板块数据分析本周强势板块
需要5000积分
"""
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_recent_trading_dates(days_back=5):
"""获取最近的交易日期"""
dates = []
current = datetime.now()
while len(dates) < days_back:
# 排除周末
if current.weekday() < 5: # 0-4是周一到周五
dates.append(current.strftime('%Y%m%d'))
current -= timedelta(days=1)
return sorted(dates) # 升序返回
def analyze_eastmoney_concepts(fetcher: TushareFetcher):
"""使用东财概念板块数据分析"""
try:
if not fetcher.pro:
logger.error("需要Tushare Pro权限")
return
logger.info("🚀 使用东财概念板块数据分析...")
# 获取最近5个交易日
trading_dates = get_recent_trading_dates(5)
logger.info(f"分析时间范围: {trading_dates[0]}{trading_dates[-1]}")
# 获取最新交易日的概念板块数据
latest_date = trading_dates[-1]
try:
# 使用东财概念板块接口
dc_concepts = fetcher.pro.dc_index(trade_date=latest_date)
logger.info(f"获取到 {len(dc_concepts)} 个东财概念板块")
if dc_concepts.empty:
logger.warning("未获取到东财概念板块数据")
return
# 打印数据结构以便调试
logger.info(f"数据列名: {list(dc_concepts.columns)}")
if not dc_concepts.empty:
logger.info(f"样本数据:\n{dc_concepts.head(2)}")
# 检查涨跌幅字段名
change_col = None
for col in ['pct_chg', 'pct_change', 'change_pct', 'chg_pct']:
if col in dc_concepts.columns:
change_col = col
break
if change_col:
# 按涨跌幅排序
dc_concepts = dc_concepts.sort_values(change_col, ascending=False)
else:
logger.warning("未找到涨跌幅字段,使用原始顺序")
change_col = 'code' # 使用code作为默认排序
print("\n" + "="*80)
print("📈 东财概念板块实时排行榜")
print("="*80)
# 显示表头
if change_col != 'code':
print(f"{'排名':<4} {'概念名称':<25} {'涨跌幅':<10} {'概念代码':<15}")
else:
print(f"{'排名':<4} {'概念名称':<25} {'概念代码':<15}")
print("-" * 80)
for i, (_, concept) in enumerate(dc_concepts.head(20).iterrows()):
rank = i + 1
name = concept.get('name', 'N/A')[:23] + '..' if len(str(concept.get('name', 'N/A'))) > 23 else concept.get('name', 'N/A')
code = concept.get('ts_code', 'N/A')
if change_col != 'code':
change_pct = f"{concept[change_col]:+.2f}%" if not pd.isna(concept.get(change_col, 0)) else "N/A"
print(f"{rank:<4} {name:<25} {change_pct:<10} {code:<15}")
else:
print(f"{rank:<4} {name:<25} {code:<15}")
# 强势概念TOP10
if change_col != 'code':
print(f"\n🚀 强势概念板块TOP10:")
for i, (_, concept) in enumerate(dc_concepts.head(10).iterrows()):
change_val = concept.get(change_col, 0)
if not pd.isna(change_val):
print(f" {i+1:2d}. {concept.get('name', 'N/A')}: {change_val:+.2f}%")
# 弱势概念TOP10
print(f"\n📉 弱势概念板块TOP10:")
weak_concepts = dc_concepts.tail(10).iloc[::-1] # 反转顺序
for i, (_, concept) in enumerate(weak_concepts.iterrows()):
change_val = concept.get(change_col, 0)
if not pd.isna(change_val):
print(f" {i+1:2d}. {concept.get('name', 'N/A')}: {change_val:+.2f}%")
else:
print(f"\n📋 概念板块列表前10个:")
for i, (_, concept) in enumerate(dc_concepts.head(10).iterrows()):
print(f" {i+1:2d}. {concept.get('name', 'N/A')} ({concept.get('ts_code', 'N/A')})")
return dc_concepts
except Exception as e:
logger.error(f"获取东财概念板块数据失败: {e}")
return None
except Exception as e:
logger.error(f"分析东财概念板块失败: {e}")
return None
def analyze_concept_trend(fetcher: TushareFetcher, concept_codes=None):
"""分析概念板块的趋势(多日对比)"""
try:
if not fetcher.pro:
logger.error("需要Tushare Pro权限")
return
logger.info("📊 分析概念板块趋势...")
# 获取最近5个交易日
trading_dates = get_recent_trading_dates(5)
# 如果没有指定概念代码获取当日表现最好的前10个
if concept_codes is None:
latest_concepts = analyze_eastmoney_concepts(fetcher)
if latest_concepts is not None and not latest_concepts.empty:
concept_codes = latest_concepts.head(5)['code'].tolist()
else:
logger.warning("无法获取概念代码")
return
print(f"\n" + "="*80)
print("📈 热门概念板块多日趋势分析")
print("="*80)
for concept_code in concept_codes:
concept_trend = []
for date in trading_dates:
try:
# 获取特定日期的概念数据
daily_data = fetcher.pro.dc_index(
trade_date=date,
ts_code=concept_code
)
if not daily_data.empty:
# 检查数据结构
logger.debug(f"概念 {concept_code}{date} 的数据字段: {list(daily_data.columns)}")
# 东财概念数据可能没有close字段使用其他字段替代
close_value = daily_data.iloc[0].get('total_mv', 1) # 使用总市值代替
if close_value == 0:
close_value = 1 # 避免除零
concept_trend.append({
'date': date,
'name': daily_data.iloc[0]['name'],
'close': close_value,
'pct_chg': daily_data.iloc[0]['pct_change']
})
except Exception as e:
logger.debug(f"获取概念 {concept_code}{date} 的数据失败: {e}")
continue
# 输出趋势
if concept_trend:
concept_name = concept_trend[0]['name']
print(f"\n📊 {concept_name} ({concept_code}) 近5日走势:")
# 计算总涨跌幅
if len(concept_trend) >= 2:
start_close = concept_trend[0]['close']
end_close = concept_trend[-1]['close']
if start_close != 0 and start_close is not None:
total_change = (end_close - start_close) / start_close * 100
print(f" 总涨跌幅: {total_change:+.2f}%")
else:
print(f" 总涨跌幅: 无法计算起始值为0")
# 显示每日数据
for data in concept_trend:
print(f" {data['date']}: {data['pct_chg']:+6.2f}% (指数: {data['close']:8.2f})")
print("\n" + "="*80)
except Exception as e:
logger.error(f"分析概念趋势失败: {e}")
def get_concept_constituents(fetcher: TushareFetcher, concept_code: str):
"""获取概念板块成分股"""
try:
if not fetcher.pro:
logger.error("需要Tushare Pro权限")
return
logger.info(f"获取概念 {concept_code} 的成分股...")
# 尝试通过概念板块获取成分股
try:
# 使用concept_detail接口如果可用
constituents = fetcher.pro.concept_detail(id=concept_code)
if not constituents.empty:
print(f"\n📋 概念成分股 ({len(constituents)}只):")
for _, stock in constituents.head(10).iterrows():
print(f" {stock['ts_code']}: {stock.get('name', 'N/A')}")
else:
logger.warning(f"概念 {concept_code} 无成分股数据")
except Exception as e:
logger.error(f"获取概念成分股失败: {e}")
except Exception as e:
logger.error(f"获取概念成分股失败: {e}")
def main():
"""主函数"""
logger.info("🚀 开始使用东财概念板块数据分析...")
# 初始化Tushare数据获取器
token = "0ed6419a00d8923dc19c0b58fc92d94c9a0696949ab91a13aa58a0cc"
fetcher = TushareFetcher(token=token)
# 1. 分析当日概念板块表现
concepts_data = analyze_eastmoney_concepts(fetcher)
# 2. 分析热门概念的多日趋势
if concepts_data is not None and not concepts_data.empty:
print("\n" + "="*80 + "\n")
# 获取表现最好的前3个概念进行趋势分析
top_concepts = concepts_data.head(3)['ts_code'].tolist()
analyze_concept_trend(fetcher, top_concepts)
# 3. 获取第一个概念的成分股示例
# top_concept_code = top_concepts[0] if top_concepts else None
# if top_concept_code:
# get_concept_constituents(fetcher, top_concept_code)
logger.info("✅ 分析完成!")
if __name__ == "__main__":
main()