69 lines
1.9 KiB
Python
69 lines
1.9 KiB
Python
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
|