""" 风控预警和执行系统 功能: 1. 三级预警机制(黄/橙/红) 2. 预警触发后的执行规则 3. 三级风控体系(个股→板块→整体) 4. 执行记录留存,方便回测复盘 Author: 关羽(云长) Date: 2026-03-27 """ from dataclasses import dataclass from typing import List, Dict, Optional, Tuple, Callable from enum import Enum from datetime import datetime import json class WarningLevel(Enum): YELLOW = 1 # 黄色预警:观察 ORANGE = 2 # 橙色预警:减仓 RED = 3 # 红色预警:清仓 @dataclass class WarningMessage: """预警消息""" level: WarningLevel scope: str # individual / sector / portfolio target: str # code / sector name level_name: str reason: str timestamp: str current_position: float # 当前仓位 target_position: float # 目标仓位 executed: bool = False @dataclass class RiskWarningConfig: """风控预警参数配置""" # 个股预警阈值 yellow_threshold: float = 0.2 # 风险分0.2→黄 orange_threshold: float = 0.4 # 风险分0.4→橙 red_threshold: float = 0.7 # 风险分0.7→红 # 执行规则:仓位调整比例 yellow_reduce: float = 0.0 # 黄色不减仓 orange_reduce: float = 0.5 # 橙色减仓一半 red_reduce: float = 1.0 # 红色清仓 # 板块预警阈值 sector_warning_threshold: int = 10 # 风险积分10→黄 sector_orange_threshold: int = 25 # 积分25→橙 sector_red_threshold: int = 40 # 积分40→红 # 组合预警阈值 portfolio_yellow: float = 0.2 # 总分0.2→黄 portfolio_orange: float = 0.4 # 总分0.4→橙 portfolio_red: float = 0.7 # 总分0.7→红 default_config = RiskWarningConfig() class IndividualRiskWarning: """个股风险预警""" def __init__(self, config: RiskWarningConfig = None): self.config = config or default_config def evaluate(self, risk_score: float) -> WarningLevel: """根据风险分评估预警等级""" if risk_score >= self.config.red_threshold: return WarningLevel.RED elif risk_score >= self.config.orange_threshold: return WarningLevel.ORANGE elif risk_score >= self.config.yellow_threshold: return WarningLevel.YELLOW else: return None # 无预警 def calculate_target_position(self, current_position: float, level: WarningLevel) -> float: """计算目标仓位""" if level == WarningLevel.RED: return current_position * (1 - self.config.red_reduce) elif level == WarningLevel.ORANGE: return current_position * (1 - self.config.orange_reduce) elif level == WarningLevel.YELLOW: return current_position * (1 - self.config.yellow_reduce) else: return current_position class SectorRiskWarning: """板块风险预警""" def __init__(self, config: RiskWarningConfig = None): self.config = config or default_config def evaluate(self, risk_score: int) -> WarningLevel: if risk_score >= self.config.sector_red_threshold: return WarningLevel.RED elif risk_score >= self.config.sector_orange_threshold: return WarningLevel.ORANGE elif risk_score >= self.config.sector_warning_threshold: return WarningLevel.YELLOW else: return None def get_target_ratio(self, current_ratio: float, level: WarningLevel) -> float: """计算目标仓位比例""" if level == WarningLevel.RED: return current_ratio * 0.25 # 保留25% elif level == WarningLevel.ORANGE: return current_ratio * 0.5 # 保留一半 elif level == WarningLevel.YELLOW: return current_ratio # 不变 else: return current_ratio class PortfolioRiskWarning: """整体组合风险预警""" def __init__(self, config: RiskWarningConfig = None): self.config = config or default_config def evaluate(self, total_risk_score: float) -> WarningLevel: if total_risk_score >= self.config.portfolio_red: return WarningLevel.RED elif total_risk_score >= self.config.portfolio_orange: return WarningLevel.ORANGE elif total_risk_score >= self.config.portfolio_yellow: return WarningLevel.YELLOW else: return None def get_overall_target_ratio(self, level: WarningLevel) -> float: """整体目标仓位比例""" if level == WarningLevel.RED: return 0.25 # 保留25% elif level == WarningLevel.ORANGE: return 0.5 # 保留一半 elif level == WarningLevel.YELLOW: return 0.8 # 保留80% else: return 1.0 # 满仓 class RiskWarningSystem: """三级风控预警总系统(个股→板块→整体)""" def __init__(self, config: RiskWarningConfig = None): self.config = config or default_config self.individual_warn = IndividualRiskWarning(config) self.sector_warn = SectorRiskWarning(config) self.portfolio_warn = PortfolioRiskWarning(config) self.warning_history: List[WarningMessage] = [] self.execution_callback: Optional[Callable] = None def register_execution_callback(self, callback: Callable): """注册执行回调,预警触发后自动调用""" self.execution_callback = callback def evaluate_stock(self, code: str, name: str, risk_score: float, current_position: float) -> Optional[WarningMessage]: """评估个股风险,产生预警""" level = self.individual_warn.evaluate(risk_score) if level is None: return None target = self.individual_warn.calculate_target_position(current_position, level) level_names = { WarningLevel.YELLOW: "黄色", WarningLevel.ORANGE: "橙色", WarningLevel.RED: "红色" } msg = WarningMessage( level=level, scope="individual", target=f"{code} {name}", level_name=level_names[level], reason=f"个股风险分{risk_score:.2f},触发{level_names[level]}预警", timestamp=datetime.now().isoformat(), current_position=current_position, target_position=target ) self.warning_history.append(msg) return msg def evaluate_sector(self, name: str, risk_score: int, current_ratio: float) -> Optional[WarningMessage]: """评估板块风险,产生预警""" level = self.sector_warn.evaluate(risk_score) if level is None: return None target = self.sector_warn.get_target_ratio(current_ratio, level) level_names = { WarningLevel.YELLOW: "黄色", WarningLevel.ORANGE: "橙色", WarningLevel.RED: "红色" } msg = WarningMessage( level=level, scope="sector", target=name, level_name=level_names[level], reason=f"板块风险积分{risk_score},触发{level_names[level]}预警", timestamp=datetime.now().isoformat(), current_position=current_ratio, target_position=target ) self.warning_history.append(msg) return msg def evaluate_portfolio(self, total_risk_score: float) -> Optional[WarningMessage]: """评估整体组合风险""" level = self.portfolio_warn.evaluate(total_risk_score) if level is None: return None target_ratio = self.portfolio_warn.get_overall_target_ratio(level) level_names = { WarningLevel.YELLOW: "黄色", WarningLevel.ORANGE: "橙色", WarningLevel.RED: "红色" } msg = WarningMessage( level=level, scope="portfolio", target="整体组合", level_name=level_names[level], reason=f"组合总风险分{total_risk_score:.2f},触发{level_names[level]}预警", timestamp=datetime.now().isoformat(), current_position=1.0, # 当前总仓位比例 target_position=target_ratio ) self.warning_history.append(msg) return msg def get_pending_warnings(self) -> List[WarningMessage]: """获取未执行预警""" return [w for w in self.warning_history if not w.executed] def mark_executed(self, warning: WarningMessage): """标记已执行""" warning.executed = True def get_warning_report(self) -> str: """生成预警报告""" pending = self.get_pending_warnings() all_warnings = self.warning_history levels = { WarningLevel.YELLOW: "🟡 黄色", WarningLevel.ORANGE: "🟠 橙色", WarningLevel.RED: "🔴 红色", } lines = [] lines.append("=" * 60) lines.append("风控预警系统报告") lines.append("=" * 60) lines.append(f"总预警数量: {len(all_warnings)}") lines.append(f"未执行预警: {len(pending)}") lines.append("") if pending: lines.append("⚠️ 待执行预警:") for w in pending: lines.append(f" [{levels[w.level]}] [{w.scope}] {w.target}") lines.append(f" 原因: {w.reason}") lines.append(f" 当前仓位: {w.current_position:.2%} → 目标仓位: {w.target_position:.2%}") lines.append("") else: lines.append("✅ 无待执行预警") lines.append("=" * 60) return "\n".join(lines) def export_history(self, path: str): """导出预警历史到json,方便复盘""" data = [] for w in self.warning_history: data.append({ "level": w.level.value, "scope": w.scope, "target": w.target, "level_name": w.level_name, "reason": w.reason, "timestamp": w.timestamp, "current_position": w.current_position, "target_position": w.target_position, "executed": w.executed }) with open(path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) class RiskExecution: """风控执行器,根据预警执行调仓""" def __init__(self, warning_system: RiskWarningSystem): self.warning_system = warning_system def execute_warnings(self) -> List[dict]: """执行所有待执行预警""" pending = self.warning_system.get_pending_warnings() execution_records = [] for warning in pending: record = { "scope": warning.scope, "target": warning.target, "level": warning.level_name, "current": warning.current_position, "target": warning.target_position, "adjust_amount": warning.current_position - warning.target_position, "timestamp": warning.timestamp } execution_records.append(record) self.warning_system.mark_executed(warning) return execution_records def get_execution_report(self, records: List[dict]) -> str: """生成执行报告""" lines = [] lines.append("=" * 60) lines.append("风控执行报告") lines.append("=" * 60) lines.append(f"本次执行 {len(records)} 条预警") lines.append("") for r in records: lines.append(f"⚠️ [{r['level']}] {r['scope']} {r['target']}:") lines.append(f" 仓位调整: {r['current']:.2%} → {r['target']:.2%},需要卖出{r['adjust_amount']:.2%}") if not records: lines.append("✅ 无需要执行的调整") lines.append("=" * 60) return "\n".join(lines) if __name__ == "__main__": print("=== 测试风控预警和执行系统 ===\n") system = RiskWarningSystem(default_config) # 测试个股预警 msg1 = system.evaluate_stock("600000", "浦发银行", 0.45, 100000) msg2 = system.evaluate_stock("000001", "平安银行", 0.75, 150000) msg3 = system.evaluate_stock("002XXX", "AI龙头", 0.15, 80000) print("个股预警测试:") for msg in [msg1, msg2, msg3]: if msg: print(f" {msg.target}: {msg.level_name} → 当前{msg.current_position:.0f} → 目标{msg.target_position:.0f}") print() # 测试板块预警 s_msg1 = system.evaluate_sector("AI", 30, 0.22) s_msg2 = system.evaluate_sector("新能源", 15, 0.10) print("板块预警测试:") for msg in [s_msg1, s_msg2]: if msg: print(f" {msg.target}: {msg.level_name} → 当前{msg.current_position:.1%} → 目标{msg.target_position:.1%}") print() # 测试组合预警 p_msg = system.evaluate_portfolio(0.45) print(f"组合预警: {p_msg.level_name if p_msg else 'None'}") print() # 生成报告 print(system.get_warning_report()) print() # 执行预警 executor = RiskExecution(system) records = executor.execute_warnings() print(executor.get_execution_report(records))