feat: add Super Alpha research, management and MCP workflows
Deploy production / deploy (push) Successful in 56s

This commit is contained in:
yuxuanhui
2026-09-13 12:32:16 +08:00
parent 7c8188df9c
commit e256d6fef1
59 changed files with 3766 additions and 125 deletions
+15 -4
View File
@@ -93,7 +93,7 @@ class Backtests:
async def capabilities(self):
return {
"alpha_types": ["REGULAR"],
"alpha_types": ["REGULAR", "SUPER"],
"languages": ["FASTEXPR"],
"instrument_types": ["EQUITY"],
"settings_schema": Candidate.model_json_schema(),
@@ -111,6 +111,8 @@ class Backtests:
from ..research.expressions import analyze
if not body.preparation_refs and not body.input_ids:
return
if any(c.alpha_type == "SUPER" for c in body.candidates):
raise HTTPException(422, "SUPER 组件快照不能使用字段数据准备集合")
await Preparations(self.db).bind(body)
snapshots = [await Preparations(self.db).snapshot(i) for i in body.input_ids]
for candidate in body.candidates:
@@ -221,6 +223,8 @@ class Backtests:
if len(candidates) != len(selection):
raise HTTPException(422, "选择包含不属于当前草稿的候选")
data = {"name": draft.name, "source": draft.source, "candidates": candidates}
from ..superalpha.service import validate_source
await validate_source(self.db, data["source"], data["candidates"])
candidates = DraftInput.model_validate(data).model_dump(mode="json")["candidates"]
config = await self.db.get(BacktestConfig, 1)
groups = defaultdict(list)
@@ -253,6 +257,9 @@ class Backtests:
for indices in groups.values():
local_batches = []
for index in indices:
if candidates[index]["alpha_type"] == "SUPER":
batches.append([index])
continue
batch = next(
(
b
@@ -352,6 +359,7 @@ class Backtests:
ordinal=i,
client_item_id=c.client_item_id,
expression=c.expression,
alpha_type=c.alpha_type, selection=c.selection, combo=c.combo,
settings=c.settings.model_dump(),
fingerprint=fingerprint(c.platform_input()),
)
@@ -360,8 +368,10 @@ class Backtests:
await self.db.flush()
return await self.run(run.id)
async def runs(self, limit=25, offset=0, source=None, reference=None, research_id=None, q="", sort="created_at", direction="desc"):
async def runs(self, limit=25, offset=0, source=None, reference=None, research_id=None, q="", sort="created_at", direction="desc", alpha_type=None):
query = select(BacktestRun)
if alpha_type:
query = query.where(BacktestRun.id.in_(select(BacktestItem.run_id).where(BacktestItem.alpha_type == alpha_type)))
if q:
query = query.where(BacktestRun.name.contains(q, autoescape=True))
column = {"name": BacktestRun.name, "created_at": BacktestRun.created_at}[sort]
@@ -460,7 +470,7 @@ class Backtests:
for k in (
"id",
"client_item_id",
"expression",
"expression", "alpha_type", "selection", "combo",
"settings",
"attempt_id",
"platform_status",
@@ -610,7 +620,8 @@ class Backtests:
source=Source.model_validate({**run.source, "parent_run_id": run.id}),
candidates=[
Candidate(
client_item_id=r.client_item_id, expression=r.expression, settings=r.settings
client_item_id=r.client_item_id, expression=r.expression, settings=r.settings,
alpha_type=r.alpha_type, selection=r.selection, combo=r.combo
)
for r in selected
],