import json import os import subprocess from typing import Any WATCHLIST_DEFAULT = [ # A-share ETF proxies for indices (QFR raw data uses ETF parquets) # HS300 "510300.SH", # ZZ500 "510500.SH", # ChiNext "159915.SZ", # SSE50 proxy (may not exist in rawdir unless downloaded) "510050.SH", # Futures placeholders (not in QFR rawdir by default; will show as errors until sourced) "AU.SHF", "CU.SHF", "M.DCE", "TA.CZCE", "SC.INE", ] def fetch_moves_via_qfr(*, trade_date: str | None = None, symbols: list[str] | None = None) -> dict[str, Any]: """Fetch day-level moves by shelling out to the existing qfr conda env. Reason: eventflow env is kept minimal; qfr env already has pandas/pyarrow. """ sym_list = symbols or WATCHLIST_DEFAULT rawdir = os.environ.get("QFR_RAWDIR", "/home/openclaw/projects/quant-factor-research/data/raw") env = os.environ.copy() env["QFR_RAWDIR"] = rawdir env["QFR_SYMBOLS"] = ",".join(sym_list) if trade_date: env["QFR_TRADE_DATE"] = trade_date conda = os.environ.get("CONDA_BIN", "/home/openclaw/miniconda3/bin/conda") script = os.path.join(os.path.dirname(__file__), "market_moves_qfr.py") cmd = [conda, "run", "-n", "qfr", "python", script] proc = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if proc.returncode != 0: return { "ok": False, "error": "qfr_subprocess_failed", "returncode": proc.returncode, "stderr": proc.stderr[-4000:], } try: data = json.loads(proc.stdout) except json.JSONDecodeError: return { "ok": False, "error": "invalid_json_from_qfr", "stdout": proc.stdout[-2000:], "stderr": proc.stderr[-2000:], } data["ok"] = True data["symbols"] = sym_list return data