#!/usr/bin/env python3 """CONSECUTIVE_STREAK_V1 — spec/formulas/domains/entry.yaml. Symmetric up_streak/down_streak from the most recent close-to-close changes. governance/todo/technical_signals_p4_adoption_plan.yaml P4-5. """ from __future__ import annotations import argparse import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] DEFAULT_OUT = ROOT / "Temp" / "consecutive_streak_v1.json" def compute_streaks(daily_close_changes: list[float] | None) -> dict: if not daily_close_changes: return {"up_streak": None, "down_streak": None} up_streak = 0 for change in reversed(daily_close_changes): if change > 0: up_streak += 1 else: break down_streak = 0 for change in reversed(daily_close_changes): if change < 0: down_streak += 1 else: break return {"up_streak": up_streak, "down_streak": down_streak} def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--changes", default=None, help="comma-separated daily close changes") ap.add_argument("--out", default=str(DEFAULT_OUT)) args = ap.parse_args() daily_close_changes = [float(x) for x in args.changes.split(",")] if args.changes else None result = {"formula_id": "CONSECUTIVE_STREAK_V1", **compute_streaks(daily_close_changes)} out = Path(args.out) out.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8") print(json.dumps(result, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())