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

318 lines
12 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
"""
测试同花顺概念板块数据
"""
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 explore_ths_interfaces(fetcher: TushareFetcher):
"""探索同花顺相关接口"""
try:
if not fetcher.pro:
logger.error("需要Tushare Pro权限")
return
logger.info("🔍 探索同花顺概念板块相关接口...")
# 1. 获取同花顺概念指数列表
try:
logger.info("1. 获取同花顺概念指数列表...")
ths_index = fetcher.pro.ths_index(exchange='A', type='N')
logger.info(f"获取到 {len(ths_index)} 个同花顺概念指数")
if not ths_index.empty:
print("\n📋 同花顺概念指数前20个")
print(f"{'代码':<15} {'名称':<30} {'发布日期':<12}")
print("-" * 60)
for _, index in ths_index.head(20).iterrows():
code = index['ts_code']
name = index['name'][:28] + '..' if len(index['name']) > 28 else index['name']
pub_date = index.get('list_date', 'N/A')
print(f"{code:<15} {name:<30} {pub_date:<12}")
return ths_index
except Exception as e:
logger.error(f"获取同花顺概念指数失败: {e}")
# 2. 尝试获取同花顺概念成分股
try:
logger.info("\n2. 测试获取同花顺概念成分股...")
# 尝试获取一个概念的成分股
sample_concept = "885311.TI" # 智能电网
ths_member = fetcher.pro.ths_member(ts_code=sample_concept)
logger.info(f"获取智能电网概念成分股: {len(ths_member)}")
if not ths_member.empty:
print(f"\n📊 智能电网概念成分股前10只")
for _, stock in ths_member.head(10).iterrows():
print(f" {stock['code']}: {stock.get('name', 'N/A')}")
except Exception as e:
logger.error(f"获取同花顺概念成分股失败: {e}")
# 3. 尝试获取同花顺概念日行情
try:
logger.info("\n3. 测试获取同花顺概念日行情...")
today = datetime.now().strftime('%Y%m%d')
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y%m%d')
ths_daily = fetcher.pro.ths_daily(
ts_code="885311.TI", # 智能电网
start_date=yesterday,
end_date=today
)
logger.info(f"获取智能电网概念日行情: {len(ths_daily)} 条记录")
if not ths_daily.empty:
print(f"\n📈 智能电网概念近期行情:")
print(ths_daily[['trade_date', 'close', 'pct_chg', 'vol']].head())
except Exception as e:
logger.error(f"获取同花顺概念日行情失败: {e}")
# 4. 探索其他可能的同花顺接口
try:
logger.info("\n4. 探索同花顺行业分类...")
ths_industry = fetcher.pro.ths_index(exchange='A', type='I')
logger.info(f"获取到 {len(ths_industry)} 个同花顺行业指数")
if not ths_industry.empty:
print(f"\n📊 同花顺行业指数前10个")
for _, index in ths_industry.head(10).iterrows():
print(f" {index['ts_code']}: {index['name']}")
except Exception as e:
logger.error(f"获取同花顺行业分类失败: {e}")
except Exception as e:
logger.error(f"探索同花顺接口失败: {e}")
def get_ths_concept_7day_ranking(fetcher: TushareFetcher):
"""获取同花顺概念板块过去7个交易日排名"""
try:
if not fetcher.pro:
logger.error("需要Tushare Pro权限")
return
logger.info("📊 计算同花顺概念板块过去7个交易日涨幅...")
# 获取同花顺概念指数列表
ths_concepts = fetcher.pro.ths_index(exchange='A', type='N')
if ths_concepts.empty:
logger.error("未获取到同花顺概念指数")
return
# 过滤掉指数型板块,只保留真正的概念板块
logger.info("过滤指数型板块...")
index_keywords = [
'成份股', '样本股', '成分股', '50', '100', '300', '500', '1000',
'上证', '深证', '中证', '创业板', '科创板', '北证',
'ETF', '指数', 'Index', '基准'
]
def is_concept_plate(name: str) -> bool:
"""判断是否为真正的概念板块"""
name_lower = name.lower()
for keyword in index_keywords:
if keyword.lower() in name_lower:
return False
return True
# 过滤数据
original_count = len(ths_concepts)
ths_concepts = ths_concepts[ths_concepts['name'].apply(is_concept_plate)]
filtered_count = len(ths_concepts)
logger.info(f"过滤结果: {original_count} -> {filtered_count} 个概念板块(剔除{original_count - filtered_count}个指数型板块)")
# 获取过去7个交易日
trading_dates = []
current = datetime.now()
while len(trading_dates) < 7:
if current.weekday() < 5: # 周一到周五
trading_dates.append(current.strftime('%Y%m%d'))
current -= timedelta(days=1)
trading_dates.reverse() # 升序排列,最早的日期在前
if len(trading_dates) < 2:
logger.warning("交易日不足")
return
start_date = trading_dates[0] # 7个交易日前
end_date = trading_dates[-1] # 最新交易日
logger.info(f"分析周期: {start_date}{end_date} (过去7个交易日)")
# 计算各概念的7日涨幅
concept_performance = []
# 限制分析数量避免API调用过多
sample_concepts = ths_concepts.head(50) # 分析前50个概念过滤后数量减少
logger.info(f"分析前 {len(sample_concepts)} 个同花顺概念...")
for _, concept in sample_concepts.iterrows():
ts_code = concept['ts_code']
name = concept['name']
try:
# 获取过去7个交易日行情数据
daily_data = fetcher.pro.ths_daily(
ts_code=ts_code,
start_date=start_date,
end_date=end_date
)
if not daily_data.empty:
# 检查数据结构
logger.debug(f"{name} 数据字段: {list(daily_data.columns)}")
if len(daily_data) >= 2:
# 按日期排序
daily_data = daily_data.sort_values('trade_date')
start_close = daily_data.iloc[0]['close']
end_close = daily_data.iloc[-1]['close']
if start_close > 0:
period_change = (end_close - start_close) / start_close * 100
# 检查涨跌幅字段名
pct_change_col = None
for col in ['pct_chg', 'pct_change', 'change']:
if col in daily_data.columns:
pct_change_col = col
break
latest_daily_change = daily_data.iloc[-1][pct_change_col] if pct_change_col else 0
concept_performance.append({
'ts_code': ts_code,
'name': name,
'period_change': period_change,
'start_close': start_close,
'end_close': end_close,
'latest_daily_change': latest_daily_change,
'trading_days': len(daily_data)
})
logger.debug(f"{name}: 过去7日{period_change:+.2f}%")
except Exception as e:
logger.debug(f"获取 {name} 数据失败: {e}")
continue
# 显示结果
if concept_performance:
df_ths = pd.DataFrame(concept_performance)
df_ths = df_ths.sort_values('period_change', ascending=False)
print(f"\n" + "="*80)
print("📈 同花顺概念板块过去7个交易日涨幅排行榜")
print("="*80)
print(f"{'排名':<4} {'概念名称':<30} {'7日涨幅':<12} {'今日涨幅':<12} {'指数代码':<15}")
print("-" * 80)
for i, (_, concept) in enumerate(df_ths.iterrows()):
rank = i + 1
name = concept['name'][:28] + '..' if len(concept['name']) > 28 else concept['name']
period_chg = f"{concept['period_change']:+.2f}%"
daily_chg = f"{concept['latest_daily_change']:+.2f}%"
ts_code = concept['ts_code']
print(f"{rank:<4} {name:<30} {period_chg:<12} {daily_chg:<12} {ts_code:<15}")
# 强势概念TOP15
print(f"\n🚀 同花顺强势概念TOP15:")
for i, (_, concept) in enumerate(df_ths.head(15).iterrows()):
print(f" {i+1:2d}. {concept['name']}: {concept['period_change']:+.2f}%")
# 弱势概念TOP10
print(f"\n📉 同花顺弱势概念TOP10:")
weak_concepts = df_ths.tail(10).iloc[::-1] # 反转顺序
for i, (_, concept) in enumerate(weak_concepts.iterrows()):
print(f" {i+1:2d}. {concept['name']}: {concept['period_change']:+.2f}%")
return df_ths
else:
logger.warning("未能计算同花顺概念涨幅")
except Exception as e:
logger.error(f"获取同花顺概念排名失败: {e}")
def compare_concept_sources(fetcher: TushareFetcher):
"""对比东财和同花顺概念数据"""
try:
logger.info("📊 对比东财 vs 同花顺概念数据...")
# 获取东财概念数量
today = datetime.now().strftime('%Y%m%d')
dc_concepts = fetcher.pro.dc_index(trade_date=today)
dc_count = len(dc_concepts) if not dc_concepts.empty else 0
# 获取同花顺概念数量
ths_concepts = fetcher.pro.ths_index(exchange='A', type='N')
ths_count = len(ths_concepts) if not ths_concepts.empty else 0
print(f"\n📊 概念板块数据源对比:")
print(f" 东财概念板块: {dc_count}")
print(f" 同花顺概念: {ths_count}")
# 数据特点对比
print(f"\n📈 数据特点对比:")
print(f" 东财概念:")
print(f" - 更新频率: 每日更新")
print(f" - 数据字段: 涨跌幅、市值、上涨下跌股数等")
print(f" - 适用场景: 实时概念轮动分析")
print(f" 同花顺概念:")
print(f" - 更新频率: 每日更新")
print(f" - 数据字段: 指数价格、涨跌幅、成交量等")
print(f" - 适用场景: 概念指数走势分析")
except Exception as e:
logger.error(f"对比概念数据源失败: {e}")
def main():
"""主函数"""
logger.info("🚀 开始探索同花顺概念板块数据...")
# 初始化Tushare数据获取器
token = "0ed6419a00d8923dc19c0b58fc92d94c9a0696949ab91a13aa58a0cc"
fetcher = TushareFetcher(token=token)
# 1. 探索同花顺接口
ths_index = explore_ths_interfaces(fetcher)
print("\n" + "="*80 + "\n")
# 2. 计算同花顺概念过去7个交易日排名
get_ths_concept_7day_ranking(fetcher)
print("\n" + "="*80 + "\n")
# 3. 对比数据源
compare_concept_sources(fetcher)
logger.info("✅ 探索完成!")
if __name__ == "__main__":
main()