From d57ce2b9b6d25661a3b4972e881493f29014eb69 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 8 Jul 2026 22:59:53 +0800 Subject: [PATCH] docs(thesis): add thesis ledger and monthly check workflow Co-Authored-By: Claude Co-authored-by: Cursor --- .github/workflows/thesis-check.yml | 70 ++++++++++++++++++++++++++++++ docs/thesis-ledger.json | 28 ++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 .github/workflows/thesis-check.yml create mode 100644 docs/thesis-ledger.json diff --git a/.github/workflows/thesis-check.yml b/.github/workflows/thesis-check.yml new file mode 100644 index 0000000..1ebaf13 --- /dev/null +++ b/.github/workflows/thesis-check.yml @@ -0,0 +1,70 @@ +name: Thesis Check + +on: + schedule: + - cron: "0 2 1 * *" + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + thesis: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.11" + + - name: Validate thesis ledger + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + python - <<'PY' + import json, os, pathlib, subprocess, sys + path = pathlib.Path("docs/thesis-ledger.json") + if not path.exists(): + print("::error::docs/thesis-ledger.json missing") + sys.exit(1) + data = json.loads(path.read_text()) + strategies = data.get("strategies") or {} + if not strategies: + print("::error::no strategies in thesis ledger") + sys.exit(1) + failures = [] + warnings = [] + for name, row in strategies.items(): + fals = row.get("falsification_conditions") or [] + if not row.get("thesis"): + failures.append(f"{name}: missing thesis") + if len(fals) < 2: + failures.append(f"{name}: need >=2 falsification_conditions") + hit = row.get("hit_rate") + if hit is not None and float(hit) < 0.5: + warnings.append(f"{name}: hit_rate {hit} < 0.5") + if str(row.get("verdict", "")).lower() in {"falsified", "failed", "reject"}: + failures.append(f"{name}: verdict={row.get('verdict')}") + print(f"[thesis-check] strategies={len(strategies)} failures={len(failures)} warnings={len(warnings)}") + for item in failures: + print(f"::error::{item}") + for item in warnings: + print(f"::warning::{item}") + repo = os.environ.get("GITHUB_REPOSITORY", "") + token = os.environ.get("GH_TOKEN", "") + if failures and repo and token: + title = f"[thesis-check] falsification/validation failures ({len(failures)})" + body = "\n".join(f"- {x}" for x in failures) + # create issue (best-effort) + subprocess.run([ + "gh", "issue", "create", "--title", title, "--body", body + "\n\ncc @Pigbibi" + ], check=False) + sys.exit(1 if failures else 0) + PY diff --git a/docs/thesis-ledger.json b/docs/thesis-ledger.json new file mode 100644 index 0000000..2d6ead9 --- /dev/null +++ b/docs/thesis-ledger.json @@ -0,0 +1,28 @@ +{ + "strategies": { + "hk_global_etf_tactical_rotation": { + "thesis": "港股通全球ETF存在可交易的战术动量/风险切换效应", + "falsification_conditions": [ + "滚动12个月相对等权基准超额 < 0", + "最大回撤超过回测基线 1.5 倍" + ], + "created": "2025-09-01", + "last_verified": "2026-07-08", + "verdict": "active", + "hit_rate": null, + "status_note": "runtime_enabled" + }, + "hk_low_vol_dividend_quality_snapshot": { + "thesis": "港股低波+红利质量快照组合在风险调整后优于等权港股", + "falsification_conditions": [ + "滚动12个月 Sharpe < 基准", + "红利因子 IC 连续3个月 < 0" + ], + "created": "2025-10-01", + "last_verified": "2026-07-08", + "verdict": "active", + "hit_rate": null, + "status_note": "runtime_enabled" + } + } +}