manager.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. """
  2. 风险管理体系
  3. 整合仓位管理、风险预算、硬止损等功能
  4. """
  5. from dataclasses import dataclass
  6. from typing import Dict, List, Optional, Any
  7. from datetime import datetime
  8. from .position_sizing import AntifragilePositionSizer, PositionSize
  9. from .budget import RiskBudgetManager, BudgetState
  10. @dataclass
  11. class RiskCheckResult:
  12. """风险检查结果"""
  13. can_trade: bool
  14. allowed_position: float
  15. risk_level: str
  16. warnings: List[str]
  17. stop_loss_price: Optional[float] = None
  18. class RiskManager:
  19. """
  20. 风险管理者
  21. 整合所有风险管理组件:
  22. - 仓位管理
  23. - 风险预算
  24. - 组合级硬止损
  25. """
  26. def __init__(
  27. self,
  28. max_drawdown_stop: float = 0.15,
  29. max_daily_loss: float = 0.05,
  30. position_sizer: Optional[AntifragilePositionSizer] = None,
  31. budget_manager: Optional[RiskBudgetManager] = None
  32. ):
  33. self.max_drawdown_stop = max_drawdown_stop
  34. self.max_daily_loss = max_daily_loss
  35. self.position_sizer = position_sizer or AntifragilePositionSizer()
  36. self.budget_manager = budget_manager or RiskBudgetManager()
  37. # 状态追踪
  38. self.peak_value: float = 0.0
  39. self.current_drawdown: float = 0.0
  40. self.daily_pnl: float = 0.0
  41. self.last_reset_date: Optional[datetime] = None
  42. def check_trade_permission(
  43. self,
  44. account_value: float,
  45. proposed_position: float,
  46. entry_price: float
  47. ) -> RiskCheckResult:
  48. """
  49. 检查交易权限
  50. Returns:
  51. RiskCheckResult: 检查结果
  52. """
  53. warnings = []
  54. # 1. 检查风险预算
  55. if not self.budget_manager.check_can_trade():
  56. return RiskCheckResult(
  57. can_trade=False,
  58. allowed_position=0.0,
  59. risk_level="high",
  60. warnings=["风险预算已耗尽,处于冷却/停止期"]
  61. )
  62. # 2. 检查最大回撤 - 激进模式:允许50%仓位继续交易
  63. if self.current_drawdown <= -self.max_drawdown_stop:
  64. warnings.append(f"最大回撤已达到{self.max_drawdown_stop:.1%},限制仓位")
  65. proposed_position *= 0.5 # 允许50%仓位
  66. risk_level = "critical"
  67. # 3. 检查单日亏损
  68. if self.daily_pnl <= -account_value * self.max_daily_loss:
  69. warnings.append(f"单日亏损已达到{self.max_daily_loss:.1%},建议减仓")
  70. proposed_position *= 0.5
  71. # 4. 确定风险等级
  72. if self.current_drawdown <= -0.10:
  73. risk_level = "high"
  74. elif self.current_drawdown <= -0.05:
  75. risk_level = "medium"
  76. else:
  77. risk_level = "low"
  78. # 计算止损价格
  79. stop_loss = entry_price * 0.98 if proposed_position > 0 else None
  80. return RiskCheckResult(
  81. can_trade=True,
  82. allowed_position=proposed_position,
  83. risk_level=risk_level,
  84. warnings=warnings,
  85. stop_loss_price=stop_loss
  86. )
  87. def update_account_state(
  88. self,
  89. account_value: float,
  90. daily_pnl: Optional[float] = None
  91. ):
  92. """更新账户状态"""
  93. today = datetime.now().date()
  94. # 重置每日盈亏
  95. if self.last_reset_date != today:
  96. self.daily_pnl = 0.0
  97. self.last_reset_date = today
  98. if daily_pnl is not None:
  99. self.daily_pnl += daily_pnl
  100. # 更新峰值和回撤
  101. if account_value > self.peak_value:
  102. self.peak_value = account_value
  103. if self.peak_value > 0:
  104. self.current_drawdown = (account_value - self.peak_value) / self.peak_value
  105. def record_trade_result(self, trade_result: Dict):
  106. """记录交易结果"""
  107. # 更新风险预算
  108. if "realized_loss" in trade_result:
  109. self.budget_manager.record_trade_result(
  110. trade_result.get("trade_id", "unknown"),
  111. trade_result["realized_loss"]
  112. )
  113. # 更新账户状态
  114. if "pnl" in trade_result:
  115. self.update_account_state(
  116. trade_result.get("account_value", 0),
  117. trade_result["pnl"]
  118. )
  119. def get_risk_summary(self) -> Dict[str, Any]:
  120. """获取风险摘要"""
  121. return {
  122. "current_drawdown": self.current_drawdown,
  123. "daily_pnl": self.daily_pnl,
  124. "max_drawdown_stop": self.max_drawdown_stop,
  125. "budget_summary": self.budget_manager.get_budget_summary()
  126. }