""" 行业映射同步 — 从 QMT get_sector_list + get_stock_list_in_sector 获取 """ from datetime import date from core.scoring.sync.base import BaseSync from core.scoring.models import IndustryMapping from core.database import db from core.logger import LogLevel, PrintLog class IndustrySync(BaseSync): """行业映射同步 — QMT 行业板块 → IndustryMapping 表(全量替换)""" def _fetch(self, **kwargs): """从 QMT 拉取全部行业板块的成份股映射""" from xtquant import xtdata all_sectors = xtdata.get_sector_list() PrintLog(LogLevel.INFO, f'[sync] Industry: 共 {len(all_sectors)} 个板块') # 尝试使用 get_sector_info 过滤行业板块 industry_sectors = [] try: sector_info = xtdata.get_sector_info() if sector_info is not None and not sector_info.empty: for _, row in sector_info.iterrows(): cat = row.get('category', '') if '行业' in str(cat): industry_sectors.append(row['sector']) except Exception: pass # 如果 get_sector_info 无效,回退到名称过滤 if not industry_sectors: for s in all_sectors: # 排除明显非行业的板块 skip_markers = ['概念', '风格', '地域', '地区', '指数', '自定义', 'ETF', 'LOF', '债券', '基金', '期货', '期权'] if any(m in s for m in skip_markers): continue industry_sectors.append(s) PrintLog(LogLevel.INFO, f'[sync] Industry: 筛选出 {len(industry_sectors)} 个行业板块') # 构建 code → {industry_name, classification} 映射 mapping = {} # code → (industry_name, classification) today = date.today() for sector_name in industry_sectors: try: stocks = xtdata.get_stock_list_in_sector(sector_name) for full_code in stocks: code = full_code.split('.')[0] if code not in mapping: mapping[code] = { 'code': code, 'industry_name': sector_name, 'industry_classification': 'QMT', 'update_date': today, } except Exception: self.stats['errors'] += 1 self.stats['inserted'] = len(mapping) return list(mapping.values()) def _upsert(self, data: list): """全量替换: 清空旧数据 → 批量插入新数据""" if not data: PrintLog(LogLevel.WARNING, '[sync] Industry: 无数据, 跳过') return with db.atomic(): IndustryMapping.delete().execute() for batch in _chunked(data, 500): IndustryMapping.insert_many(batch).execute() PrintLog(LogLevel.INFO, f'[sync] Industry: 全量替换完成, {len(data)} 条映射') def _chunked(lst: list, n: int): for i in range(0, len(lst), n): yield lst[i:i + n]