import json from datetime import datetime from indian_paper_trading_strategy.engine.db import db_connection, get_context DEFAULT_CONFIG = { "active": False, "sip_amount": 0, "sip_frequency": {"value": 30, "unit": "days"}, "next_run": None } def _maybe_parse_json(value): if value is None: return None if not isinstance(value, str): return value text = value.strip() if not text: return None try: return json.loads(text) except Exception: return value def _format_ts(value: datetime | None): if value is None: return None return value.isoformat() def load_strategy_config(user_id: str | None = None, run_id: str | None = None): scope_user, scope_run = get_context(user_id, run_id) with db_connection() as conn: with conn.cursor() as cur: cur.execute( """ SELECT strategy, sip_amount, sip_frequency_value, sip_frequency_unit, mode, broker, active, frequency, frequency_days, unit, next_run FROM strategy_config WHERE user_id = %s AND run_id = %s LIMIT 1 """, (scope_user, scope_run), ) row = cur.fetchone() if not row: return DEFAULT_CONFIG.copy() cfg = DEFAULT_CONFIG.copy() cfg["strategy"] = row[0] cfg["strategy_name"] = row[0] cfg["sip_amount"] = float(row[1]) if row[1] is not None else cfg.get("sip_amount") cfg["mode"] = row[4] cfg["broker"] = row[5] cfg["active"] = row[6] if row[6] is not None else cfg.get("active") cfg["frequency"] = _maybe_parse_json(row[7]) cfg["frequency_days"] = row[8] cfg["unit"] = row[9] cfg["next_run"] = _format_ts(row[10]) if row[2] is not None or row[3] is not None: cfg["sip_frequency"] = {"value": row[2], "unit": row[3]} else: value = cfg.get("frequency") unit = cfg.get("unit") if isinstance(value, dict): unit = value.get("unit", unit) value = value.get("value") if value is None and cfg.get("frequency_days") is not None: value = cfg.get("frequency_days") unit = unit or "days" if value is not None and unit: cfg["sip_frequency"] = {"value": value, "unit": unit} return cfg def save_strategy_config(cfg, user_id: str | None = None, run_id: str | None = None): scope_user, scope_run = get_context(user_id, run_id) sip_frequency = cfg.get("sip_frequency") sip_value = None sip_unit = None if isinstance(sip_frequency, dict): sip_value = sip_frequency.get("value") sip_unit = sip_frequency.get("unit") frequency = cfg.get("frequency") if not isinstance(frequency, str) and frequency is not None: frequency = json.dumps(frequency) next_run = cfg.get("next_run") next_run_dt = None if isinstance(next_run, str): try: next_run_dt = datetime.fromisoformat(next_run) except ValueError: next_run_dt = None strategy = cfg.get("strategy") or cfg.get("strategy_name") with db_connection() as conn: with conn: with conn.cursor() as cur: cur.execute( """ INSERT INTO strategy_config ( user_id, run_id, strategy, sip_amount, sip_frequency_value, sip_frequency_unit, mode, broker, active, frequency, frequency_days, unit, next_run ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT (user_id, run_id) DO UPDATE SET strategy = EXCLUDED.strategy, sip_amount = EXCLUDED.sip_amount, sip_frequency_value = EXCLUDED.sip_frequency_value, sip_frequency_unit = EXCLUDED.sip_frequency_unit, mode = EXCLUDED.mode, broker = EXCLUDED.broker, active = EXCLUDED.active, frequency = EXCLUDED.frequency, frequency_days = EXCLUDED.frequency_days, unit = EXCLUDED.unit, next_run = EXCLUDED.next_run """, ( scope_user, scope_run, strategy, cfg.get("sip_amount"), sip_value, sip_unit, cfg.get("mode"), cfg.get("broker"), cfg.get("active"), frequency, cfg.get("frequency_days"), cfg.get("unit"), next_run_dt, ), )