tradingSystem/config/settings.py

185 lines
13 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.

# -*- coding: utf-8 -*-
"""
tradingSystem (PMS) 配置
========================
纪律 (沿袭 bionic_trader 踩坑经验):
1. 所有配置字段必须在 Settings 类中显式声明 —— pydantic 的 extra="ignore" 会静默忽略
未声明的环境变量, 这是历史头号坑。新增配置必须同时加字段。
2. 基础设施键名与 bionic_trader 对齐 (PROXY_DB_URL / SIGNAL_REDIS_* / SOURCE_DB_EXT_DSN
/ DB_MYSQL_URL), 同一份 .env 可服务两个系统。
3. 业务参数在此处只是「初值」: 页面修改后持久化到 pms_runtime_param 表,
运行时经 ParamStore 读取 (表值优先于本文件)。禁止在业务代码里直接
读 settings 取业务参数 —— 统一走 ParamStore, 保证页面调参即时生效。
"""
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
# =========================================================
# 一、基础设施 (键名对齐 bionic_trader, 同一 .env 可共用)
# =========================================================
PROXY_DB_URL: str = "mysql+pymysql://user:pass@192.168.16.153:3307/my_quant_db"
# 153 代理: pms_* 全部表 + trading_position / trading_order / trading_buy_plan /
# strategy_daily_results (决策系统结论) —— 严格单表访问, 代理禁多表联查
SOURCE_DB_EXT_DSN: str = "mysql+pymysql://user:pass@192.168.16.150:3306/factordb_mysql"
# 因子库直连。**PMS 当前不使用**: 因子分表 gp_stock_factor_pro_YYYYMM 经
# ShardingSphere 动态分配物理落点, 直连单台会在分片变动的月份漏表, 必须走
# PROXY_DB_URL 逐表单查 (沿用 bionic_trader 的踩坑结论)。保留本键仅为与 bionic
# 的 .env 对齐, 连不通不影响任何功能。
DB_MYSQL_URL: str = "mysql+pymysql://user:pass@192.168.18.199:3306/db_gp_cj"
# 大盘指数 zs_day_data (页面区制提示用, 非约束)
SIGNAL_REDIS_HOST: str = "192.168.18.208"
SIGNAL_REDIS_PORT: int = 6379
SIGNAL_REDIS_PASSWORD: str = ""
SIGNAL_REDIS_DB_INTRADAY: int = 2 # 决策系统盘中信号流 (PMS 订阅消化)
SIGNAL_REDIS_DB_ACTIONS: int = 3 # 决策系统风控 SELL 流 (PMS 订阅消化)
SIGNAL_REDIS_DB_QUOTES: int = 13 # 实时分钟行情 (择时/扫描)
SIGNAL_REDIS_SOCKET_TIMEOUT: int = 5
PMS_REDIS_URL: str = "redis://:pass@192.168.16.150:6379/8"
# PMS 自己的 Celery 总线, 独立 db=8 (决策系统用 db7, 物理同机逻辑隔离)
PMS_WEB_HOST: str = "0.0.0.0" # 管理页面 (FastAPI + 单页)
PMS_WEB_PORT: int = 38100
# =========================================================
# 二、业务参数「初值」(运行时以 pms_runtime_param 表为准, 页面可调)
# =========================================================
# --- 资金与总体 (对应参数命令) ---
PMS_TOTAL_SCALE: float = 2_000_000 # 总操作规模 (元)
PMS_PORTFOLIO_CAP: float = 0.60 # 总仓上限 (占规模)
PMS_STOCK_CAP: float = 0.08 # 单股上限
PMS_STOCK_TARGET_DEFAULT: float = 0.06 # 默认单股目标仓位
PMS_MAX_NAMES: int = 15 # 最大持仓数
PMS_CASH_RESERVE: float = 0.0 # 预留现金比例 (永不动用)
PMS_AUTONOMY: str = "propose_only" # full / propose_only / off
# --- 批次与安全垫 ---
PMS_BATCH_SPLIT: str = "0.5,0.25,0.25" # 底仓/回踩补足/盈利加仓
PMS_CUSHION_SOLID: float = 0.03 # 安全垫厚垫线 (解锁加仓)
PMS_TRIM_PEAK: float = 0.06 # 保垫减仓: 垫子峰值门槛
PMS_TRIM_GIVEBACK: float = 0.5 # 保垫减仓: 回吐比例门槛
PMS_DCA_TRIGGERS: str = "-0.08,-0.15" # 补仓评估档
PMS_DCA_DEEP_CONFIRM: float = -0.15 # 此档及更深永远需用户确认
PMS_DCA_MAX_RATIO: float = 0.5 # 补仓上限 (占底仓)
PMS_NO_CHASE_MA5: float = 0.06 # 距 MA5 超此幅度不追买
PMS_BUILD_WINDOW_TDAYS: int = 10 # 建仓期窗口 (交易日)
PMS_FILL_MAX_LOSS: float = -0.03 # 浮亏深于此不走回踩补足 (转补仓域)
PMS_WEAK_NEG_DAYS: int = 5 # 降仓「清弱票」判定: 安全垫连续为负 N 日 (设计 §3.2)
PMS_PROPOSAL_TTL_HOURS: int = 24 # 自主提议待确认有效期 (超时置 EXPIRED)
# --- 上游选股计划接口 (候选池的事实源; 口径与待确认项见 UPSTREAM_PLAN_API.md) ---
# 上游只回答「买什么、排第几」, 不给价格金额 —— 买多少/什么价是 PMS 自己算。
# 接口拿不到一律显式失败 (候选池为空 + ERROR), 绝不静默回退旧表。
PMS_CANDIDATE_SOURCE: str = "plan_api" # plan_api(默认) / buy_plan(旧表) / both(并集)
# 计划服务与 PMS 同机: 走 host.docker.internal (compose 里配了 host-gateway)。
# 容器直连宿主机物理 IP 192.168.16.155:8300 会被宿主机 INPUT 链丢包 (超时非拒绝);
# 若日后计划服务搬到别的机器, 这里直接填那台的 IP:端口。空=停用, 候选池恒为空。
PMS_PLAN_API_BASE: str = "http://host.docker.internal:8300"
PMS_PLAN_API_PATH: str = "/plan"
PMS_PLAN_TIMEOUT: int = 10 # 单次请求超时 (秒)
PMS_PLAN_CACHE_SEC: int = 300 # 计划缓存秒数 (上游日频产出, 没必要每跳都拉)
# 下面三个是**发给上游的请求参数** (对方 api.py: top=20/obs_top=10/theme_cap=5 都是
# 可传的, 不是它的既定政策)。0 = 不传, 用上游默认。要个宽池子回来, 主题分散交给
# PMS_PLAN_THEME_CAP_LOCAL 在候选阶段做 —— 理由见 plan_feed.select_candidates。
PMS_PLAN_TOP: int = 300 # 上游 top: 主榜要多少条
PMS_PLAN_OBS_TOP: int = 100 # 上游 obs_top: 观察档要多少条
PMS_PLAN_THEME_CAP: int = 999 # 上游 theme_cap: 让它别裁 (PMS 自己裁)
PMS_PLAN_THEME_CAP_LOCAL: int = 5 # PMS 侧同主题限额, 在 TOP_N 截断**之前**生效, 0=不限
PMS_PLAN_TOP_N: int = 30 # 主榜按 score 降序取前 N 进池 (900+ 只是排序池不是清单)
PMS_PLAN_TIERS: str = "强传导" # 传导档白名单; 留空=不按档过滤
PMS_PLAN_INCLUDE_OBSERVE: bool = False # 观察档是否进候选池 (上游把它定位为备选, 无 upside)
PMS_PLAN_MIN_SCORE: float = 0.0 # score 下限, 0=不设
PMS_PLAN_MIN_SOURCES: int = 0 # evidence.n_sources 下限, 0=不设
PMS_PLAN_MIN_UPSIDE: float = 0.0 # 预期空间下限 (0.5=+50%), 0=不设。券商目标价
# 口径, 噪音大 (榜首能到 +212%), 只做下限过滤, **不参与排序** —— 排序始终是 score
PMS_PLAN_STALE_TDAYS: int = 1 # 计划日龄超此交易日数即判过期并拒用 (防上游停更)
PMS_PLAN_THEME_SYNC: bool = True # 刷新时把 evidence.theme 灌进 pms_industry_map
PMS_PLAN_QUERY_EXTRA: str = "" # 附加查询串逃生口, 如 "foo=1"。上游哪天加了新参数
# 不用改代码即可透传; top/obs_top/theme_cap 已有显式参数, 同名键以显式参数为准
# --- 行业约束 (硬拦截; 数据源接口化) ---
PMS_SECTOR_SOURCE: str = "" # "" = 停用并页面提示 / custom_table / gp_stock_category
PMS_SECTOR_MAX_NAMES: int = 4
PMS_SECTOR_MAX_RATIO: float = 0.40 # 占总仓
# --- 择时执行 (内置实现B; 决策系统接通后切实现A) ---
PMS_EXEC_WINDOW_TDAYS: int = 3 # 任务命令默认执行窗口
PMS_SELL_AVOID_OPEN_MIN: int = 30 # 卖出避开开盘 N 分钟
PMS_BUY_HALT_DAYUP: float = 0.05 # 当日涨幅超此停止买入
PMS_EOD_FORCE_TIME: str = "14:45" # 当日配额兜底时点
PMS_EOD_FORCE_DISCOUNT: float = 0.998 # 兜底限价 = 现价 × 此系数 (卖出)
PMS_MIN_LOT_MERGE: bool = True # 一手检查: 批次自动合并
PMS_DISPATCH_EXPIRE_MIN: int = 30 # 指令下发后未被接受的过期时间
PMS_DISPATCH_MODE: str = "shadow" # 下发通道: shadow(影子,默认) / ws(直连QMT,待实现)
PMS_EXEC_SLICES: int = 1 # 当日配额分几笔出手 (设计「分笔卖出配额」)
PMS_ORDER_TTL_MIN: int = 10 # 单个下发分片的挂单有效期(交易分钟), 到点下游自动撤
# --- QMT WebSocket 直连通道 (协议见 QMT_WS_PROTOCOL.md V1.0) ---
# 连接由 pms-ws 常驻进程独占 (app/ws/runner.py); executor 经 pms_qmt_order
# 出口表递单, 详见 app/services/dispatcher.py 头部的「进程边界」一节。
PMS_QMT_WS_URL: str = "ws://192.168.16.98:9443/pms"
PMS_QMT_WS_ENABLED: bool = False # pms-ws 进程总开关; False = 空转不连接不写心跳
PMS_QMT_ACK_BATCH: int = 20 # 累积确认: 每落库 N 条发一次 ack_seq
PMS_QMT_ACK_INTERVAL_SEC: float = 2.0 # 累积确认: 或每 N 秒发一次 (取先到)
PMS_QMT_HEARTBEAT_SEC: int = 5 # ping 间隔
PMS_QMT_IDLE_TIMEOUT_SEC: int = 15 # 超过此时长未收到对端消息即重连
PMS_QMT_OUTBOX_POLL_SEC: float = 0.5 # 出口队列轮询间隔 (择时本是分钟级, 无需更快)
PMS_QMT_HEARTBEAT_DB_SEC: int = 2 # ws 进程写存活心跳的间隔
PMS_QMT_HEARTBEAT_STALE_SEC: int = 15 # 心跳陈旧超此秒数 → 判定进程已死, dispatcher 拒发
PMS_QMT_CONNECT_TIMEOUT_SEC: int = 10 # 建连超时
PMS_QMT_QUERY_INTERVAL_SEC: int = 300 # 全量快照轮询 query_positions+query_funds (协议 §6.2)
PMS_QMT_SEND_MAX_ATTEMPTS: int = 3 # 单张委托发送重试上限, 试满置 SEND_FAILED
# 下面两项是**密钥**: 只从 .env 注入, 不入库、不进 ParamStore、不上页面 (协议 §10.1.1)。
# param_store.SECRET_KEYS 已把它们挡在可调参数与页面快照之外。
PMS_QMT_SIGN_SEED_HEX: str = "" # PMS 私钥 seed (Ed25519, 32 字节 hex)
PMS_QMT_PEER_PUBKEY_B64: str = "" # QMT 公钥 (base64), 验上行签名用
# --- 风险披露与刹车 ---
PMS_RISK_WARN_ENTRY: float = 0.01 # 单笔敞口告警线 (占规模)
PMS_RISK_WARN_PORTFOLIO: float = 0.06 # 组合敞口告警线
PMS_BRAKE_DRAWDOWN: float = 0.05 # 组合刹车: 高水位回撤
PMS_BRAKE_DAYS: int = 3 # 刹车持续交易日
PMS_STOP_ATR_MULT: float = 2.0 # 自算止损参考: 成本 - N×ATR
PMS_REF_STALE_TDAYS: int = 3 # 决策系统结论日龄超此转自算兜底
# --- 研判闸 (委托决策系统) ---
PMS_JUDGE_ENABLED: bool = True
PMS_JUDGE_ACTIONS: str = "FILL,ADD,DCA,SWITCH"
PMS_JUDGE_TIMEOUT: int = 90 # 超时 → 降级 propose_only
PMS_JUDGE_API_BASE: str = "" # 决策系统 PMS 研判接口根地址; 空=未接通(自动降级人工确认)
PMS_JUDGE_PATH: str = "/api/intraday/pms_judge" # 研判接口路径 (bionic 侧配套改造后确定)
# --- T0 做T (命令授权制) ---
PMS_T0_RATIO_MAX: float = 0.333 # T仓硬上限 (占持仓)
PMS_T0_PULLBACK_PCT: float = 0.03 # 正T: 距当日高点回落触发
PMS_T0_RALLY_PCT: float = 0.05 # 反T: 日内涨幅触发
PMS_T0_ROUND_TARGET: float = 0.015 # 单次T目标价差
PMS_T0_CLOSE_TIME: str = "14:50" # 强制平回时点
PMS_T0_STOCK_DAY_LOSS: float = 0.003 # 单票当日T亏熔断 (占规模)
PMS_T0_GLOBAL_DAY_LOSS: float = 0.01 # 全局当日T亏熔断
# --- 决策系统信号消化 (设计 §10) ---
PMS_SIGNAL_ENABLED: bool = True
PMS_SIGNAL_GROUP: str = "pms_signal_consumer" # 独立消费组, 不与 trading_service 抢消息
PMS_SIGNAL_CONSUMER: str = "pms_1"
PMS_SIGNAL_STREAM_INTRADAY: str = "intraday_signals:{ymd}" # db2, 每日一条流
PMS_SIGNAL_STREAM_SELL: str = "bionic:signals:llm_sell_actions" # db3, 固定 key
PMS_SIGNAL_SELL_CONF_MIN: float = 0.75 # 低于此置信度的卖出信号不消化
PMS_SIGNAL_AUTO_EXIT_CONF: float = 0.85 # 高于此置信度直接转清仓指令, 之间则落提议
PMS_SIGNAL_TRIM_RATIO: float = 0.3333 # 中等置信度时的减仓比例
# --- 对账与回放 ---
PMS_REPLAY_INTERVAL_MIN: int = 5
PMS_RECON_ALARM_DAYS: int = 3 # 连续不一致 N 日升级 ERROR
# 持仓事实源: ws_first(默认, ws 快照为主/表为兜底) / ws_only / table_only
# 目标架构下 trading_service 全量退出业务, 那张表没有明确写入方; 协议 §6.2 定的也是 ws 快照。
PMS_RECON_SOURCE: str = "ws_first"
PMS_RECON_WS_SNAPSHOT_MAX_AGE_SEC: int = 900 # ws 快照超此秒数视为过期 (轮询 300s + 余量)
settings = Settings()