feat(factor): NAS 日度 runner 一次性容器两段链+月度 runner registry 切运行副本(存量错位修正:批侧原读 config 种子,首班后出生因子不在批视野) [nas]

This commit is contained in:
2026-10-10 07:22:15 +08:00
parent 299f3a27ed
commit 3bca54d69b
2 changed files with 95 additions and 1 deletions
@@ -0,0 +1,86 @@
#!/bin/bash
# run_factor_daily_standalone.sh — 因子日度重评批·NAS 侧(决议 H 修订 2026-10-10)
# 「bash wrapper → 一次性容器」同月度链模式(--user 1024:100 --group-add 101,
# 主容器重启/CI 重建永不波及)。
#
# 两段链(as_of=T-1,等 21:00 xt_eod 收完 T-1 bar,DSM 任务 21:30 触发):
# ① monthly_batch --daily 全量重评批(注册表全量,12M 窗,as_of 直用不归一月末)
# ② monthly_review 日度对拍件落 daily/ 子目录(host=nas,append-only)
# ——判定/报告层月末快照语义不动:月度四段链照旧每月第一个周日跑,正式报告
# 落根目录,API 端点只读根层,daily/ 子目录天然隔离。
#
# registry 对齐(2026-10-10 修正存量错位):批侧改读运行副本 /app/data/
# factor_registry.yaml(与控制台同源——decompose 新生/判死即时生效);
# 旧月度链用 config 种子,首班后新因子不在批视野=盲区不止时序还有注册表
# 错位。防御:运行副本缺失时从 config 种子拷(API 从未跑过的机器)。
#
# 部署位: NAS /volume1/stock/sanguo_vnpy_v2/run_factor_daily.sh(宿主文件,
# CI 不覆盖;改 repo 副本后 scp -O 手动同步,同月度纪律):
# scp -O scripts/nas_sync/run_factor_daily_standalone.sh \
# sanguo-nas:/volume1/stock/sanguo_vnpy_v2/run_factor_daily.sh
#
# DSM 任务(sanguo-factor-daily, 每日 21:30, 用户=admin):
# bash /volume1/stock/sanguo_vnpy_v2/run_factor_daily.sh
set -u
DOCKER=/var/packages/Docker/target/usr/bin/docker
BASE=/volume1/stock/sanguo_vnpy_v2
LOG=$BASE/factor_daily_cron.log
APP=/volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2
UID_ADMIN=1024
GID_ADMIN=100
GID_ADMINS=101
EVAL_DB=$BASE/data/factor_eval.db
OUT_DIR=$BASE/reports/factor_monthly/daily
REGISTRY=/app/data/factor_registry.yaml # 运行副本(控制台同源);缺失时下方向下拷种
# T-1(昨日):宿主 python3 算,不依赖 GNU date -d
AS_OF=$(python3 - <<'PY'
from datetime import date, timedelta
print((date.today() - timedelta(days=1)).isoformat())
PY
)
{
echo "=== $(date '+%F %T') factor-daily start (as_of=$AS_OF) ==="
mkdir -p "$OUT_DIR"
# 运行副本防御:缺失从 config 种子拷(API 从未起过的机器)
if [ ! -f "$APP/data/factor_registry.yaml" ]; then
echo "--- 运行副本缺失,从 config 种子拷贝 ---"
cp "$APP/config/factor_registry.yaml" "$APP/data/factor_registry.yaml" || exit 1
fi
"$DOCKER" run --rm --name sanguo-factor-daily --user "${UID_ADMIN}:${GID_ADMIN}" \
--group-add "${GID_ADMINS}" --no-healthcheck --entrypoint python \
-e HOME=/tmp -e MPLCONFIGDIR=/tmp/mpl \
-v /volume1/stock:/volume1/stock \
-v "$APP":/app:ro \
-w /app \
sanguo_vnpy_v2:lock-aligned \
-m sanguo_factor.monthly_batch --as-of "$AS_OF" --daily \
--registry "$REGISTRY" --eval-db "$EVAL_DB" --report-dir "$OUT_DIR" \
--host nas
rc_batch=$?
echo "=== $(date '+%F %T') stage1 daily_batch exit=$rc_batch ==="
if [ "$rc_batch" -ne 0 ]; then
echo "!!! stage1 失败,停链(review 无新批可评) ==="
exit "$rc_batch"
fi
"$DOCKER" run --rm --name sanguo-factor-daily-rev --user "${UID_ADMIN}:${GID_ADMIN}" \
--group-add "${GID_ADMINS}" --no-healthcheck --entrypoint python \
-e HOME=/tmp -e MPLCONFIGDIR=/tmp/mpl \
-v /volume1/stock:/volume1/stock \
-v "$APP":/app:ro \
-w /app \
sanguo_vnpy_v2:lock-aligned \
-m sanguo_factor.monthly_review --as-of "$AS_OF" --host nas \
--registry "$REGISTRY" --eval-db "$EVAL_DB" --out-dir "$OUT_DIR"
rc_review=$?
echo "=== $(date '+%F %T') stage2 daily_review exit=$rc_review (2=告警信号,有效) ==="
final=0
[ "$rc_review" -eq 1 ] && final=1
echo "=== $(date '+%F %T') factor-daily done final_rc=$final (batch=$rc_batch review=$rc_review) ==="
exit $final
} >> "$LOG" 2>&1
@@ -47,7 +47,9 @@ GID_ADMIN=100 # users
GID_ADMINS=101 # administrators(Synology ACL 授权组,金丝雀实测必带)
EVAL_DB=$BASE/data/factor_eval.db
OUT_DIR=$BASE/reports/factor_monthly
REGISTRY=/app/config/factor_registry.yaml
# 2026-10-10 registry 对齐控制台运行副本(data/,非 config 种子):decompose
# 新生/判死即时进批视野;防御=运行副本缺失时从种子拷(API 从未跑过的机器)
REGISTRY=/app/data/factor_registry.yaml
MANIFEST=/app/config/data_manifest.yaml
# 上月末(自然月末):宿主 python3 算,不依赖 GNU date -d
@@ -70,6 +72,12 @@ PY
echo "=== $(date '+%F %T') factor-monthly start (as_of=$AS_OF) ==="
mkdir -p "$OUT_DIR"
# 运行副本防御:缺失从 config 种子拷
if [ ! -f "$APP/data/factor_registry.yaml" ]; then
echo "--- 运行副本缺失,从 config 种子拷贝 ---"
cp "$APP/config/factor_registry.yaml" "$APP/data/factor_registry.yaml" || exit 1
fi
"$DOCKER" run --rm --name sanguo-factor-batch --user "${UID_ADMIN}:${GID_ADMIN}" \
--group-add "${GID_ADMINS}" --no-healthcheck --entrypoint python \
-e HOME=/tmp -e MPLCONFIGDIR=/tmp/mpl \