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_OUT = ROOT / "Temp" / "cash_raise_value_optimizer_v3.json" def _load(path: Path) -> dict[str, Any]: 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("--out", default=str(DEFAULT_OUT)) args = ap.parse_args() jp = Path(args.json) op = Path(args.out) if not jp.is_absolute(): jp = ROOT / jp 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"] cash_shortfall = _f(h.get("cash_shortfall_min_krw")) scrs = _obj(h.get("scrs_v2_json")) selected = _rows(scrs.get("selected_combo")) if not selected: selected = _rows(h.get("trim_plan_to_min_cash_json")) ranked = sorted(selected, key=lambda r: (_f(r.get("value_damage_pct")), -_f(r.get("expected_sell_krw")))) immediate_total = _f(scrs.get("total_immediate_sell_krw")) rebound_gain = _f(scrs.get("expected_rebound_gain_krw")) value_damage = _f(scrs.get("value_damage_pct_avg")) cash_after = max(0.0, cash_shortfall - immediate_total) objective = round( cash_after * 1.0 + value_damage * 10000.0 - rebound_gain * 0.1, 2, ) orders = [] for r in ranked[:10]: orders.append( { "ticker": r.get("ticker"), "name": r.get("name"), "immediate_qty": r.get("immediate_qty", r.get("sell_qty")), "rebound_wait_qty": r.get("rebound_wait_qty", 0), "estimated_immediate_krw": r.get("expected_sell_krw", r.get("estimated_sell_krw", 0)), "value_damage_pct": r.get("value_damage_pct"), } ) out = { "formula_id": "CASH_RAISE_VALUE_OPTIMIZER_V3", "objective_score": objective, "cash_target_krw": round(cash_shortfall), "cash_raised_immediate_krw": round(immediate_total), "cash_raised_rebound_krw": round(max(0.0, _f(scrs.get("total_projected_sell_krw")) - immediate_total)), "expected_rebound_gain_krw": round(rebound_gain), "value_damage_pct_avg": round(value_damage, 2), "leader_damage_score": round(value_damage * 1.2, 2), "cluster_risk_after_pct": round(_f(_obj(h.get("mandatory_reduction_json")).get("cluster_pct")), 2), "orders": orders, } 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())