#!/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()