244 lines
8.5 KiB
Python
244 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
按本周总涨幅排名东财概念板块
|
|
"""
|
|
|
|
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
|
|
|
|
# 生成本周所有交易日
|
|
dates = []
|
|
current = monday
|
|
while current <= friday:
|
|
if current.weekday() < 5: # 周一到周五
|
|
dates.append(current.strftime('%Y%m%d'))
|
|
current += timedelta(days=1)
|
|
|
|
return dates
|
|
|
|
|
|
def calculate_weekly_concept_performance(fetcher: TushareFetcher):
|
|
"""计算概念板块本周总涨幅"""
|
|
try:
|
|
if not fetcher.pro:
|
|
logger.error("需要Tushare Pro权限")
|
|
return None
|
|
|
|
logger.info("🚀 计算概念板块本周总涨幅排名...")
|
|
|
|
# 获取本周交易日
|
|
week_dates = get_this_week_dates()
|
|
logger.info(f"本周交易日: {week_dates}")
|
|
|
|
if len(week_dates) < 2:
|
|
logger.warning("本周交易日不足,无法计算周涨幅")
|
|
return None
|
|
|
|
start_date = week_dates[0] # 周一
|
|
end_date = week_dates[-1] # 最新交易日
|
|
|
|
logger.info(f"分析周期: {start_date} 到 {end_date}")
|
|
|
|
# 获取周一的概念板块数据(基准)
|
|
logger.info(f"获取 {start_date} 的概念数据作为基准...")
|
|
start_concepts = fetcher.pro.dc_index(trade_date=start_date)
|
|
|
|
# 获取最新交易日的概念板块数据
|
|
logger.info(f"获取 {end_date} 的概念数据...")
|
|
end_concepts = fetcher.pro.dc_index(trade_date=end_date)
|
|
|
|
if start_concepts.empty or end_concepts.empty:
|
|
logger.error("无法获取概念板块数据")
|
|
return None
|
|
|
|
logger.info(f"周一概念数据: {len(start_concepts)} 个")
|
|
logger.info(f"最新概念数据: {len(end_concepts)} 个")
|
|
|
|
# 计算本周涨幅
|
|
weekly_performance = []
|
|
|
|
# 以最新数据为准,匹配周一数据
|
|
for _, end_concept in end_concepts.iterrows():
|
|
ts_code = end_concept['ts_code']
|
|
name = end_concept['name']
|
|
end_mv = end_concept['total_mv']
|
|
|
|
# 查找对应的周一数据
|
|
start_data = start_concepts[start_concepts['ts_code'] == ts_code]
|
|
|
|
if not start_data.empty:
|
|
start_mv = start_data.iloc[0]['total_mv']
|
|
|
|
# 计算本周总涨幅
|
|
if start_mv > 0:
|
|
weekly_change = (end_mv - start_mv) / start_mv * 100
|
|
|
|
weekly_performance.append({
|
|
'ts_code': ts_code,
|
|
'name': name,
|
|
'weekly_change': weekly_change,
|
|
'start_mv': start_mv,
|
|
'end_mv': end_mv,
|
|
'latest_daily_change': end_concept['pct_change'],
|
|
'up_num': end_concept.get('up_num', 0),
|
|
'down_num': end_concept.get('down_num', 0)
|
|
})
|
|
|
|
if not weekly_performance:
|
|
logger.error("无法计算概念板块周涨幅")
|
|
return None
|
|
|
|
# 转换为DataFrame并按周涨幅排序
|
|
df_weekly = pd.DataFrame(weekly_performance)
|
|
df_weekly = df_weekly.sort_values('weekly_change', ascending=False)
|
|
|
|
logger.info(f"成功计算 {len(df_weekly)} 个概念板块的本周涨幅")
|
|
|
|
return df_weekly
|
|
|
|
except Exception as e:
|
|
logger.error(f"计算概念板块周涨幅失败: {e}")
|
|
return None
|
|
|
|
|
|
def display_weekly_ranking(df_weekly: pd.DataFrame):
|
|
"""显示本周涨幅排名"""
|
|
if df_weekly is None or df_weekly.empty:
|
|
logger.error("无数据可显示")
|
|
return
|
|
|
|
print("\n" + "="*100)
|
|
print("📈 东财概念板块本周涨幅排行榜")
|
|
print("="*100)
|
|
print(f"{'排名':<4} {'概念名称':<25} {'本周涨幅':<12} {'今日涨幅':<12} {'上涨股数':<8} {'下跌股数':<8} {'概念代码':<15}")
|
|
print("-" * 100)
|
|
|
|
for i, (_, concept) in enumerate(df_weekly.head(30).iterrows()):
|
|
rank = i + 1
|
|
name = concept['name'][:23] + '..' if len(concept['name']) > 23 else concept['name']
|
|
weekly_chg = f"{concept['weekly_change']:+.2f}%"
|
|
daily_chg = f"{concept['latest_daily_change']:+.2f}%"
|
|
up_num = f"{concept['up_num']:.0f}"
|
|
down_num = f"{concept['down_num']:.0f}"
|
|
ts_code = concept['ts_code']
|
|
|
|
print(f"{rank:<4} {name:<25} {weekly_chg:<12} {daily_chg:<12} {up_num:<8} {down_num:<8} {ts_code:<15}")
|
|
|
|
# 强势概念TOP15
|
|
print(f"\n🚀 本周强势概念板块TOP15:")
|
|
for i, (_, concept) in enumerate(df_weekly.head(15).iterrows()):
|
|
print(f" {i+1:2d}. {concept['name']}: {concept['weekly_change']:+.2f}% (今日{concept['latest_daily_change']:+.2f}%)")
|
|
|
|
# 弱势概念TOP10
|
|
print(f"\n📉 本周弱势概念板块TOP10:")
|
|
weak_concepts = df_weekly.tail(10).iloc[::-1] # 反转顺序
|
|
for i, (_, concept) in enumerate(weak_concepts.iterrows()):
|
|
print(f" {i+1:2d}. {concept['name']}: {concept['weekly_change']:+.2f}% (今日{concept['latest_daily_change']:+.2f}%)")
|
|
|
|
# 统计分析
|
|
print(f"\n📊 本周概念板块统计:")
|
|
total_concepts = len(df_weekly)
|
|
positive_concepts = len(df_weekly[df_weekly['weekly_change'] > 0])
|
|
negative_concepts = len(df_weekly[df_weekly['weekly_change'] < 0])
|
|
|
|
print(f" 总概念数量: {total_concepts}")
|
|
print(f" 上涨概念: {positive_concepts} ({positive_concepts/total_concepts*100:.1f}%)")
|
|
print(f" 下跌概念: {negative_concepts} ({negative_concepts/total_concepts*100:.1f}%)")
|
|
print(f" 平均涨幅: {df_weekly['weekly_change'].mean():+.2f}%")
|
|
print(f" 涨幅中位数: {df_weekly['weekly_change'].median():+.2f}%")
|
|
|
|
return df_weekly
|
|
|
|
|
|
def analyze_top_concepts_detail(fetcher: TushareFetcher, df_weekly: pd.DataFrame, top_n=5):
|
|
"""分析TOP概念的详细趋势"""
|
|
if df_weekly is None or df_weekly.empty:
|
|
return
|
|
|
|
logger.info(f"详细分析TOP{top_n}强势概念...")
|
|
|
|
print(f"\n" + "="*80)
|
|
print(f"📊 TOP{top_n}强势概念详细分析")
|
|
print("="*80)
|
|
|
|
week_dates = get_this_week_dates()
|
|
|
|
for i, (_, concept) in enumerate(df_weekly.head(top_n).iterrows()):
|
|
concept_code = concept['ts_code']
|
|
concept_name = concept['name']
|
|
|
|
print(f"\n📈 {i+1}. {concept_name} ({concept_code})")
|
|
print(f" 本周总涨幅: {concept['weekly_change']:+.2f}%")
|
|
|
|
# 获取每日详细数据
|
|
daily_data = []
|
|
for date in week_dates:
|
|
try:
|
|
daily_concept = fetcher.pro.dc_index(
|
|
trade_date=date,
|
|
ts_code=concept_code
|
|
)
|
|
|
|
if not daily_concept.empty:
|
|
daily_data.append({
|
|
'date': date,
|
|
'pct_change': daily_concept.iloc[0]['pct_change'],
|
|
'total_mv': daily_concept.iloc[0]['total_mv'],
|
|
'up_num': daily_concept.iloc[0].get('up_num', 0),
|
|
'down_num': daily_concept.iloc[0].get('down_num', 0)
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.debug(f"获取 {concept_code} 在 {date} 的数据失败: {e}")
|
|
continue
|
|
|
|
# 显示每日走势
|
|
if daily_data:
|
|
print(f" 每日走势:")
|
|
for data in daily_data:
|
|
print(f" {data['date']}: {data['pct_change']:+6.2f}% (上涨{data['up_num']:.0f}只/下跌{data['down_num']:.0f}只)")
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
logger.info("🚀 开始计算东财概念板块本周涨幅排名...")
|
|
|
|
# 初始化Tushare数据获取器
|
|
token = "0ed6419a00d8923dc19c0b58fc92d94c9a0696949ab91a13aa58a0cc"
|
|
fetcher = TushareFetcher(token=token)
|
|
|
|
# 1. 计算本周涨幅
|
|
df_weekly = calculate_weekly_concept_performance(fetcher)
|
|
|
|
# 2. 显示排名
|
|
if df_weekly is not None:
|
|
display_weekly_ranking(df_weekly)
|
|
|
|
# 3. 详细分析TOP5概念
|
|
analyze_top_concepts_detail(fetcher, df_weekly, top_n=5)
|
|
|
|
logger.info("✅ 分析完成!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |