easyquant/task/check_positions_stop_loss_task.py

95 lines
4.9 KiB
Python
Raw Permalink Normal View History

2025-07-03 23:39:31 +08:00
from typing import Any
from kit.kit import DataHelper
from strategy import trade_strategy
from task.base_task import base_task
class check_positions_stop_loss_task(base_task):
def __init__(self, strategy: trade_strategy):
super().__init__(strategy)
def config(self, context: Any):
self.stoploss_switch = self.get_config('stoploss_switch') # 是否启用止损策略
self.hold_list = self.strategy.state.data['position_list'] # 持仓列表
self.today_trade_switch = self.get_config('today_trade_switch') # 今日交易开关
self.stoploss_strategy = self.get_config('stoploss_strategy') # 止损策略
self.stoploss_stock_rate_data = self.get_config('stoploss_stock_rate_data') # 个股止损阀值
self.stoploss_market_rate_data = self.get_config('stoploss_market_rate_data') # 市场止损阀值
2025-07-04 14:35:51 +08:00
# self.reason_to_sell = self.strategy.state.get_sell_reason() # 卖出原因
2025-07-03 23:39:31 +08:00
self.index_stocks = self.get_config('index_stocks') # 指数代码
2025-07-04 14:35:51 +08:00
self.temp_sells_list = {}
2025-07-03 23:39:31 +08:00
def run(self, context: Any):
if len(self.hold_list) == 0:
self.log.debug("当前无持仓,跳过止损检查。")
return
if self.stoploss_switch and self.today_trade_switch:
if self.stoploss_strategy == 1 or self.stoploss_strategy == 3:
# 个股止盈或止损判断
for stock in list(context.portfolio.positions.keys()):
pos = context.portfolio.positions[stock]
if pos.price >= pos.avg_cost * 2:
# 通过持仓监控器注册卖出请求,而不是直接卖出
2025-07-04 14:35:51 +08:00
# self.strategy.state.set_sell_request(stock, pos, 'take_profit')
2025-07-05 17:31:46 +08:00
self.sell_request(stock, pos, 'take_profit')
2025-07-03 23:39:31 +08:00
self.log.debug(f"股票 {stock} 实现100%盈利,执行止盈卖出。")
elif pos.price < pos.avg_cost * self.stoploss_stock_rate_data:
# 通过持仓监控器注册卖出请求,而不是直接卖出
self.strategy.state.set_sell_request(stock, pos, 'stop_loss')
2025-07-05 17:31:46 +08:00
self.sell_request(stock, pos, 'take_profit')
2025-07-03 23:39:31 +08:00
self.log.debug(f"股票 {stock} 触及止损阈值,执行卖出。")
2025-07-05 17:31:46 +08:00
# self.strategy.state.set_sell_reason("stoploss")
2025-07-03 23:39:31 +08:00
if self.stoploss_strategy == 2 or self.stoploss_strategy == 3:
# 大盘止损判断,若整体市场跌幅过大则平仓所有股票
stock_list = DataHelper.get_index_stocks(self.index_stocks)
df = DataHelper.get_price_safe(
stock_list,
end_date=context.previous_date,
frequency='daily',
fields=['close', 'open'],
count=1,
panel=False
)
if df is not None and not df.empty:
down_ratio = (df['close'] / df['open']).mean()
if down_ratio <= self.stoploss_market_rate_data:
2025-07-05 17:31:46 +08:00
# self.strategy.state.set_sell_reason("stoploss")
2025-07-03 23:39:31 +08:00
self.log.debug(f"市场检测到跌幅(平均跌幅 {down_ratio:.2%}),卖出所有持仓。")
for stock in list(context.portfolio.positions.keys()):
pos = context.portfolio.positions[stock]
# 通过持仓监控器注册卖出请求,而不是直接卖出
2025-07-04 14:35:51 +08:00
self.sell_request(stock, pos, 'market_stop_loss')
def handle(self, context: Any):
2025-07-06 17:42:06 +08:00
# 保存状态
for key, value in self.temp_sells_list.items():
stock, reason = key.split('_')
self.strategy.state.set_sell_request(stock, value, reason)
2025-07-04 14:35:51 +08:00
pass
def end(self, context: Any):
self.log.info("-----------------")
self.log.info("止损策略开关:{}".format("启用" if self.stoploss_switch else "不启用"))
2025-07-06 17:42:06 +08:00
self.log.info("今日交易开关:{}".format("交易" if self.today_trade_switch else "不交易"))
self.log.info("止损策略方式:{}".format("个股止损" if self.stoploss_strategy == 1 else "大盘止损" if self.stoploss_strategy == 2 else "联合止损" if
self.stoploss_strategy == 3 else "异常"))
2025-07-04 14:35:51 +08:00
self.log.info("当前卖出请求")
2025-07-06 17:42:06 +08:00
for key, value in self.temp_sells_list.items():
self.log.info(f" {key}: {value}")
# 总卖出请求
sells_list = self.strategy.state.get_sell_requests()
if len(sells_list) > 0:
self.log.info("总卖出请求:")
for stock, data in sells_list.items():
self.log.info(f" {stock}: {data}")
2025-07-04 14:35:51 +08:00
pass
2025-07-05 17:31:46 +08:00
def sell_request(self, stock, data, reason):
self.temp_sells_list[f"{stock}_{reason}"] = data