feat: add versioned research templates and alpha variants

This commit is contained in:
yuxuanhui
2026-09-08 21:29:21 +08:00
parent b604e6050e
commit f89ae211d2
55 changed files with 5650 additions and 435 deletions
+19 -2
View File
@@ -268,7 +268,7 @@ class WqClient:
async def get(self, path: str, params=None, headers=None):
return await self._read_json("GET", path, params=params, headers=headers)
async def _read_json(self, method: str, path: str, **kwargs):
async def _read_json(self, method: str, path: str, *, allow_list=False, **kwargs):
"""Authenticated read with shared refresh/retry handling; callers use GET or OPTIONS."""
if not self.credentials:
raise WqError("请先连接 WorldQuant", "disconnected")
@@ -302,7 +302,7 @@ class WqClient:
continue
try:
result = response.json()
if not isinstance(result, dict):
if not isinstance(result, dict) and not (allow_list and isinstance(result, list)):
raise ValueError()
return result
except ValueError:
@@ -375,6 +375,23 @@ class WqClient:
params["dataset.id"] = dataset_id
return await self.get("/data-fields" if dataset_id else "/data-sets", params)
async def operators(self, offset=0):
"""The operator endpoint has both list and paginated response forms."""
return await self._read_json("GET", "/operators", allow_list=True, params={"limit": 100, "offset": offset})
async def field_availability(self, field_id, scope):
"""Use a validated identifier, never an arbitrary upstream path or URL."""
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", field_id):
raise WqError("字段标识格式无效", "invalid_field")
return await self.get(f"/data-fields/{field_id}", {
"instrumentType": scope.instrument_type, "region": scope.region,
"universe": scope.universe, "delay": scope.delay,
})
async def research_setting_options(self):
"""Snapshot full setting choices for constrained research, including neutralization."""
return await self._read_json("OPTIONS", "/simulations")
async def get_platform_setting_options(self):
"""Read platform choices for the connected account; malformed responses raise WqError."""
data = await self._read_json("OPTIONS", "/simulations")