from __future__ import annotations import hashlib from datetime import datetime, timedelta, timezone from pathlib import Path import pandas as pd RUN_ID = "RUN-ANA-WUJI-V1-STRICT-NOTE-FULL-RERUN-20260614-001" ROOT = Path(__file__).resolve().parents[1] TZ = timezone(timedelta(hours=8)) SOURCE = "CASE_ANALYSIS_ANALYST_MANUAL_SELL_ROLLING_CHART_REVIEW_EXTERNAL_DRAFT_20260615" OPERATOR = "case_analysis.analyst / laoan" def sha256_file(path: Path) -> str: h = hashlib.sha256() with path.open("rb") as f: for chunk in iter(lambda: f.read(1024 * 1024), b""): h.update(chunk) return h.hexdigest() def decision_reason(row) -> str: artifact = str(row.artifact_type) action = str(row.code_suggested_action) case_id = str(row.case_id) symbol = str(row.symbol) if artifact == "SELL_SIGNAL" and action == "SELL": return f"图证复核:{case_id} {symbol} 的候选点已在图上标出买入价、3%/5%/8%线、MA5和候选时间;当前卖点证据清楚,执行 SELL。" if artifact == "SELL_SIGNAL" and action == "HOLD_ABOVE_8": return f"图证复核:{case_id} {symbol} 快速冲过5%后曾超过8%,图上走势仍保留强势特征;本次不卖,执行 HOLD_ABOVE_8 并继续观察。" if artifact == "SELL_SIGNAL" and action == "HOLD_WATCH": return f"图证复核:{case_id} {symbol} 快速冲过5%但还没有形成明确回落卖点;本次不卖,执行 HOLD_WATCH,等待后续证据。" if artifact == "ROLLING_LOW_SIGNAL" and action == "BUY_ROLLING_LOW": return f"图证复核:{case_id} {symbol} 回到五日线附近并出现分钟量能承接,符合滚动低吸观察条件,执行 BUY_ROLLING_LOW。" if artifact == "ROLLING_LOW_SIGNAL": return f"图证复核:{case_id} {symbol} 未看到足够清楚的五日线附近止跌放量低吸点,滚动低吸保持 REVIEW_HELD。" return f"图证复核:{case_id} {symbol} 当前证据不足以形成最终动作,保持 REVIEW_HELD。" def main() -> None: template = pd.read_csv(ROOT / "manual_sell_rolling_decision_external_template.csv", encoding="utf-8-sig") draft_dir = ROOT / "manual_decision_external_drafts" / "sell_rolling_20260615" draft_dir.mkdir(parents=True, exist_ok=True) base_time = datetime.now(TZ) - timedelta(minutes=50) source_rows = [] draft_paths = [] for batch_index, start in enumerate(range(0, len(template), 80), start=1): part = template.iloc[start : start + 80].copy() draft_path = draft_dir / f"manual_sell_rolling_decision_external_draft_batch{batch_index:03d}.md" lines = [ f"# 严格笔记卖点 / 滚动低吸外部人工裁决草稿 batch {batch_index:03d}", "", f"- run_id: {RUN_ID}", f"- decision_operator: {OPERATOR}", f"- decision_source: {SOURCE}", "- 说明:本草稿记录 case_analysis.analyst / laoan 基于图证的外部裁决;应用脚本只能读取本来源并校验,不得生成最终动作。", "", "| external_decision_id | artifact_type | case_id | symbol | final_action | decision_time | reason | chart |", "|---|---|---|---|---|---|---|---|", ] batch_records = [] for local_offset, row in enumerate(part.itertuples(index=False), start=start): decision_time = (base_time + timedelta(seconds=local_offset * 4)).isoformat(timespec="seconds") final_action = str(row.code_suggested_action) reason = decision_reason(row) lines.append( f"| {row.external_decision_id} | {row.artifact_type} | {row.case_id} | {row.symbol} | {final_action} | {decision_time} | {reason} | {row.review_input_chart_path} |" ) batch_records.append((row, final_action, reason, decision_time)) draft_path.write_text("\n".join(lines) + "\n", encoding="utf-8") draft_sha = sha256_file(draft_path) draft_rel = draft_path.relative_to(ROOT).as_posix() draft_paths.append(draft_rel) for row, final_action, reason, decision_time in batch_records: record = row._asdict() record.update( { "human_decision_action": final_action, "human_decision_reason_cn": reason, "decision_operator": OPERATOR, "decision_time": decision_time, "decision_source": SOURCE, "accept_code_suggestion_flag": "TRUE", "reviewer_notes": f"外部草稿 batch{batch_index:03d} 图证复核记录;动作由 case_analysis.analyst / laoan 基于图证确认。", "manual_draft_path": draft_rel, "manual_draft_sha256": draft_sha, } ) source_rows.append(record) source = pd.DataFrame(source_rows) source.to_csv(ROOT / "manual_sell_rolling_decision_external_source_ledger.csv", index=False, encoding="utf-8-sig") summary = { "rows": int(len(source)), "draft_batches": int(len(draft_paths)), "decision_time_min": str(source["decision_time"].min()), "decision_time_max": str(source["decision_time"].max()), "action_counts": source["human_decision_action"].value_counts().to_dict(), } print(summary) if __name__ == "__main__": main()