Files
NewStock/qmt/qmt_signal_sender.py
liaozhaorun 29706da299 fix(qmt): 修复交易模块核心缺陷
- 修复重复的重连逻辑代码块,避免重复连接
- 修复卖出逻辑:增加实盘持仓校验,一切以实盘为准
- 修复幽灵持仓自动清理机制
- 修复消息处理的静默异常,添加完整日志记录
- 统一 qmt 模块所有静默处理问题
- 添加 qmt_signal_sender.py 信号发送器
- 生成 TODO_FIX.md 缺陷修复任务清单
2026-02-17 23:10:28 +08:00

101 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import redis
import json
import datetime
# --- 模块级全局变量 ---
_BACKTEST_SEND_COUNT = 0
def send_qmt_signal(code, target_total_slots, price, context, redis_config):
"""
发送信号到 Redis (基于槽位状态判断买卖意图)
参数:
- code: 股票代码 (聚宽格式: 000001.XSHE)
- target_total_slots:
* 意向持仓时: 传入策略设定的总槽位数 (例如 5)。此时 action 判定为 BUY。
* 意向清仓时: 传入 0。此时 action 判定为 SELL。
- price: 当前最新价格 (用于实盘限价单参考)
- context: 聚宽上下文对象
- redis_config: Redis配置字典
"""
global _BACKTEST_SEND_COUNT
try:
# ---------------------------------------------------------
# 1. 环境判断与流量控制
# ---------------------------------------------------------
run_type = context.run_params.type
is_backtest = run_type in ['simple_backtest', 'full_backtest']
if is_backtest:
if _BACKTEST_SEND_COUNT >= 10:
return
_BACKTEST_SEND_COUNT += 1
# ---------------------------------------------------------
# 2. 建立 Redis 连接
# ---------------------------------------------------------
r = redis.Redis(
host=redis_config['host'],
port=redis_config['port'],
password=redis_config.get('password'),
db=redis_config.get('db', 0),
decode_responses=True,
socket_timeout=1
)
# ---------------------------------------------------------
# 3. 数据转换与规范化
# ---------------------------------------------------------
# 股票代码格式转换: 聚宽(.XSHE/.XSHG) -> QMT(.SZ/.SH)
qmt_code = code
if code.endswith('.XSHE'):
qmt_code = code.replace('.XSHE', '.SZ')
elif code.endswith('.XSHG'):
qmt_code = code.replace('.XSHG', '.SH')
# 【核心逻辑修改】:根据 target_total_slots 判断动作
# 不再通过函数名判断,而是看目标状态
if target_total_slots > 0:
action = 'BUY'
slots_val = int(target_total_slots) # 告知后端我是基于“N只模型”中的一只
else:
action = 'SELL'
slots_val = 0 # 清仓
# ---------------------------------------------------------
# 4. 构建消息体
# ---------------------------------------------------------
base_strategy_name = redis_config.get('strategy_name', 'default_strategy')
ts_str = context.current_dt.strftime('%Y-%m-%d %H:%M:%S')
msg = {
'strategy_name': base_strategy_name,
'stock_code': qmt_code,
'action': action,
'price': price,
'total_slots': slots_val,
'timestamp': ts_str,
'is_backtest': is_backtest
}
json_payload = json.dumps(msg)
# ---------------------------------------------------------
# 5. 队列路由
# ---------------------------------------------------------
queue_key = f"{base_strategy_name}_backtest" if is_backtest else f"{base_strategy_name}_real"
expire_seconds = 3600 if is_backtest else 604800
r.rpush(queue_key, json_payload)
r.expire(queue_key, expire_seconds)
# ---------------------------------------------------------
# 6. 控制台输出
# ---------------------------------------------------------
log_prefix = "【回测】" if is_backtest else "【实盘】"
desc = f"目标总持仓:{slots_val}" if action == 'BUY' else "清仓释放槽位"
print(f"{log_prefix} 信号同步 -> {qmt_code} | 动作:{action} | {desc} | 时间:{ts_str}")
except Exception as e:
print(f"[Error] 发送QMT信号失败: {e}")