候选池发布给择时决策系统(台账 004)

只写代码列表到共享 Redis 的 pms:candidates 键,择时侧的盘中强势扫描拿它当覆盖面。
走 Redis 不走接口:两侧本来就连着同一台盘中库,不新增网络方向、不涉及鉴权;失败模式
也良性,键没了就是那边本轮不扫,绝不回退全市场。写失败只记日志,不影响本轮扫描。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
zlt 2026-09-09 15:30:35 +08:00
parent 6f416ead6b
commit 11fbc36119
2 changed files with 53 additions and 2 deletions

View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
"""把今天的候选池代码写进共享 Redis, 给择时决策系统的盘中强势扫描当覆盖面 (2026-09-09, 台账 004)。
**只写一份, 只写代码** 不写分数不写理由不写价格 那些是 PMS 的内部判断,
择时侧要的只是"今天该盯哪几十只"
为什么走 Redis 不走接口: 两侧本来就连着同一台行情信号 Redis 的盘中库 (PMS 的信号消化
读它的盘中信号流, 择时侧写那条流), 不新增网络方向不涉及鉴权; 失败模式也良性
键没了就是择时侧本轮不扫, 它绝不会因此回退到全市场反过来让择时侧调 PMS 的计划接口,
要新造一条"择时到 PMS"的调用方向, 还要处理会话票签
写失败只记日志, **绝不影响扫描主流程** 这个键是给别人用的方便, 不是 PMS 自己的依赖
"""
from __future__ import annotations
import json
import logging
from datetime import datetime
from app.services import signal_service
logger = logging.getLogger("pms.candpub")
KEY = "pms:candidates:{ymd}"
TTL_SEC = 2 * 24 * 3600
def publish(codes) -> bool:
"""写今天的候选代码列表。返回是否写成功。"""
try:
arr = sorted({str(c).strip().upper() for c in (codes or []) if c})
if not arr:
return False
key = KEY.format(ymd=datetime.now().strftime("%Y%m%d"))
payload = json.dumps({"ymd": datetime.now().strftime("%Y%m%d"), "codes": arr,
"at": datetime.now().isoformat(timespec="seconds"),
"n": len(arr)}, ensure_ascii=False)
from config.settings import settings
signal_service._client(settings.SIGNAL_REDIS_DB_INTRADAY).set(key, payload, ex=TTL_SEC)
return True
except Exception as e:
logger.warning("[候选池发布] 写共享键失败 (不影响扫描): %s", e)
return False

View File

@ -39,8 +39,8 @@ from app.core import rule_gate
from app.core import signal_rules as sr from app.core import signal_rules as sr
from app.core import tradedays as td from app.core import tradedays as td
from app.repo import pms_repo from app.repo import pms_repo
from app.services import (command_service, executor, industry, judge, market, param_store, from app.services import (candidate_pub, command_service, executor, industry, judge, market,
reask_service, param_store, reask_service,
plan_feed, portfolio) plan_feed, portfolio)
logger = logging.getLogger("pms.proposal") logger = logging.getLogger("pms.proposal")
@ -160,6 +160,14 @@ def scan_and_route(*, now=None, dry_run: bool = False) -> dict:
logger.exception("新建仓扫描失败") logger.exception("新建仓扫描失败")
out["errors"].append(f"新建仓扫描失败: {type(e).__name__}: {e}") out["errors"].append(f"新建仓扫描失败: {type(e).__name__}: {e}")
out["open_candidates"] = len(open_cands) out["open_candidates"] = len(open_cands)
# 候选池发布给择时决策系统 (2026-09-09, 台账 004): 它的盘中强势扫描拿这份当覆盖面,
# 读不到就本轮不扫、绝不回退全市场。这里只写代码不写别的; 写失败只记日志, 不影响本轮。
# 落点选在候选产出之后、分流之前: 发布的是"今天该盯哪几只", 与它们最后买没买无关。
if not dry_run and open_cands:
try:
candidate_pub.publish([x.get("ts_code") for x in open_cands])
except Exception as e:
logger.warning("[新建仓] 候选池发布失败 (不影响本轮): %s", e)
# 研判的时间预算从这一刻起算。**先跑已有持仓的四类, 再跑新建仓** —— 预算真用尽时, # 研判的时间预算从这一刻起算。**先跑已有持仓的四类, 再跑新建仓** —— 预算真用尽时,
# 被推到下一跳的一定是新建仓, 已有持仓的动作行为与 2026-08-06 之前一致。 # 被推到下一跳的一定是新建仓, 已有持仓的动作行为与 2026-08-06 之前一致。