模型,评分,修复网格策略市场状态监听
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
行业映射同步 — 从 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]
|
||||
Reference in New Issue
Block a user