fix: fetch dataset scope options from WorldQuant platform

This commit is contained in:
yuxuanhui
2026-09-08 18:57:03 +08:00
parent 80cb7d2b80
commit 3d26827b49
13 changed files with 367 additions and 53 deletions
+6 -20
View File
@@ -16,29 +16,15 @@ def utc_timestamp(value: datetime) -> datetime:
UTCTimestamp = Annotated[datetime, AfterValidator(utc_timestamp)]
# Supported research scopes, not an assertion about a connected account's permissions.
UNIVERSES = {
"USA": ["TOP3000", "TOP1000", "TOP500", "TOP200"],
"CHN": ["TOP2000"],
"EUR": ["TOP2500", "TOP1200"],
"ASI": ["TOP1000"],
"GLB": ["TOP3000"],
"JPN": ["TOP1600"],
"HKG": ["TOP800"],
}
# Platform membership is checked before synchronization, not while reading historical caches.
ScopeName = Annotated[str, Field(min_length=1, max_length=100, pattern=r"^[^|\s]+$")]
class Scope(Contract):
instrument_type: Literal["EQUITY"] = "EQUITY"
region: str
universe: str
delay: int = Field(ge=0, le=1)
@model_validator(mode="after")
def valid_scope(self):
if self.universe not in UNIVERSES.get(self.region, []):
raise ValueError("不支持的 Region / Universe 组合")
return self
instrument_type: ScopeName = "EQUITY"
region: ScopeName
universe: ScopeName
delay: int = Field(ge=0)
def key(self):
return f"{self.instrument_type}|{self.region}|{self.universe}|{self.delay}"
+30
View File
@@ -0,0 +1,30 @@
"""Shared platform scope discovery for HTTP and AI consumers."""
from fastapi import HTTPException
from ..worldquant import WqError
async def platform_options(client):
"""Return live account choices, surfacing sanitized upstream failures to callers."""
if client is None:
raise HTTPException(409, "请先连接 WorldQuant")
try:
return await client.get_platform_setting_options()
except WqError as exc:
raise HTTPException(
409 if exc.code in ("disconnected", "verification_required") else 502, str(exc)
) from None
async def validate_platform_scope(client, scope):
"""Reject unsupported combinations before creating a synchronization job."""
data = await platform_options(client)
if not any(
row["instrument_type"] == scope.instrument_type
and row["region"] == scope.region
and row["delay"] == scope.delay
and scope.universe in row["universes"]
for row in data["instrument_options"]
):
raise HTTPException(422, "平台不支持此 Instrument Type / Region / Delay / Universe 组合")
+4 -3
View File
@@ -7,7 +7,6 @@ from fastapi import APIRouter, Depends, Query, Request
from ..schemas import JobOutput
from ..security import require_auth
from .contracts import (
UNIVERSES,
CatalogFilters,
CatalogJobInput,
CatalogPage,
@@ -19,14 +18,15 @@ from .contracts import (
NoteOutput,
Scope,
)
from .platform import platform_options, validate_platform_scope
from .service import Catalog
router = APIRouter(prefix="/api/v1/catalog", tags=["catalog"], dependencies=[Depends(require_auth)])
@router.get("/scopes")
async def scopes() -> dict[str, list[str]]:
return UNIVERSES
async def scopes(request: Request):
return await platform_options(request.app.state.runner.client)
@router.get("/datasets", response_model=CatalogPage)
@@ -69,6 +69,7 @@ async def field_note(
@router.post("/sync-jobs", status_code=202, response_model=JobOutput)
async def sync(request: Request, body: CatalogJobInput):
await validate_platform_scope(request.app.state.runner.client, body.scope)
async with request.app.state.sessions.begin() as db:
result = await Catalog(db).create_job(body)
request.app.state.runner.wake.set()