from __future__ import annotations import argparse import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] DEFAULT_JSON = ROOT / "GatherTradingData.json" DEFAULT_VPS = ROOT / "Temp" / "value_preservation_scorer_v1.json" DEFAULT_OUT = ROOT / "Temp" / "smart_cash_recovery_v3.json" def _load(path: Path) -> dict[str, Any]: if not path.exists(): return {} try: obj = json.loads(path.read_text(encoding="utf-8")) except Exception: return {} return obj if isinstance(obj, dict) else {} def _rows(v: Any) -> list[dict[str, Any]]: if isinstance(v, list): return [x for x in v if isinstance(x, dict)] if isinstance(v, str): try: return _rows(json.loads(v)) except Exception: return [] return [] def _obj(v: Any) -> dict[str, Any]: if isinstance(v, dict): return v if isinstance(v, str): try: x = json.loads(v) return x if isinstance(x, dict) else {} except Exception: return {} return {} def _f(v: Any) -> float: try: return float(v) except Exception: return 0.0 def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--json", default=str(DEFAULT_JSON)) ap.add_argument("--vps", default=str(DEFAULT_VPS)) ap.add_argument("--out", default=str(DEFAULT_OUT)) args = ap.parse_args() jp = Path(args.json) vp = Path(args.vps) op = Path(args.out) if not jp.is_absolute(): jp = ROOT / jp if not vp.is_absolute(): vp = ROOT / vp if not op.is_absolute(): op = ROOT / op payload = _load(jp) data = payload.get("data") if isinstance(payload.get("data"), dict) else {} h = data.get("_harness_context") if isinstance(data.get("_harness_context"), dict) else {} if isinstance(payload.get("hApex"), dict): h = dict(h) | payload["hApex"] scrs = _obj(h.get("scrs_v2_json")) selected = _rows(scrs.get("selected_combo")) vps_rows = {str(r.get("ticker") or ""): r for r in _rows(_load(vp).get("rows"))} beta_gate = _obj(h.get("portfolio_beta_gate_json")) routing_trace = _obj(h.get("routing_trace_json")) regime = str( h.get("market_regime") or h.get("regime_label") or beta_gate.get("regime_applied") or routing_trace.get("market_regime") or "RISK_ON" ).upper() if regime == "NEUTRAL": regime = "RISK_ON" rebound_factor_map = { "EVENT_SHOCK": 0.7, "RISK_OFF": 0.6, "NEUTRAL": 0.5, "RISK_ON": 0.3, "SECULAR_LEADER_RISK_ON": 0.25, } rebound_factor = rebound_factor_map.get(regime, 0.5) out_rows = [] for r in selected: t = str(r.get("ticker") or "") score = vps_rows.get(t, {}) rp = _f(score.get("rebound_potential")) if rp >= 70: split = "40/60" elif rp <= 30: split = "80/20" else: split = "50/50" out_rows.append( { "ticker": t, "name": r.get("name"), "exec_mode": "TWAP_5_SPLIT" if _f(r.get("immediate_qty")) > 50 else "LIMIT_NEAR_BID", "split_plan": split, "rebound_factor_atr": rebound_factor, "rebound_trigger_price": r.get("rebound_trigger_price"), "value_damage_score": score.get("value_damage_score"), "rebound_potential": rp, "recommended_action": score.get("recommended_action", "SPLIT_REBOUND"), } ) distinct_modes = len({str(r.get("exec_mode") or "") for r in out_rows}) out = { "formula_id": "SMART_CASH_RECOVERY_V3", "gate": "PASS" if len(out_rows) > 0 else "CAUTION", "regime": regime, "rebound_factor_atr": rebound_factor, "selected_combo": out_rows, "distinct_exec_modes": distinct_modes, } op.parent.mkdir(parents=True, exist_ok=True) op.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding="utf-8") print(json.dumps(out, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())