Files
sanguo_quant_live/strategies/structured-dynamic-factors-20260327/policy_news_parser.py
T

381 lines
14 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.
"""
政策消息解析模块
功能:
1. 政策消息分类(货币/财政/产业/监管)
2. 政策力度分级
3. 受益板块识别
4. 政策驱动轮动信号生成
5. 利空政策预警
Author: 关羽(云长)
Date: 2026-03-27
"""
from dataclasses import dataclass
from typing import List, Dict, Optional, Tuple
from enum import Enum
import re
class PolicyType(Enum):
MONETARY = "货币政策"
FISCAL = "财政政策"
INDUSTRY = "产业政策"
REGULATORY = "监管政策"
MACRO = "宏观政策"
OTHER = "其他"
class PolicyStrength(Enum):
WEAK = 1
MEDIUM = 2
STRONG = 3
VERY_STRONG = 4
class PolicySentiment(Enum):
BULL = 1
NEUTRAL = 2
BEAR = 3
@dataclass
class PolicyNews:
"""政策消息"""
title: str
content: str
date: str
source: str
policy_type: PolicyType = PolicyType.OTHER
strength: PolicyStrength = PolicyStrength.MEDIUM
sentiment: PolicySentiment = PolicySentiment.NEUTRAL
affected_sectors: List[str] = None
keywords: List[str] = None
def __post_init__(self):
if self.affected_sectors is None:
self.affected_sectors = []
if self.keywords is None:
self.keywords = []
@dataclass
class PolicySignal:
"""政策轮动信号"""
sector: str
sentiment: PolicySentiment
strength: int
signal_date: str
reason: str
class PolicyClassifier:
"""政策消息分类器"""
# 关键词分类词典
TYPE_KEYWORDS = {
PolicyType.MONETARY: [
"降息", "降准", "货币政策", "流动性", "MLF", "LPR", "美联储", "加息",
"存款准备金", "公开市场操作", "Shibor", "利率"
],
PolicyType.FISCAL: [
"财政政策", "减税", "降费", "赤字", "专项债", "国债", "转移支付",
"积极财政", "财政刺激"
],
PolicyType.INDUSTRY: [
"扶持", "鼓励", "补贴", "规划", "纲要", "产业链", "新能源", "AI",
"半导体", "芯片", "消费", "汽车", "地产", "基建", "数字经济",
"高端制造", "生物医药", "绿色能源", "碳中和"
],
PolicyType.REGULATORY: [
"监管", "整治", "整顿", "约谈", "退市", "处罚", "反垄断", "立案",
"调查", "整改", "规范", "限购", "限跌", "双减", "教培"
],
PolicyType.MACRO: [
"GDP", "CPI", "PMI", "经济数据", "失业率", "经济增长", "通胀",
"经济会议", "中央经济工作", "两会", "政治局会议"
]
}
# 受益板块映射
SECTOR_KEYWORDS = {
"AI": ["AI", "人工智能", "大模型", "ChatGPT", "算力"],
"半导体": ["半导体", "芯片", "光刻机", "集成电路"],
"新能源": ["新能源", "光伏", "风电", "储能", "新能源车", "动力电池"],
"消费": ["消费", "内需", "促消费", "零售", "食品饮料"],
"医药": ["医药", "生物医药", "创新药", "医疗", "集采"],
"金融": ["金融", "银行", "证券", "券商", "保险"],
"地产": ["房地产", "地产", "楼市", "保交楼"],
"基建": ["基建", "新基建", "传统基建", "基础设施"],
"汽车": ["汽车", "新能源车", "汽车消费", "智能驾驶"],
"军工": ["军工", "国防", "武器装备"],
"农业": ["农业", "粮食", "种子", "乡村振兴"],
"环保": ["环保", "碳中和", "绿色发展", "碳达峰"]
}
def classify_type(self, text: str) -> PolicyType:
"""根据关键词分类政策类型"""
max_count = 0
best_type = PolicyType.OTHER
for ptype, keywords in self.TYPE_KEYWORDS.items():
count = sum(1 for kw in keywords if kw in text)
if count > max_count:
max_count = count
best_type = ptype
return best_type
def recognize_affected_sectors(self, text: str) -> List[str]:
"""识别受影响板块"""
affected = []
for sector, keywords in self.SECTOR_KEYWORDS.items():
for kw in keywords:
if kw in text:
affected.append(sector)
break
return affected
def judge_strength(self, text: str, sentiment: PolicySentiment) -> PolicyStrength:
"""判断政策力度"""
strong_words = ["全面", "大力", "全力", "重磅", "重大", "万亿", "千亿",
"顶格", "全面放开", "重磅推出", "重大利好"]
medium_words = ["稳步", "适度", "推进", "支持", "鼓励"]
weak_words = ["研究", "酝酿", "讨论", "草案", "征求意见"]
strong_count = sum(1 for w in strong_words if w in text)
weak_count = sum(1 for w in weak_words if w in text)
if strong_count >= 2:
return PolicyStrength.VERY_STRONG
elif strong_count >= 1:
return PolicyStrength.STRONG
elif weak_count >= 1:
return PolicyStrength.WEAK
else:
return PolicyStrength.MEDIUM
def judge_sentiment(self, text: str) -> PolicySentiment:
"""判断政策多空"""
bull_words = ["利好", "扶持", "鼓励", "支持", "发展", "推广", "优惠",
"补贴", "降税", "松绑", "放开"]
bear_words = ["监管", "整治", "限制", "禁止", "处罚", "退市", "打压",
"收紧", "加息", "降准", "调控", "整顿"]
bull_count = sum(1 for w in bull_words if w in text)
bear_count = sum(1 for w in bear_words if w in text)
if bull_count > bear_count:
return PolicySentiment.BULL
elif bear_count > bull_count:
return PolicySentiment.BEAR
else:
return PolicySentiment.NEUTRAL
class PolicySignalGenerator:
"""政策驱动轮动信号生成"""
def __init__(self):
self.classifier = PolicyClassifier()
def parse_news(self, news: PolicyNews) -> PolicyNews:
"""解析新闻,自动分类、判断力度和多空"""
full_text = news.title + news.content
news.policy_type = self.classifier.classify_type(full_text)
news.sentiment = self.classifier.judge_sentiment(full_text)
news.strength = self.classifier.judge_strength(full_text, news.sentiment)
news.affected_sectors = self.classifier.recognize_affected_sectors(full_text)
return news
def generate_signal(self, news_list: List[PolicyNews]) -> List[PolicySignal]:
"""根据多个政策生成板块轮动信号"""
sector_scores: Dict[str, int] = {}
for news in news_list:
# 解析后得到评分
strength_weight = news.strength.value
if news.sentiment == PolicySentiment.BULL:
score = strength_weight * 2
elif news.sentiment == PolicySentiment.BEAR:
score = -strength_weight * 2
else:
score = 0
for sector in news.affected_sectors:
sector_scores[sector] = sector_scores.get(sector, 0) + score
# 生成信号
signals = []
for sector, score in sector_scores.items():
if score > 0:
sentiment = PolicySentiment.BULL
elif score < 0:
sentiment = PolicySentiment.BEAR
else:
sentiment = PolicySentiment.NEUTRAL
signals.append(PolicySignal(
sector=sector,
sentiment=sentiment,
strength=abs(score),
signal_date=news_list[-1].date,
reason=f"累计政策评分{score}"
))
# 按强度排序
signals.sort(key=lambda x: x.strength, reverse=True)
return signals
class PolicyRiskAlert:
"""政策风险预警"""
# 高风险关键词
HIGH_RISK_KEYWORDS = [
"反垄断", "强监管", "整治", "集采", "退市", "立案调查", "约谈",
"处罚", "退市风险", "退市警示", "全面收紧", "加息超预期"
]
def check_risk(self, news: PolicyNews) -> Tuple[bool, int, str]:
"""
检查政策风险
返回:(是否高风险, 风险等级 1~3, 原因)
"""
full_text = news.title + news.content
risk_count = sum(1 for kw in self.HIGH_RISK_KEYWORDS if kw in full_text)
if news.sentiment == PolicySentiment.BEAR and news.strength.value >= 3:
return True, 3, f"{news.policy_type.value}利空,力度强,高度风险"
elif risk_count >= 2:
return True, 2, f"多个高风险关键词,中度风险"
elif risk_count >= 1:
return True, 1, f"存在风险关键词,轻度风险"
else:
return False, 0, "无明显政策风险"
class PolicyRotationModule:
"""政策驱动轮动总模块"""
def __init__(self):
self.signal_generator = PolicySignalGenerator()
self.risk_alert = PolicyRiskAlert()
self.parsed_news: List[PolicyNews] = []
def add_and_parse(self, news: PolicyNews) -> PolicyNews:
"""添加并解析政策新闻"""
parsed = self.signal_generator.parse_news(news)
self.parsed_news.append(parsed)
return parsed
def get_current_signals(self) -> List[PolicySignal]:
"""获取当前轮动信号"""
return self.signal_generator.generate_signal(self.parsed_news[-20:])
def get_risk_alerts(self) -> List[Tuple[str, int, str]]:
"""获取当前风险预警"""
alerts = []
for news in self.parsed_news[-10:]:
is_risk, level, reason = self.risk_alert.check_risk(news)
if is_risk:
alerts.append((f"{news.title} ({news.date})", level, reason))
return alerts
def get_rotation_report(self) -> str:
"""生成政策轮动报告"""
signals = self.get_current_signals()
alerts = self.get_risk_alerts()
lines = []
lines.append("=" * 60)
lines.append("政策驱动板块轮动报告")
lines.append("=" * 60)
lines.append(f"已解析政策数量: {len(self.parsed_news)}")
lines.append("")
if signals:
lines.append("🔔 当前板块信号:")
for sig in signals[:10]: # 只放前10个
sentiment_emoji = {
PolicySentiment.BULL: "🔼",
PolicySentiment.NEUTRAL: "",
PolicySentiment.BEAR: "🔽"
}
lines.append(f" {sentiment_emoji[sig.sentiment]} {sig.sector}: 强度={sig.strength}{sig.reason}")
lines.append("")
if alerts:
lines.append("⚠️ 政策风险预警:")
for title, level, reason in alerts:
lines.append(f" [{level}级风险] {title}: {reason}")
lines.append("")
if not signals and not alerts:
lines.append("无明确信号,保持观察")
lines.append("=" * 60)
return "\n".join(lines)
if __name__ == "__main__":
print("=== 测试政策消息解析模块 ===\n")
module = PolicyRotationModule()
# 测试案例1AI产业政策
news1 = PolicyNews(
title="重磅政策支持人工智能发展,算力基础设施加快建设",
content="近日,国务院印发《新一代人工智能发展规划》,全面支持人工智能产业发展,加大算力基础设施建设,对AI企业给予税收优惠。",
date="2026-03-27",
source="新华社"
)
parsed1 = module.add_and_parse(news1)
print(f"[测试1] {parsed1.title}")
print(f" 类型: {parsed1.policy_type.value}")
print(f" 力度: {parsed1.strength.name}")
print(f" 情绪: {parsed1.sentiment.name}")
print(f" 影响板块: {parsed1.affected_sectors}")
print()
# 测试案例2:监管政策
news2 = PolicyNews(
title="监管部门加强对互联网平台反垄断监管,约谈头部企业",
content="近日,市场监管总局对互联网平台企业反垄断问题开展专项整治,约谈头部三家企业要求整改,规范市场竞争秩序。",
date="2026-03-26",
source="证监会"
)
parsed2 = module.add_and_parse(news2)
print(f"[测试2] {parsed2.title}")
print(f" 类型: {parsed2.policy_type.value}")
print(f" 力度: {parsed2.strength.name}")
print(f" 情绪: {parsed2.sentiment.name}")
print()
# 测试案例3:降准
news3 = PolicyNews(
title="央行宣布全面降准0.5个百分点,释放长期资金一万亿",
content="中国人民银行决定下调金融机构存款准备金率0.5个百分点,释放长期资金约一万亿元,支持实体经济发展。",
date="2026-03-25",
source="央行官网"
)
parsed3 = module.add_and_parse(news3)
print(f"[测试3] {parsed3.title}")
print(f" 类型: {parsed3.policy_type.value}")
print(f" 力度: {parsed3.strength.name}")
print(f" 情绪: {parsed3.sentiment.name}")
print(f" 影响板块: {parsed3.affected_sectors}")
print()
# 生成报告
print(module.get_rotation_report())
# 风险预警测试
print("\n=== 风险预警测试 ===")
for n in module.parsed_news:
is_risk, level, reason = module.risk_alert.check_risk(n)
print(f"{n.title}: is_risk={is_risk}, level={level}, reason={reason}")