refactor(archive): move unused modules to archive/
Archive legacy framework and utility modules that are no longer referenced by the active core (datasource/ and rotation/): - framework/ -> archive/framework/ - framework_v2/ -> archive/framework_v2/ - strategies/ -> archive/strategies/ - config/ -> archive/config/ - visualization/ -> archive/visualization/ - scripts/ -> archive/scripts/ - tests/ -> archive/tests/ - run_rotation.py, run_us_rotation.py -> archive/single_files/ - compare_*.py, test_api_dates.py -> archive/single_files/
This commit is contained in:
143
archive/strategies/shared/risk/controls.py
Normal file
143
archive/strategies/shared/risk/controls.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
定制风控组件实现
|
||||
|
||||
这些风控组件继承framework.core.risk.RiskControl
|
||||
"""
|
||||
|
||||
from framework.risk import RiskControl, Position, CallbackHook
|
||||
|
||||
|
||||
class StopLossControl(RiskControl):
|
||||
"""止损控制(定制实现)"""
|
||||
|
||||
name = "stop_loss"
|
||||
|
||||
def __init__(self, threshold: float = -0.05, trailing: bool = False, trailing_percent: float = 0.03):
|
||||
super().__init__(threshold=threshold, trailing=trailing, trailing_percent=trailing_percent)
|
||||
self.threshold = threshold
|
||||
self.trailing = trailing
|
||||
self.trailing_percent = trailing_percent
|
||||
self._highest_price = {}
|
||||
|
||||
def check(self, position: Position, **kwargs) -> bool:
|
||||
"""检查是否触发止损"""
|
||||
if position is None:
|
||||
return True
|
||||
|
||||
if self.trailing:
|
||||
if position.code not in self._highest_price:
|
||||
self._highest_price[position.code] = position.entry_price
|
||||
self._highest_price[position.code] = max(
|
||||
self._highest_price[position.code],
|
||||
position.current_price
|
||||
)
|
||||
|
||||
if self.trailing:
|
||||
highest = self._highest_price[position.code]
|
||||
drawdown = (position.current_price - highest) / highest
|
||||
return drawdown > -self.trailing_percent
|
||||
else:
|
||||
return position.profit_ratio > self.threshold
|
||||
|
||||
def apply(self, position: Position):
|
||||
"""返回止损价格"""
|
||||
if self.trailing:
|
||||
highest = self._highest_price.get(position.code, position.entry_price)
|
||||
return highest * (1 - self.trailing_percent)
|
||||
else:
|
||||
return position.entry_price * (1 + self.threshold)
|
||||
|
||||
|
||||
class PositionLimitControl(RiskControl):
|
||||
"""仓位限制控制(定制实现)"""
|
||||
|
||||
name = "position_limit"
|
||||
|
||||
def __init__(self, max_position: float = 0.33, max_total: float = 1.0):
|
||||
super().__init__(max_position=max_position, max_total=max_total)
|
||||
self.max_position = max_position
|
||||
self.max_total = max_total
|
||||
|
||||
def check(self, position: Position, **kwargs) -> bool:
|
||||
"""检查仓位是否超限"""
|
||||
if position is None:
|
||||
return True
|
||||
|
||||
if position.weight > self.max_position:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def apply(self, position: Position):
|
||||
"""返回建议仓位"""
|
||||
return min(position.weight, self.max_position)
|
||||
|
||||
|
||||
class PremiumControl(RiskControl):
|
||||
"""溢价控制(定制实现)"""
|
||||
|
||||
name = "premium"
|
||||
|
||||
def __init__(self, threshold: float = 0.10, mode: str = 'filter'):
|
||||
super().__init__(threshold=threshold, mode=mode)
|
||||
self.threshold = threshold
|
||||
self.mode = mode
|
||||
|
||||
def check(self, position: Position, **kwargs) -> bool:
|
||||
"""检查溢价是否超限"""
|
||||
premium = kwargs.get('premium', 0)
|
||||
|
||||
if self.mode == 'filter':
|
||||
return premium <= self.threshold
|
||||
else:
|
||||
return True
|
||||
|
||||
def apply(self, position: Position):
|
||||
"""返回溢价惩罚系数"""
|
||||
if self.mode == 'penalize':
|
||||
return 0.5
|
||||
return None
|
||||
|
||||
|
||||
# 定制回调函数
|
||||
def premium_filter_callback(threshold: float = 0.10):
|
||||
"""溢价过滤回调(定制实现)"""
|
||||
def callback(code: str, price: float, **kwargs) -> bool:
|
||||
premium = kwargs.get('premium', 0)
|
||||
if premium > threshold:
|
||||
print(f"溢价过高,拒绝入场: {code} (溢价={premium:.2%})")
|
||||
return False
|
||||
return True
|
||||
return callback
|
||||
|
||||
|
||||
def crash_filter_callback(lookback: int = 3, crash_threshold: float = 0.05):
|
||||
"""崩盘过滤回调(定制实现)"""
|
||||
def callback(code: str, price: float, **kwargs) -> bool:
|
||||
history = kwargs.get('history', None)
|
||||
if history is None:
|
||||
return True
|
||||
|
||||
recent = history.tail(lookback)
|
||||
if len(recent) < lookback:
|
||||
return True
|
||||
|
||||
returns = recent['close'].pct_change()
|
||||
min_return = returns.min()
|
||||
|
||||
if min_return < -crash_threshold:
|
||||
print(f"崩盘检测,拒绝入场: {code} (最大跌幅={min_return:.2%})")
|
||||
return False
|
||||
return True
|
||||
return callback
|
||||
|
||||
|
||||
def holding_time_stoploss_callback(day_5_stoploss: float = -0.05, day_10_stoploss: float = -0.03):
|
||||
"""持仓时间动态止损回调(定制实现)"""
|
||||
def callback(position: Position) -> float:
|
||||
if position.holding_days >= 10:
|
||||
return day_10_stoploss
|
||||
elif position.holding_days >= 5:
|
||||
return day_5_stoploss
|
||||
return -0.10
|
||||
return callback
|
||||
Reference in New Issue
Block a user