Files

85 lines
3.1 KiB
Python

"""
行业映射同步 — 从 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]