Skip to content

Commit 582bbb7

Browse files
Pigbibicursoragent
andcommitted
Stamp as_of on dividend quality snapshot outputs for runtime guards.
Ensures built snapshot CSVs satisfy QuantPlatformKit feature snapshot date requirements and AkShare staging emits the same column. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 7fd3c25 commit 582bbb7

3 files changed

Lines changed: 20 additions & 1 deletion

File tree

src/cn_equity_snapshot_pipelines/akshare_staging.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import argparse
4+
from datetime import datetime, timezone
45
from pathlib import Path
56

67
import pandas as pd
@@ -127,6 +128,9 @@ def build_factor_snapshot_from_akshare(
127128
}
128129
)
129130
frame = pd.DataFrame(rows, columns=list(FACTOR_SNAPSHOT_COLUMNS))
131+
if "as_of" not in frame.columns and "snapshot_date" not in frame.columns:
132+
stamp = datetime.now(timezone.utc).date().isoformat()
133+
frame.insert(0, "as_of", stamp)
130134
diagnostics["row_count"] = len(frame)
131135
return frame, diagnostics
132136

src/cn_equity_snapshot_pipelines/dividend_quality.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import argparse
4+
from datetime import date, datetime, timezone
45
from pathlib import Path
56

67
import pandas as pd
@@ -15,16 +16,26 @@ def _read_csv(path: str | Path) -> pd.DataFrame:
1516
return pd.read_csv(Path(path))
1617

1718

19+
def _ensure_snapshot_as_of(snapshot: pd.DataFrame, *, as_of: str | date | None = None) -> pd.DataFrame:
20+
frame = snapshot.copy()
21+
if "as_of" in frame.columns or "snapshot_date" in frame.columns:
22+
return frame
23+
stamp = as_of or datetime.now(timezone.utc).date().isoformat()
24+
frame.insert(0, "as_of", str(stamp))
25+
return frame
26+
27+
1828
def build_and_write_snapshot(
1929
*,
2030
factor_snapshot_path: str | Path,
2131
output_dir: str | Path,
2232
min_adv20_cny: float = 0.0,
2333
min_market_cap_cny: float = 0.0,
34+
as_of: str | date | None = None,
2435
) -> SnapshotBuildResult:
2536
contract = get_profile_contract(CN_DIVIDEND_QUALITY_SNAPSHOT_PROFILE)
2637
artifact_paths = contract.artifact_paths(output_dir)
27-
snapshot = _read_csv(factor_snapshot_path)
38+
snapshot = _ensure_snapshot_as_of(_read_csv(factor_snapshot_path), as_of=as_of)
2839
ranking = score_candidates(
2940
snapshot,
3041
min_adv20_cny=float(min_adv20_cny),
@@ -74,13 +85,15 @@ def main(argv: list[str] | None = None) -> int:
7485
parser.add_argument("--output-dir", default="data/output/dividend_quality")
7586
parser.add_argument("--min-adv20-cny", type=float, default=0.0)
7687
parser.add_argument("--min-market-cap-cny", type=float, default=0.0)
88+
parser.add_argument("--as-of", default=None, help="Snapshot as_of date (YYYY-MM-DD). Defaults to UTC today.")
7789
args = parser.parse_args(argv)
7890

7991
result = build_and_write_snapshot(
8092
factor_snapshot_path=args.factor_snapshot,
8193
output_dir=args.output_dir,
8294
min_adv20_cny=args.min_adv20_cny,
8395
min_market_cap_cny=args.min_market_cap_cny,
96+
as_of=args.as_of,
8497
)
8598
print(f"snapshot={result.artifact_paths['snapshot']}")
8699
print(f"manifest={result.artifact_paths['manifest']}")

tests/test_dividend_quality.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ def test_build_dividend_quality_snapshot_writes_artifact_pack(tmp_path: Path):
1010
result = build_and_write_snapshot(
1111
factor_snapshot_path=sample,
1212
output_dir=tmp_path,
13+
as_of="2026-02-25",
1314
)
1415

1516
assert len(result.snapshot) == 4
17+
assert "as_of" in result.snapshot.columns
1618
assert not result.ranking.empty
1719
for key in ("snapshot", "manifest", "ranking", "release_summary"):
1820
assert result.artifact_paths[key].exists()

0 commit comments

Comments
 (0)