feat: 初始提交 - 科创企业特有风险的识别与管理 (数智风控系统)
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
六维风险评分器
|
||||
整合所有数据源和分析结果,生成结构化六维风险画像
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# 风险等级映射
|
||||
RISK_LEVELS = {
|
||||
(0, 30): {"level": "低", "color": "#4CAF50", "emoji": "🟢"},
|
||||
(30, 50): {"level": "中低", "color": "#8BC34A", "emoji": "🟡"},
|
||||
(50, 70): {"level": "中高", "color": "#FF9800", "emoji": "🟠"},
|
||||
(70, 90): {"level": "高", "color": "#F44336", "emoji": "🔴"},
|
||||
(90, 101): {"level": "极高", "color": "#B71C1C", "emoji": "⛔"},
|
||||
}
|
||||
|
||||
|
||||
def get_risk_level(score: int) -> dict:
|
||||
"""根据分数获取风险等级详情"""
|
||||
for (low, high), info in RISK_LEVELS.items():
|
||||
if low <= score < high:
|
||||
return info
|
||||
return {"level": "未知", "color": "#9E9E9E", "emoji": "❓"}
|
||||
|
||||
|
||||
def calculate_six_dimension_scores(company_data: dict) -> dict:
|
||||
"""
|
||||
基于企业数据直接计算六维风险评分(不依赖 LLM)
|
||||
用于快速预览和规则引擎降级场景
|
||||
"""
|
||||
financials = company_data.get("financials", {})
|
||||
compliance = company_data.get("compliance", {})
|
||||
tech_route = company_data.get("tech_route", {})
|
||||
personnel = company_data.get("core_tech_personnel", [])
|
||||
supply_chain = company_data.get("supply_chain", {})
|
||||
|
||||
scores = {}
|
||||
|
||||
# 1. 技术路线颠覆风险
|
||||
competing = len(tech_route.get("competing_techs", []))
|
||||
moat = tech_route.get("tech_moat", "")
|
||||
tech_score = min(25 + competing * 15, 85)
|
||||
if "差距" in moat or "受制" in moat or "威胁" in moat:
|
||||
tech_score = min(tech_score + 15, 95)
|
||||
if "领先" in moat or "第一" in moat:
|
||||
tech_score = max(tech_score - 10, 10)
|
||||
scores["tech_disruption"] = tech_score
|
||||
|
||||
# 2. 核心人员流失风险
|
||||
departed = [p for p in personnel if "离职" in p.get("status", "")]
|
||||
high_imp = [p for p in personnel if p.get("importance") == "极高"]
|
||||
if departed:
|
||||
scores["talent_loss"] = 80
|
||||
elif len(high_imp) <= 1 and len(personnel) <= 2:
|
||||
scores["talent_loss"] = 55
|
||||
else:
|
||||
scores["talent_loss"] = 25
|
||||
|
||||
# 3. 算法/数据合规风险
|
||||
algo_status = compliance.get("algo_filing_status", "")
|
||||
data_risk = compliance.get("data_export_risk", "低")
|
||||
algo_score = 20
|
||||
if "未" in algo_status:
|
||||
algo_score = 75
|
||||
elif data_risk == "高":
|
||||
algo_score = 65
|
||||
elif data_risk == "中":
|
||||
algo_score = 40
|
||||
elif "已备案" in algo_status:
|
||||
algo_score = 15
|
||||
scores["algo_compliance"] = algo_score
|
||||
|
||||
# 4. 地缘政治/出口管制风险
|
||||
entity_status = compliance.get("entity_list_status", "")
|
||||
if "被列入" in entity_status:
|
||||
scores["geopolitical"] = 92
|
||||
elif supply_chain.get("supplier_concentration_risk") == "极高":
|
||||
scores["geopolitical"] = 68
|
||||
elif supply_chain.get("supplier_concentration_risk") == "高":
|
||||
scores["geopolitical"] = 50
|
||||
else:
|
||||
scores["geopolitical"] = 18
|
||||
|
||||
# 5. 研发资本化操纵风险
|
||||
cap_rate = financials.get("rd_capitalization_rate", 0)
|
||||
if cap_rate >= 0.4:
|
||||
scores["rd_capitalization"] = 90
|
||||
elif cap_rate >= 0.3:
|
||||
scores["rd_capitalization"] = 72
|
||||
elif cap_rate >= 0.15:
|
||||
scores["rd_capitalization"] = 48
|
||||
elif cap_rate > 0:
|
||||
scores["rd_capitalization"] = 25
|
||||
else:
|
||||
scores["rd_capitalization"] = 10
|
||||
|
||||
# 6. 客户/供应商集中风险
|
||||
cust_ratio = financials.get("top5_customer_ratio", 0)
|
||||
supp_ratio = financials.get("top5_supplier_ratio", 0)
|
||||
max_conc = max(cust_ratio, supp_ratio)
|
||||
if max_conc >= 0.8:
|
||||
scores["concentration"] = 88
|
||||
elif max_conc >= 0.6:
|
||||
scores["concentration"] = 68
|
||||
elif max_conc >= 0.4:
|
||||
scores["concentration"] = 42
|
||||
else:
|
||||
scores["concentration"] = 18
|
||||
|
||||
# 加权综合
|
||||
weights = {
|
||||
"tech_disruption": 0.20,
|
||||
"talent_loss": 0.15,
|
||||
"algo_compliance": 0.15,
|
||||
"geopolitical": 0.20,
|
||||
"rd_capitalization": 0.15,
|
||||
"concentration": 0.15,
|
||||
}
|
||||
comprehensive = int(sum(scores[k] * weights[k] for k in scores))
|
||||
|
||||
# 维度中文名映射
|
||||
dim_names = {
|
||||
"tech_disruption": "技术路线颠覆",
|
||||
"talent_loss": "核心人员流失",
|
||||
"algo_compliance": "算法/数据合规",
|
||||
"geopolitical": "地缘政治/出口管制",
|
||||
"rd_capitalization": "研发资本化操纵",
|
||||
"concentration": "客户/供应商集中",
|
||||
}
|
||||
|
||||
return {
|
||||
"scores": scores,
|
||||
"comprehensive_score": comprehensive,
|
||||
"risk_level": get_risk_level(comprehensive),
|
||||
"dimension_details": {
|
||||
k: {
|
||||
"name": dim_names[k],
|
||||
"score": v,
|
||||
"level": get_risk_level(v),
|
||||
"weight": weights[k],
|
||||
}
|
||||
for k, v in scores.items()
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user