Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ai_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
Return only the final bilingual review in markdown.
The workflow will publish your final review as the issue comment.

You are reviewing the monthly upstream selector report for CryptoLeaderRotation.
You are reviewing the monthly upstream selector report for CryptoSnapshotPipelines.
This repository owns monthly universe selection, ranking, challenger evaluation,
and publication of a 5-symbol Binance Spot leader pool for downstream execution.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/auto_optimization_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ jobs:
Do not create a pull request yourself. The workflow will handle git, PR creation, CI dispatch, and post-CI merge.
Only implement the low-risk tasks explicitly marked `[auto-pr-safe]`.
Ignore any medium-risk or high-risk tasks.
You are working inside CryptoLeaderRotation, the upstream selector repository.
You are working inside CryptoSnapshotPipelines, the upstream selector repository.
Prefer minimal changes in documentation, report wording, validation, shadow/challenger plumbing, instrumentation, and tests.
Do not change production selector logic or ranking behavior from this issue alone.
If an eligible task is marked `experiment-only`, keep the change non-production.
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/monthly_optimization_planner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: Monthly Optimization Planner
workflow_dispatch:
inputs:
upstream_run_id:
description: "AI review run id from CryptoLeaderRotation"
description: "AI review run id from CryptoSnapshotPipelines"
required: true
downstream_run_id:
description: "AI review run id from BinancePlatform"
Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
private-key: ${{ secrets.CROSS_REPO_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
CryptoLeaderRotation
CryptoSnapshotPipelines
BinancePlatform
CryptoStrategies
permission-actions: write
Expand Down Expand Up @@ -151,14 +151,14 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Fan out CryptoLeaderRotation task issue
- name: Fan out CryptoSnapshotPipelines task issue
run: |
python3 scripts/fanout_monthly_optimization_tasks.py \
--plan-file data/output/monthly_optimization/optimization_plan.json \
--owner-repo CryptoLeaderRotation \
--owner-repo CryptoSnapshotPipelines \
--repo "${GITHUB_REPOSITORY}" \
--planner-issue-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues/${{ steps.optimization_issue.outputs.issue_number }}" \
--output-file data/output/monthly_optimization/fanout/crypto_leader_rotation.json
--output-file data/output/monthly_optimization/fanout/crypto_snapshot_pipelines.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -213,12 +213,12 @@ jobs:
from pathlib import Path

fanout = json.loads(
Path("data/output/monthly_optimization/fanout/crypto_leader_rotation.json").read_text(encoding="utf-8")
Path("data/output/monthly_optimization/fanout/crypto_snapshot_pipelines.json").read_text(encoding="utf-8")
)
plan = json.loads(
Path("data/output/monthly_optimization/optimization_plan.json").read_text(encoding="utf-8")
)
actions = plan.get("repo_action_summary", {}).get("CryptoLeaderRotation", {}).get("actions", [])
actions = plan.get("repo_action_summary", {}).get("CryptoSnapshotPipelines", {}).get("actions", [])
should_dispatch = bool(fanout.get("issue_number")) and fanout.get("status") in {"created", "updated"} and any(
action.get("experiment_only") for action in actions
)
Expand All @@ -227,7 +227,7 @@ jobs:
print(f"issue_number={fanout.get('issue_number') or ''}", file=output)
PY

- name: Dispatch CryptoLeaderRotation experiment validation
- name: Dispatch CryptoSnapshotPipelines experiment validation
if: steps.upstream_experiment_target.outputs.should_dispatch == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Thanks for contributing to `CryptoLeaderRotation`.
Thanks for contributing to `CryptoSnapshotPipelines`.

## Ground Rules

Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# crypto-leader-rotation
# CryptoSnapshotPipelines

Language: English | [简体中文](README.zh-CN.md)

`crypto-leader-rotation` is the upstream research and release system for the monthly Binance Spot leader universe.
`CryptoSnapshotPipelines` is the upstream research, feature-snapshot, and release pipeline repo for crypto strategies.
The current production artifact family is still the `crypto_leader_rotation` Binance Spot leader universe.

This repository does not place trades and does not contain live execution logic. Its deliverables are the validated upstream artifacts, the monthly reporting layer around those artifacts, and the publish/notification path that keeps downstream execution systems in sync.

Expand All @@ -18,7 +19,7 @@ Core upstream artifacts:

## Upstream Boundary

`crypto-leader-rotation` is the single upstream owner for:
`CryptoSnapshotPipelines` is the single upstream owner for:

- research and walk-forward validation
- monthly universe selection and live-pool publication
Expand Down Expand Up @@ -49,6 +50,8 @@ The repository is now intentionally split into two tracks:

Production v1 is the frozen default path for this repository. The external-data branch stays in the repo, but it is explicitly experimental until it proves stably better than Binance-only across the key walk-forward leader-selection metrics.

The v1 artifact namespace intentionally remains `crypto-leader-rotation` and the live profile remains `crypto_leader_rotation` for downstream compatibility.

The design target is practical rather than flashy:

- use only data visible at the time
Expand Down Expand Up @@ -976,7 +979,7 @@ Documentation-only contract for downstream consumers:
2. if Firestore is unavailable, read `live_pool_legacy.json`
3. if both fail, fall back to a static local universe

See [docs/integration_contract.md](/Users/lisiyi/Projects/CryptoLeaderRotation/docs/integration_contract.md) for the precise payload contract and pseudocode.
See [docs/integration_contract.md](/Users/lisiyi/Projects/CryptoSnapshotPipelines/docs/integration_contract.md) for the precise payload contract and pseudocode.

### Manual Trigger And Rollback

Expand Down Expand Up @@ -1113,9 +1116,9 @@ The first external-data priority is not sentiment or on-chain complexity. It is:

Preparation added in this repository:

- [src/external_data.py](/Users/lisiyi/Projects/CryptoLeaderRotation/src/external_data.py)
- [scripts/validate_external_data.py](/Users/lisiyi/Projects/CryptoLeaderRotation/scripts/validate_external_data.py)
- [docs/external_data_roadmap.md](/Users/lisiyi/Projects/CryptoLeaderRotation/docs/external_data_roadmap.md)
- [src/external_data.py](/Users/lisiyi/Projects/CryptoSnapshotPipelines/src/external_data.py)
- [scripts/validate_external_data.py](/Users/lisiyi/Projects/CryptoSnapshotPipelines/scripts/validate_external_data.py)
- [docs/external_data_roadmap.md](/Users/lisiyi/Projects/CryptoSnapshotPipelines/docs/external_data_roadmap.md)

The current merge policy is:

Expand All @@ -1134,7 +1137,7 @@ Local validation of the merge logic:

The current validation snapshot and remaining release blockers are tracked in:

- [docs/validation_status.md](/Users/lisiyi/Projects/CryptoLeaderRotation/docs/validation_status.md)
- [docs/validation_status.md](/Users/lisiyi/Projects/CryptoSnapshotPipelines/docs/validation_status.md)

That document summarizes:

Expand Down
6 changes: 4 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# crypto-leader-rotation
# CryptoSnapshotPipelines

语言: [English](README.md) | 简体中文

`crypto-leader-rotation` 是一个“研究 + 生产发布”结合的 Python 项目,它的职责不是交易,而是为下游执行脚本提供更稳定、更高质量的 Binance Spot 主流币候选池和 leader 排名结果
`CryptoSnapshotPipelines` 是加密货币策略的上游研究、特征快照和发布流水线仓库。当前生产 artifact family 仍然是 `crypto_leader_rotation` 这条 Binance Spot leader universe

这个仓库**不下单**、**不包含 live 执行逻辑**。它的核心交付物是一个可稳定发布的上游选择器,默认输出:

Expand Down Expand Up @@ -30,6 +30,8 @@

当前默认生产路径已经冻结在 `Production v1`。外部数据分支仍保留在仓库中,但在它没证明自己长期稳定优于 Binance-only 之前,它都只是实验路线。

为了保持下游兼容,v1 artifact namespace 仍保留为 `crypto-leader-rotation`,live profile 仍保留为 `crypto_leader_rotation`。

## 这个项目为什么存在

大多数交易系统会把三件事混在一起:
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Security Policy

Thanks for helping keep `CryptoLeaderRotation` safe.
Thanks for helping keep `CryptoSnapshotPipelines` safe.

This repository is part of a research and release pipeline. Please do **not** open a public issue for vulnerabilities involving credentials, broker access, cloud resources, order execution, or secret material.

Expand Down
6 changes: 3 additions & 3 deletions docs/external_data_roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Not first priority:

The repository now includes:

- [src/external_data.py](/Users/lisiyi/Projects/CryptoLeaderRotation/src/external_data.py)
- [scripts/validate_external_data.py](/Users/lisiyi/Projects/CryptoLeaderRotation/scripts/validate_external_data.py)
- external-data config blocks in [config/default.yaml](/Users/lisiyi/Projects/CryptoLeaderRotation/config/default.yaml)
- [src/external_data.py](/Users/lisiyi/Projects/CryptoSnapshotPipelines/src/external_data.py)
- [scripts/validate_external_data.py](/Users/lisiyi/Projects/CryptoSnapshotPipelines/scripts/validate_external_data.py)
- external-data config blocks in [config/default.yaml](/Users/lisiyi/Projects/CryptoSnapshotPipelines/config/default.yaml)

Implemented concepts:

Expand Down
5 changes: 3 additions & 2 deletions docs/integration_contract.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Integration Contract

This document defines the production contract exposed by `crypto-leader-rotation` to downstream strategy systems.
This document defines the production contract exposed by `CryptoSnapshotPipelines` to downstream strategy systems.
The current v1 artifact namespace remains `crypto-leader-rotation` for compatibility with existing published objects and downstream readers.

The upstream project publishes a monthly `core_major` live pool and exposes it through:

Expand All @@ -14,7 +15,7 @@ The upstream project publishes a monthly `core_major` live pool and exposes it t

This profile-aware manifest is the canonical contract wrapper for downstream
runtimes. It lets the execution platform validate the artifact family without
binding to `CryptoLeaderRotation` internals.
binding to `CryptoSnapshotPipelines` internals.

Required stable fields:

Expand Down
4 changes: 2 additions & 2 deletions scripts/build_monthly_optimization_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

RISK_ORDER = {"low": 0, "medium": 1, "high": 2}
SCHEMA_VERSION = "2026-04-02"
REPO_ORDER = ["CryptoLeaderRotation", "CryptoStrategies", "BinancePlatform"]
REPO_ORDER = ["CryptoSnapshotPipelines", "CryptoStrategies", "BinancePlatform"]
MANUAL_REVIEW_PREFIXES = (
"check ",
"review ",
Expand Down Expand Up @@ -64,7 +64,7 @@ def _resolve_owner_repo(source_review: dict[str, Any], action: dict[str, Any]) -
"selection threshold",
)
):
return "CryptoLeaderRotation"
return "CryptoSnapshotPipelines"

return action["owner_repo"]

Expand Down
20 changes: 14 additions & 6 deletions scripts/prepare_auto_optimization_pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"test coverage",
)
AUTO_MERGE_BLOCK_TERMS = {
"CryptoLeaderRotation": (
"CryptoSnapshotPipelines": (
"tie-break",
"tie break",
"ranking",
Expand Down Expand Up @@ -81,7 +81,7 @@
),
}
SENSITIVE_PATH_PATTERNS = {
"CryptoLeaderRotation": (
"CryptoSnapshotPipelines": (
r"^src/",
r"^config/",
),
Expand All @@ -106,6 +106,14 @@
),
}

REPO_NAME_ALIASES = {
"CryptoLeaderRotation": "CryptoSnapshotPipelines",
}


def _repo_key(repo_root: Path) -> str:
return REPO_NAME_ALIASES.get(repo_root.name, repo_root.name)


def parse_actions(issue_body: str) -> list[dict[str, Any]]:
actions: list[dict[str, Any]] = []
Expand Down Expand Up @@ -158,9 +166,9 @@ def _read_text(path: Path) -> str:

def _is_completed_low_risk_task(action: dict[str, Any], repo_root: Path) -> bool:
title = str(action.get("title", "")).lower()
repo_name = repo_root.name
repo_name = _repo_key(repo_root)

if repo_name == "CryptoLeaderRotation":
if repo_name == "CryptoSnapshotPipelines":
if "shadow/challenger build generation" in title or "shadow build" in title:
workflow = _read_text(repo_root / ".github" / "workflows" / "monthly_publish.yml")
return "run_monthly_shadow_build.py" in workflow
Expand Down Expand Up @@ -198,7 +206,7 @@ def classify_action_for_auto_merge(action: dict[str, Any], repo_root: Path | Non
if not any(term in text for term in AUTO_MERGE_SAFE_TERMS):
return False, "task_not_in_auto_merge_allowlist"

for term in AUTO_MERGE_BLOCK_TERMS.get(repo_root.name, ()): # pragma: no branch - tiny tuples
for term in AUTO_MERGE_BLOCK_TERMS.get(_repo_key(repo_root), ()): # pragma: no branch - tiny tuples
if term in text:
return False, f"guarded_keyword:{term}"
return True, "auto_merge_safe"
Expand All @@ -207,7 +215,7 @@ def classify_action_for_auto_merge(action: dict[str, Any], repo_root: Path | Non
def evaluate_changed_files(changed_files: list[str], repo_root: Path | None = None) -> dict[str, Any]:
repo_root = repo_root or PROJECT_ROOT
blocked_files: list[str] = []
patterns = tuple(re.compile(pattern) for pattern in SENSITIVE_PATH_PATTERNS.get(repo_root.name, ()))
patterns = tuple(re.compile(pattern) for pattern in SENSITIVE_PATH_PATTERNS.get(_repo_key(repo_root), ()))
for raw_path in changed_files:
normalized = raw_path.strip().lstrip("./")
if not normalized:
Expand Down
2 changes: 1 addition & 1 deletion scripts/run_monthly_build_telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def format_message(payload: dict[str, Any]) -> str:
else "shadow: not_generated_in_this_run"
)
lines = [
"CryptoLeaderRotation monthly release",
"CryptoSnapshotPipelines monthly release",
f"status: {payload['status']}",
f"as_of_date: {payload['as_of_date']}",
(
Expand Down
2 changes: 1 addition & 1 deletion scripts/run_monthly_report_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def render_ai_review_input(bundle: dict[str, Any], release_status_md: str, month

## Review intent

- This is an upstream selector review for CryptoLeaderRotation, not a downstream execution report.
- This is an upstream selector review for CryptoSnapshotPipelines, not a downstream execution report.
- The main question is whether the current monthly 5-symbol pool still looks like a sound production selector output, and what additional research evidence is still missing.
- Shadow / challenger coverage should be used for strategy-optimization judgment when available. If missing, treat optimization evidence as incomplete rather than forcing a strong conclusion.
- Downstream BinancePlatform consumes this pool monthly and then applies its own execution logic on top.
Expand Down
4 changes: 2 additions & 2 deletions scripts/run_openai_secondary_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"title": {"type": "string"},
"owner_repo": {
"type": "string",
"enum": ["CryptoLeaderRotation", "CryptoStrategies", "BinancePlatform"],
"enum": ["CryptoSnapshotPipelines", "CryptoStrategies", "BinancePlatform"],
},
"risk_level": {"type": "string", "enum": ["low", "medium", "high"]},
"auto_pr_safe": {"type": "boolean"},
Expand Down Expand Up @@ -86,7 +86,7 @@
def build_system_prompt(review_kind: str) -> str:
if review_kind == "upstream_selector":
return (
"You are the independent secondary reviewer for CryptoLeaderRotation, an upstream selector "
"You are the independent secondary reviewer for CryptoSnapshotPipelines, an upstream selector "
"repository that publishes a monthly 5-symbol Binance Spot leader pool. Review the issue body "
"and the Claude primary review, then return only valid JSON matching the provided schema. "
"Do not simply echo Claude. Re-check whether release consistency, selector quality, "
Expand Down
2 changes: 1 addition & 1 deletion tests/test_auto_optimization_pr_workflow_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_auto_optimization_workflow_handles_monthly_task_issues(self) -> None:
self.assertIn("gh workflow run ci.yml", workflow)
self.assertIn("fetch-depth: 0", workflow)
self.assertIn('FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"', workflow)
self.assertIn("You are working inside CryptoLeaderRotation, the upstream selector repository.", workflow)
self.assertIn("You are working inside CryptoSnapshotPipelines, the upstream selector repository.", workflow)
self.assertIn("Never edit files under src/ or config/ in this automation step.", workflow)

def test_auto_merge_workflow_waits_for_ci_and_merges_only_safe_ready_prs(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_build_ai_review_payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class BuildAiReviewPayloadTests(unittest.TestCase):
def test_build_review_payload_carries_standardized_root_fields(self) -> None:
payload = build_review_payload(
source_repo="QuantStrategyLab/CryptoLeaderRotation",
source_repo="QuantStrategyLab/CryptoSnapshotPipelines",
review_kind="upstream_selector",
issue_context={"number": 11, "title": "Monthly Report Review: 2026-04-01"},
secondary_review={
Expand All @@ -28,7 +28,7 @@ def test_build_review_payload_carries_standardized_root_fields(self) -> None:

self.assertEqual(payload["schema_version"], SCHEMA_VERSION)
self.assertEqual(payload["repo_role"], "upstream_selector_review")
self.assertEqual(payload["source_issue"]["url"], "https://github.com/QuantStrategyLab/CryptoLeaderRotation/issues/11")
self.assertEqual(payload["source_issue"]["url"], "https://github.com/QuantStrategyLab/CryptoSnapshotPipelines/issues/11")
self.assertEqual(payload["secondary_reviewer"]["model"], "gpt-5.4-mini")


Expand Down
Loading