287 lines
20 KiB
Python
287 lines
20 KiB
Python
"""连接配置与运行旋钮:全部从环境变量/.env 读取,不硬编码任何主机。
|
||
|
||
三处连接:
|
||
AKG_PG_* —— astock-kg 基座 PostgreSQL(读只读视图,只读账号即可)
|
||
HEAT_MYSQL_* —— 153 代理 MySQL(读 stock_fund_heat_scores 热度)
|
||
FACTOR_MYSQL_* —— 平台 PROXY_DB_URL 指向的 MySQL(写 t_factor_* + factor_metadata)
|
||
现价来源 PRICE_MYSQL_*(upside 用)默认复用 FACTOR_MYSQL_* 同实例。
|
||
"""
|
||
import os
|
||
from dataclasses import dataclass
|
||
|
||
try:
|
||
from dotenv import load_dotenv
|
||
load_dotenv()
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def _req(k: str) -> str:
|
||
v = os.environ.get(k)
|
||
if not v:
|
||
raise RuntimeError(f".env 缺配置: {k}")
|
||
return v
|
||
|
||
|
||
def _opt(k: str, fallback: str) -> str:
|
||
return os.environ.get(k) or fallback
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Conn:
|
||
host: str
|
||
port: int
|
||
user: str
|
||
password: str
|
||
db: str
|
||
|
||
|
||
def akg_pg() -> Conn:
|
||
return Conn(_req("AKG_PG_HOST"), int(os.environ.get("AKG_PG_PORT", 5432)),
|
||
_req("AKG_PG_USER"), os.environ.get("AKG_PG_PASSWORD", ""), _req("AKG_PG_DB"))
|
||
|
||
|
||
def heat_mysql() -> Conn:
|
||
return Conn(_req("HEAT_MYSQL_HOST"), int(os.environ.get("HEAT_MYSQL_PORT", 3306)),
|
||
_req("HEAT_MYSQL_USER"), os.environ.get("HEAT_MYSQL_PASSWORD", ""), _req("HEAT_MYSQL_DB"))
|
||
|
||
|
||
def factor_mysql() -> Conn:
|
||
return Conn(_req("FACTOR_MYSQL_HOST"), int(os.environ.get("FACTOR_MYSQL_PORT", 3306)),
|
||
_req("FACTOR_MYSQL_USER"), os.environ.get("FACTOR_MYSQL_PASSWORD", ""), _req("FACTOR_MYSQL_DB"))
|
||
|
||
|
||
def price_mysql() -> Conn:
|
||
"""现价(gp_day_data)来源,默认与因子库同实例。"""
|
||
return Conn(_opt("PRICE_MYSQL_HOST", _req("FACTOR_MYSQL_HOST")),
|
||
int(_opt("PRICE_MYSQL_PORT", os.environ.get("FACTOR_MYSQL_PORT", "3306"))),
|
||
_opt("PRICE_MYSQL_USER", _req("FACTOR_MYSQL_USER")),
|
||
_opt("PRICE_MYSQL_PASSWORD", os.environ.get("FACTOR_MYSQL_PASSWORD", "")),
|
||
_opt("PRICE_MYSQL_DB", _req("FACTOR_MYSQL_DB")))
|
||
|
||
|
||
def pms_mysql() -> Conn:
|
||
"""读持仓(首选 PMS 账本 pms_position,下游 trading_position 兜底)与决策系统
|
||
结论(strategy_daily_results),入池用。这几张表都在 153 代理后面——与热度是
|
||
同一台,默认直接复用 HEAT_MYSQL_*,只有代理路由不通时才需要单独配 PMS_MYSQL_*。"""
|
||
return Conn(_opt("PMS_MYSQL_HOST", _req("HEAT_MYSQL_HOST")),
|
||
int(_opt("PMS_MYSQL_PORT", os.environ.get("HEAT_MYSQL_PORT", "3306"))),
|
||
_opt("PMS_MYSQL_USER", _req("HEAT_MYSQL_USER")),
|
||
_opt("PMS_MYSQL_PASSWORD", os.environ.get("HEAT_MYSQL_PASSWORD", "")),
|
||
_opt("PMS_MYSQL_DB", _req("HEAT_MYSQL_DB")))
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class MongoConn:
|
||
host: str
|
||
port: int
|
||
user: str
|
||
password: str
|
||
db: str
|
||
|
||
|
||
def mongo() -> MongoConn:
|
||
"""选股计划入池的落点(决策系统每晚扫描读同一处)。"""
|
||
return MongoConn(_req("MONGO_HOST"), int(os.environ.get("MONGO_PORT", 27017)),
|
||
_req("MONGO_USERNAME"), os.environ.get("MONGO_PASSWORD", ""),
|
||
_opt("MONGO_DB", "stock_predictions"))
|
||
|
||
|
||
# gp_day_data 股票代码列名(平台实测 = symbol;代码仍会自动兜底逐个试)
|
||
PRICE_CODE_COL = os.environ.get("PRICE_CODE_COL", "ts_code")
|
||
FACTOR_API_BASE = os.environ.get("FACTOR_API_BASE", "").rstrip("/")
|
||
|
||
|
||
# ============================================================================
|
||
# 运行旋钮(2026-07-26 评审引入)。全部有默认值,不填也能跑。
|
||
# ============================================================================
|
||
|
||
# --- 子因子是否受覆盖池限制:pool(现状)| market(评审 §4 建议)------------
|
||
# industry_pools 只存最新态、每周一 refresh_pools 自动长大。用它过滤**历史**子因子
|
||
# 会引入成员性前视(值点时正确、成员性前视——这是 §2.2 批传导用的同一条论证,
|
||
# 上升了一层),且截面统计量每周一结构性跳变。
|
||
# 子因子表的定位是「可独立观察的仪表」,过滤应发生在消费端(akg_score),不在这里。
|
||
# 传导不受此开关影响——它天生就是池内语义。
|
||
SUBFACTOR_UNIVERSE = os.environ.get("SUBFACTOR_UNIVERSE", "pool").strip().lower()
|
||
|
||
# --- 行情读取按月分块 -------------------------------------------------------
|
||
# 原来一次拉全区间,`--mode history --start 2006-01-01` 会把千万级行拉进 pandas。
|
||
PRICE_CHUNK_DAYS = int(os.environ.get("PRICE_CHUNK_DAYS", "31"))
|
||
|
||
# --- 因子表写入分块行数 -----------------------------------------------------
|
||
# 热度全史约 322×1674≈54 万行,原来单事务 executemany 走 ShardingSphere 代理有风险。
|
||
WRITE_CHUNK_ROWS = int(os.environ.get("WRITE_CHUNK_ROWS", "50000"))
|
||
|
||
# --- 事件来源白名单与单文档封顶(评审 §6.5:年报污染)----------------------
|
||
# documents.source_type 取值(astock-kg db/postgres/init.sql:12 已核实):
|
||
# annual_report / research_report / announcement / news / interactive_qa
|
||
# 年报也带 company_ts_code 文档锚,而一份年报能抽十几条 EVENT,且含**历史**诉讼/
|
||
# 处罚——会在年报披露日形成巨大负值尖峰。S2 若用 akg_event < −θ_e 做否决闸,
|
||
# 会因为一份年报提到历史诉讼而否决掉一只好股。默认只认公告。
|
||
EVENT_SOURCE_TYPES = {
|
||
s.strip() for s in
|
||
os.environ.get("EVENT_SOURCE_TYPES", "announcement").split(",") if s.strip()}
|
||
EVENT_MAX_PER_DOC = int(os.environ.get("EVENT_MAX_PER_DOC", "3"))
|
||
|
||
# --- 输入冻结落点(freeze.py)----------------------------------------------
|
||
# 容器内路径;docker-compose 已把仓库根挂到 /app,故默认落在仓库的 data/frozen/。
|
||
FROZEN_ROOT = os.environ.get("FROZEN_ROOT", "/app/data/frozen")
|
||
|
||
# --- 上游截断体检阈值(评审 硬伤1)-----------------------------------------
|
||
# 基座 graph_store.topic_context 的 Cypher 是 `LIMIT $cap`(默认 30)且无 ORDER BY;
|
||
# transmission.scan 落库时又有 `quiet[:12]`。命中这两个数就说明上游被截断了,
|
||
# 该行的 moved_ratio 建立在任意抽样上、覆盖也被展示逻辑锁住。
|
||
# 07-28 语义更新:基座二批后 topic_context cap=1000、scan 大主题闸=600、quiet 全量落库。
|
||
# 本值对齐基座"大主题闸":members_total 超过它 = 基座制度回退,桥侧告警(factors.py)。
|
||
UPSTREAM_MEMBER_CAP = int(os.environ.get("UPSTREAM_MEMBER_CAP", "600"))
|
||
|
||
# --- 赛道门槛 C(G2:config/frontier_tracks.yml + tracks.py)-----------------
|
||
# yml 是唯一事实源(设计 §3.2)。C 闸默认关:映射还是 v0.1 草案,先跑
|
||
# `python run.py tracks` 做覆盖体检、清单转正后再置 1——届时主榜(gate=2)
|
||
# 再交赛道成员,观察档的产业链锚也并入赛道成员。
|
||
TRACKS_YML = os.environ.get("TRACKS_YML", "config/frontier_tracks.yml")
|
||
ENABLE_TRACK_GATE = os.environ.get("ENABLE_TRACK_GATE", "0") == "1"
|
||
|
||
# --- 重大风险股闸(07-31 拍板:默认杜绝)-------------------------------------
|
||
# ST / *ST / S(S)T / 退市族按证券简称识别,默认挡在档位之外——gate 记 0(不采纳),
|
||
# 因此不进主榜、观察档、计划与升降档。研究口径想看全貌时置 0 关闭。
|
||
EXCLUDE_RISK_NAMES = os.environ.get("EXCLUDE_RISK_NAMES", "1") == "1"
|
||
|
||
# --- 预期空间否决的负容忍(2026-08-17 拍板:默认否决,参数控制)----------------
|
||
# 主榜判据原文是「upside >= 0,贵了不买是绝对下限」。默认 0.0 = 与拍板逐字一致。
|
||
# 背景:upside 是"报喜不报忧"的噪音口径(下游文档明写"当相对排序用"),传导强而
|
||
# upside 轻微为负的票会整只消失(实例:太极实业传导分 1.89、两源指向,因 -52% 被否
|
||
# ——这个量级该否;但 -3% 也同样消失)。把阈值放开到如 0.10,即 upside >= -10% 仍进
|
||
# 主榜,组内分的 0.4·z(upside) 自然把它压到组内低位(只降权不否决)。是否放开、放多少,
|
||
# 等 score_lab 对比器跑出数据再定;改这个值属于口径变更,改前先看对比器读数。
|
||
UPSIDE_NEG_TOLERANCE = float(os.environ.get("UPSIDE_NEG_TOLERANCE", "0"))
|
||
|
||
# --- 统一任务调度平台触发(08-03;键名与决策系统保持一致,便于平台侧统一配置)----
|
||
# 空串 = /api/v1/xxl/* 整组端点禁用(安全默认)。回调契约见 xxl.py 模块说明。
|
||
XXL_TRIGGER_KEY = os.environ.get("XXL_TRIGGER_KEY", "")
|
||
XXL_CALLBACK_READ_TIMEOUT = float(os.environ.get("XXL_CALLBACK_READ_TIMEOUT", "10"))
|
||
XXL_CALLBACK_MAX_RETRIES = int(os.environ.get("XXL_CALLBACK_MAX_RETRIES", "3"))
|
||
|
||
# --- 选股计划入池(08-03 定稿;规则与流程见 docs/选股计划入池_对接说明.md)------
|
||
# 写 Mongo stock_groups 的独立分组,决策系统每晚扫描按分组并集覆盖 → 候选票自动
|
||
# 获得夜间推理。入池范围与 PMS 候选**次序口径**一致:先筛强传导、再按绝对得分截断
|
||
# (2026-08-17 拍板:分散不由选层做,主题限额默认关,组合分散归 PMS 的行业闸)。
|
||
# 池深允许比 PMS 候选浅——POOL_TOP 直接决定决策系统每晚推理量(每只两三分钟),
|
||
# 想跟 PMS_PLAN_TOP_N 拉平就同步调大 POOL_MAX 并接受夜扫时长变长。
|
||
POOL_GROUP_CODE = os.environ.get("POOL_GROUP_CODE", "AKG_PLAN")
|
||
POOL_GROUP_NAME = os.environ.get("POOL_GROUP_NAME", "AKG每日选股计划池")
|
||
POOL_ORG_ID = os.environ.get("POOL_ORG_ID", "489281497140")
|
||
POOL_COLLECTION = os.environ.get("POOL_COLLECTION", "stock_groups")
|
||
POOL_RECYCLE_COLLECTION = os.environ.get("POOL_RECYCLE_COLLECTION", "stock_recycle_bin")
|
||
POOL_TOP = int(os.environ.get("POOL_TOP", "20"))
|
||
# 入池主题限额。默认 0 = 不限(2026-08-17:分散不由选层体现);配非零值即应急回退旧行为。
|
||
POOL_THEME_CAP = int(os.environ.get("POOL_THEME_CAP", "0"))
|
||
# 档位白名单(逗号分隔;空串=主榜全部)。默认只收强传导——候选宁缺毋滥。
|
||
POOL_TIERS = {s.strip() for s in os.environ.get("POOL_TIERS", "强传导").split(",") if s.strip()}
|
||
# 池子上限:计划+持仓+留池观察合计超过它时,从留池观察里清最久没上榜的。
|
||
# 上限直接决定决策系统每晚的推理量(每只全量分析约两三分钟)。
|
||
POOL_MAX = int(os.environ.get("POOL_MAX", "60"))
|
||
# 写完池子后触发决策系统的增量补扫(只补当天没分析过的票)。留空=不触发,
|
||
# 当晚 22:30 全量扫兜底。例:http://192.168.16.188:38000/api/v1/xxl/daily-scan
|
||
BIONIC_SCAN_URL = os.environ.get("BIONIC_SCAN_URL", "").rstrip("/")
|
||
BIONIC_SCAN_KEY = os.environ.get("BIONIC_SCAN_KEY", "")
|
||
|
||
# --- 候选卡(2026-09-02 主观选股改进方案,docs/主观选股改进方案_2026-09-02.md)------
|
||
# 桥从"打分排序器"改成"候选卡装配器":分数与档位不动,另出带理由的候选单。规则在 card.py。
|
||
# 两个旋钮保持默认、不在历史样本上挑参数,等样本外复盘读数再拍(09-02 拍板)。
|
||
FACTOR_REGISTER_STATUS = os.environ.get("FACTOR_REGISTER_STATUS", "paused") # 平台注册状态:paused=不参评(方案 2.5,平台参评列表只取 active),active=参评
|
||
CARD_START_PCT = float(os.environ.get("CARD_START_PCT", "3")) # 门槛二:数据日涨幅达到几个百分点算已启动(与基座热点扫描同口径)
|
||
|
||
# 门槛二整条开关。置 0 就是不要这条门槛,涨跌多少都不拦。
|
||
#
|
||
# 这条门槛回答的不是"这只票好不好",是"今天是不是买点":只在票已经动起来的当天买,
|
||
# 不去猜底。关掉它等于改成左侧买入——好处是研究结论成立的当天就能进场,不用等市场
|
||
# 先认同;代价是要承受不确定的等待,而且候选数会明显变多。
|
||
#
|
||
# 2026-09-04 关掉。关之前的实测:当日 83 只强传导票全部落到仅展示,其中绝大多数就
|
||
# 卡在这一条上(那天大盘在跌,三只被问到的票分别跌 3.2%、1.8%、2.2%)。
|
||
# 想开回去就把这个值设回 1 并重建容器,判决当天即恢复原样。
|
||
CARD_REQUIRE_STARTED = os.environ.get("CARD_REQUIRE_STARTED", "1") == "1"
|
||
CARD_ACCUM_MAX_AGE = int(os.environ.get("CARD_ACCUM_MAX_AGE", "30")) # 确认线:吸筹评分日龄上限(交易日)
|
||
# 计划快照落点(容器内路径;仓库根挂在 /app,故默认落在仓库 data/plan/)。
|
||
# 每日 JSON 含主榜与观察档全部行与全部证据线,是复盘与对账的唯一底本。
|
||
PLAN_SNAPSHOT_DIR = os.environ.get("PLAN_SNAPSHOT_DIR", "data/plan")
|
||
|
||
# --- 环境标签(只展示与复盘分组,不作交易前置;09-02 拍板)--------------------------
|
||
# 来源是决策系统的只读日频区制接口(请它加,桥零依赖);空串 = 未接入,标签一律 UNKNOWN,
|
||
# 不拦任何票。快照 08:40 预热,桥 07:10 出计划时拿不到,由 08:45 的追加步骤写进当日快照。
|
||
REGIME_API_URL = os.environ.get("REGIME_API_URL", "").rstrip("/")
|
||
REGIME_API_TIMEOUT = float(os.environ.get("REGIME_API_TIMEOUT", "6"))
|
||
# 弱势日定义(09-02 拍板,首份周报前锁定、之后不改;改它算新一轮验证):八个指数里弱势个数达到几个。
|
||
REGIME_WEAK_COUNT = int(os.environ.get("REGIME_WEAK_COUNT", "3"))
|
||
|
||
# --- 入池与候选卡的联动(09-02;第一步只加字段与切片,PMS 行为不变)------------------
|
||
# POOL_SOURCE:现状 = 强传导档前 POOL_TOP(默认,不变);candidate = 候选优先、再按强传导档补足到 POOL_TOP
|
||
# (第二步,复盘读数齐后拍板再切)。
|
||
POOL_SOURCE = os.environ.get("POOL_SOURCE", "tier")
|
||
# 低优先入池切片:让"门槛全过但缺吸筹评分"的关注票入池、当晚获得评分,否则复盘缺数据是环状依赖。
|
||
# 0 = 不开(默认);受 POOL_MAX 约束,只改 Mongo 池成分,PMS 不读 Mongo 池。
|
||
POOL_WATCH_SLICE = int(os.environ.get("POOL_WATCH_SLICE", "0"))
|
||
# 股票池分组文档的 pool_type 字段。以前写死为 "core",现在改为可配置,默认值不变,
|
||
# 写入的分组文档与择时决策系统读到的形状完全一样;只有在择时决策系统按 pool_type 区分
|
||
# 池子用途时才需要改它(2026-09-03 方案第 3.3 节"入池上下文补证据字段")。
|
||
POOL_TYPE = os.environ.get("POOL_TYPE", "core")
|
||
|
||
# --- 计划环境段的市场四项(2026-09-03 方案第 1.4 节与第 3.3 节"环境段扩展")------------------
|
||
# 两市成交额读平台行情库的指数日线表 zs_day_data,融资余额读 eastmoney_rzrq_data,
|
||
# 恐贪指数读 fear_greed_index。这三张表默认与个股日线 gp_day_data 在同一个 MySQL 实例
|
||
# (PRICE_MYSQL_*,默认复用平台因子库),所以默认取 "price";若它们实际落在 153 代理库,
|
||
# 把这个值改成 "heat" 或 "pms" 即可,不必改代码。可选值就是 db.read_mysql 认的四个名字:
|
||
# price / factor / heat / pms。每一项读失败都只是环境段里该项为空,不阻断出计划。
|
||
MARKET_MYSQL_SOURCE = os.environ.get("MARKET_MYSQL_SOURCE", "price").strip().lower()
|
||
|
||
# --- 候选卡的因果论断证据线(2026-09-03 方案第 3.3 节"候选卡读因果论断")----------------------
|
||
# 每只票从数据基座的因果论断视图 v_factor_logic 取最近披露日的最多几条论断挂在卡上。
|
||
# 只展示、不作门槛、不进判决;设 0 表示不读该视图(视图未建时也可用它关掉那一行告警)。
|
||
LOGIC_CLAIMS_PER_STOCK = int(os.environ.get("LOGIC_CLAIMS_PER_STOCK", "3"))
|
||
|
||
# 四态甲路吃的论断上限(2026-09-07)。它与上面那个"卡上展示几条"是两回事:展示三条够看,
|
||
# 但判跨期翻转与同期分歧要看全量——三条里"之前的论断"最多两条,翻转两头都会判错。
|
||
# 200 与覆盖率读数脚本同口径(实测单票最多 44 条,200 是护栏不是预期)。
|
||
LOGIC_CLAIMS_FULL = int(os.environ.get("LOGIC_CLAIMS_FULL", "200"))
|
||
|
||
# 乙路硬触发的维持窗口(计划日数,2026-09-07)。采信倾向从偏多迁移到偏空那一天记
|
||
# migrated=1,次日归零;不带历史的话硬触发只维持一个计划日,而倾向仍偏空并未回稳。
|
||
# 规则是:近 N 个计划日内出现过这次迁移且此后一直偏空,硬触发就仍成立。N 取 5,
|
||
# 与四态退出存疑要求"连续三个计划日不再存疑"同一量级、再留两天余量。一次定死。
|
||
JUDGEMENT_HOLD_DAYS = int(os.environ.get("JUDGEMENT_HOLD_DAYS", "5"))
|
||
|
||
# 论断陈旧线(自然日)。超过它就在候选卡的缺失项里写明"研报论断已过 N 天",只提示不作门槛。
|
||
# 取 90 天的理由是与吸筹评分的日龄上限可比:那一条是三十个交易日,约合六周多的自然日,
|
||
# 而研报的更新节奏本来就比资金结构评分慢得多(行业深度按季度、跟踪报告按事件),
|
||
# 所以放到大约两个季度这个量级。这个数一次定死,不按复盘读数回调。
|
||
# 2026-09-03 实测:当日 442 只带论断的票里,超过 90 天的有 166 只(37.6%),超过一年的 22 只。
|
||
LOGIC_STALE_DAYS = int(os.environ.get("LOGIC_STALE_DAYS", "90"))
|
||
|
||
# --- 日频行业观点快照(2026-09-03 方案第四之五之三节,落地顺序第一步;模块见 judgement.py)------
|
||
# 数据基座的研判结论按簇键唯一,重评时整行覆盖,库里永远只有最新一版,查不到"上一次是什么样、
|
||
# 什么时候变的"。选股系统每个计划日把最新一版抄一行存下来,自己攒版本史,只写不判。
|
||
# 落点是平台因子库(写因子表的同一个 MySQL):桥对数据基座只有只读账号,这张表又是选股系统的
|
||
# 派生记录不是基座事实。表名不带 t_factor_ 前缀,免得平台的因子清单把它当成一张因子表。
|
||
JUDGEMENT_SNAPSHOT_TABLE = os.environ.get("JUDGEMENT_SNAPSHOT_TABLE", "t_akg_judgement_snapshot")
|
||
# 抄哪几类评析簇。默认产业研判与环节评析两类:产业研判是主题级的慢信号(四态里的乙路),
|
||
# 环节评析将来接进来时版本史已经在攒了。个股评析与概念评析暂不抄,要抄把它们加进这个值。
|
||
JUDGEMENT_SCOPES = {s.strip() for s in
|
||
os.environ.get("JUDGEMENT_SCOPES", "industry,segment").split(",") if s.strip()}
|
||
# 比对上一版时往前看几个自然日。取到窗口内最近一个计划日的行作为上一版;超过这个窗口没写过
|
||
# 快照的主题,本次按"第一次见到"处理,迁移记为空、陈旧天数从零重新起算。
|
||
JUDGEMENT_PREV_LOOKBACK_DAYS = int(os.environ.get("JUDGEMENT_PREV_LOOKBACK_DAYS", "60"))
|
||
|
||
# --- 逐票日频逻辑状态表(2026-09-07 下一阶段方案第三件桥侧前置;模块见 logic_state_daily.py)-------
|
||
# 每个数据日为档位表里的每只票记一行原始态与落定态。只在早上 plan.generate 里写,/plan 实时重算只读。
|
||
# 同库同理由:桥对数据基座只有只读账号,这张表又是选股系统自己的派生记录。键是(数据日,前缀码),
|
||
# 数据日与 t_factor_akg_* 的 trade_date 同口径,不是行业观点快照的 plan_date(那个是写入当天)。
|
||
LOGIC_STATE_TABLE = os.environ.get("LOGIC_STATE_TABLE", "t_akg_logic_state_daily")
|
||
# 抗抖动的两个天数(计划日数),与 logic_state.settle 的默认值同源,一次定死、不按复盘读数回调:
|
||
# 其余方向的迁移要连续几个计划日同向;退出逻辑存疑要连续几个计划日不再存疑(进入存疑即刻成立)。
|
||
LOGIC_SETTLE_CONFIRM_DAYS = int(os.environ.get("LOGIC_SETTLE_CONFIRM_DAYS", "2"))
|
||
LOGIC_SETTLE_EXIT_DAYS = int(os.environ.get("LOGIC_SETTLE_EXIT_DAYS", "3"))
|
||
# 读上一次落定态与近几日原始态时往前看几个自然日。要盖住国庆这种连休八天再加两个周末的空档;
|
||
# 超过这个窗口没记过行的票按第一次见到处理,落定态等于原始态。
|
||
LOGIC_STATE_LOOKBACK_DAYS = int(os.environ.get("LOGIC_STATE_LOOKBACK_DAYS", "30"))
|