easyquant/jq_channel.py

109 lines
3.9 KiB
Python
Raw Normal View History

2025-07-03 23:39:31 +08:00
from typing import Any, List
class exchange:
def close_positions(self, context: Any, position: Any):
"""
关闭所有持仓
"""
raise NotImplementedError("This method should be implemented by subclasses")
def buy_security(self, context: Any, target_list: List[str]) -> None:
"""
买入操作对目标股票执行买入下单资金均摊分配
"""
raise NotImplementedError("This method should be implemented by subclasses")
def open_position(self, security: str, value: float) -> bool:
"""
开仓操作尝试买入指定股票
参数:
security: 股票代码
value: 分配给该股票的资金
返回:
若下单成功部分或全部成交返回 True否则返回 False
"""
raise NotImplementedError("This method should be implemented by subclasses")
class jq_channel(exchange):
def __init__(self):
pass
def order_target_value_(self, stock: str, value: float) -> Any:
"""
封装 order_target_value 函数进行下单同时记录中文日志和异常信息
参数:
security: 股票代码
value: 下单目标金额
返回:
下单后生成的订单对象若失败返回 None
"""
try:
order = order_target_value(stock, value)
return order
except Exception as e:
return None
def close_positions(self, context: Any, position: Any):
"""
平仓操作尽可能将指定股票仓位全部卖出
参数:
position: 持仓对象
返回:
若下单后订单全部成交返回 True否则返回 False
"""
security = position.security
order = self.order_target_value_(security, 0)
if order is None:
# log.error(f"股票 {security} 下单失败可能是API调用错误")
return False
if order.status == OrderStatus.held and order.filled == order.amount:
# log.info(f"股票 {security} 卖出订单完全成交")
return True
else:
# log.warning(f"股票 {security} 卖出订单部分成交或未成交,状态: {order.status}, 已成交: {order.filled}/{order.amount}")
return False
def buy_security(self, context: Any, target_list: List[str]) -> None:
"""
买入操作对目标股票执行买入下单资金均摊分配
参数:
context: 聚宽平台传入的交易上下文对象
target_list: 目标股票代码列表
"""
position_count = len(context.portfolio.positions)
target_num = len(target_list)
if target_num > position_count:
try:
value = context.portfolio.cash / (target_num - position_count)
except ZeroDivisionError as e:
# log.error(f"资金分摊时除零错误: {e}")
return
for stock in target_list:
if context.portfolio.positions[stock].total_amount == 0:
if self.open_position(stock, value):
# log.info(f"已买入股票 {stock},分配资金 {value:.2f}")
# self.not_buy_again.append(stock)
if len(context.portfolio.positions) == target_num:
break
def open_position(self, security: str, value: float) -> bool:
"""
开仓操作尝试买入指定股票
参数:
security: 股票代码
value: 分配给该股票的资金
返回:
若下单成功部分或全部成交返回 True否则返回 False
"""
order = self.order_target_value_(security, value)
if order is not None and order.filled > 0:
return True
return False