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/
143 lines
4.6 KiB
Python
143 lines
4.6 KiB
Python
"""
|
|
定制风控组件实现
|
|
|
|
这些风控组件继承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 |